Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 3 additions & 32 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ import (
"github.com/livrasand/gitGost/internal/jobs"
)

// version del CLI; puede inyectarse con -ldflags en el build.
var version = "0.1.0"

// Run despacha el subcomando de `git gost ...`. Devuelve el código de salida.
func Run(args []string) int {
if len(args) == 0 {
printUsage()
Expand Down Expand Up @@ -45,7 +43,7 @@ func Run(args []string) int {
return cmdResume(args[1:])
case "cancel":
return cmdCancel(args[1:])
case "run": // interno: ejecuta un job en background
case "run":
return cmdRun(args[1:])
case "help", "-h", "--help":
printUsage()
Expand All @@ -54,12 +52,10 @@ func Run(args []string) int {
fmt.Printf("git-gost %s\n", version)
return 0
default:
// Pass-through: cualquier comando Git sin lógica especial.
return passthrough(args)
}
}

// passthrough reenvía el comando a Git (status, log, branch, diff, ...).
func passthrough(args []string) int {
cmd := exec.Command("git", args...)
cmd.Stdin = os.Stdin
Expand All @@ -75,7 +71,6 @@ func passthrough(args []string) int {
return 0
}

// dataDir devuelve el directorio de datos del cliente (env GITGOST_HOME o ~/.gitgost).
func dataDir() string {
if v := os.Getenv("GITGOST_HOME"); v != "" {
return v
Expand All @@ -95,9 +90,6 @@ func openStore() (*jobs.Store, error) {
return jobs.Open(dbPath())
}

// cmdInstall prepara el entorno del cliente: crea la cola SQLite y, si el
// binario no está disponible como 'git-gost' en el PATH, se auto-instala en
// ~/.local/bin y añade ese directorio al PATH del shell.
func cmdInstall() int {
s, err := openStore()
if err != nil {
Expand All @@ -116,9 +108,6 @@ func cmdInstall() int {
return 0
}

// selfInstall copia el binario en ejecución como 'git-gost' a ~/.local/bin y,
// en Unix, añade ese directorio al PATH del shell si no está ya. No hace nada
// si ya hay un 'git-gost' disponible en el PATH.
func selfInstall() error {
if _, err := exec.LookPath("git-gost"); err == nil {
return nil
Expand Down Expand Up @@ -154,14 +143,12 @@ func selfInstall() error {
}

if runtime.GOOS == "windows" {
// En Windows no se editan rc files: se indica el directorio a añadir.
fmt.Printf("Añade %s a tu PATH para usar 'git gost ...'.\n", binDir)
return nil
}
return addToPath(binDir, home)
}

// addToPath añade dir al PATH del shell del usuario si no está ya referenciado.
func addToPath(dir, home string) error {
shell := filepath.Base(os.Getenv("SHELL"))
var rc, line string
Expand All @@ -175,7 +162,7 @@ func addToPath(dir, home string) error {
rc = filepath.Join(home, ".bash_profile")
}
line = fmt.Sprintf(`export PATH=%q:$PATH`, dir)
default: // zsh y cualquier otro shell
default:
rc = filepath.Join(home, ".zshrc")
line = fmt.Sprintf(`export PATH=%q:$PATH`, dir)
}
Expand All @@ -185,7 +172,7 @@ func addToPath(dir, home string) error {
return err
}
if strings.Contains(string(data), dir) {
return nil // el directorio ya está en el PATH del shell
return nil
}

if err := os.MkdirAll(filepath.Dir(rc), 0o755); err != nil {
Expand All @@ -203,7 +190,6 @@ func addToPath(dir, home string) error {
return nil
}

// copyFile copia un archivo (los permisos se ajustan aparte).
func copyFile(src, dst string) error {
in, err := os.Open(src)
if err != nil {
Expand All @@ -223,7 +209,6 @@ func copyFile(src, dst string) error {
return out.Close()
}

// cmdClone crea un job de clone. Por defecto corre en background; con -f/--foreground en primer plano.
func cmdClone(args []string) int {
foreground, rest, err := parseFlags(args)
if err != nil {
Expand Down Expand Up @@ -276,8 +261,6 @@ func cmdClone(args []string) int {
return launchBackground(s, id)
}

// defaultCloneDir deriva el directorio destino de un clone a partir de la URL
// original (basename del repo, sin .git), igual que hace `git clone`.
func defaultCloneDir(raw string) string {
u, err := parseRepoURL(raw)
if err != nil {
Expand All @@ -290,7 +273,6 @@ func defaultCloneDir(raw string) string {
return strings.TrimSuffix(parts[len(parts)-1], ".git")
}

// cmdGitJob crea un job para fetch/pull/push en el repositorio actual.
func cmdGitJob(op string, args []string) int {
foreground, rest, err := parseFlags(args)
if err != nil {
Expand Down Expand Up @@ -324,7 +306,6 @@ func cmdGitJob(op string, args []string) int {
return launchBackground(s, id)
}

// parseFlags extrae -f/--foreground del resto de argumentos.
func parseFlags(args []string) (foreground bool, rest []string, err error) {
for _, a := range args {
switch a {
Expand All @@ -337,7 +318,6 @@ func parseFlags(args []string) (foreground bool, rest []string, err error) {
return foreground, rest, nil
}

// runForeground ejecuta el job en primer plano y muestra el resultado.
func runForeground(s *jobs.Store, id int64) int {
if err := jobs.Run(s, id); err != nil {
job, gerr := s.Get(id)
Expand All @@ -352,7 +332,6 @@ func runForeground(s *jobs.Store, id int64) int {
return 0
}

// launchBackground lanza `git-gost run <id>` como proceso independiente.
func launchBackground(s *jobs.Store, id int64) int {
pid, err := startBackground(id)
if err != nil {
Expand All @@ -366,7 +345,6 @@ func launchBackground(s *jobs.Store, id int64) int {
return 0
}

// cmdRun ejecuta un job de la cola (invocado como proceso hijo en background).
func cmdRun(args []string) int {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "uso interno: git gost run <id>")
Expand All @@ -390,7 +368,6 @@ func cmdRun(args []string) int {
return 0
}

// cmdJobs lista los jobs recientes de la cola.
func cmdJobs(args []string) int {
s, err := openStore()
if err != nil {
Expand Down Expand Up @@ -427,7 +404,6 @@ func cmdJobs(args []string) int {
return 0
}

// cmdWatch sigue el progreso de un job hasta que termina.
func cmdWatch(args []string) int {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "uso: git gost watch <id>")
Expand Down Expand Up @@ -468,7 +444,6 @@ func cmdWatch(args []string) int {
}
}

// cmdPause pausa un job en cola o en ejecución.
func cmdPause(args []string) int {
return signalCommand("pause", args, func(j *jobs.Job, s *jobs.Store) (int, error) {
switch j.State {
Expand All @@ -485,7 +460,6 @@ func cmdPause(args []string) int {
})
}

// cmdResume reanuda un job pausado.
func cmdResume(args []string) int {
return signalCommand("resume", args, func(j *jobs.Job, s *jobs.Store) (int, error) {
if j.State != jobs.StatePaused {
Expand All @@ -497,7 +471,6 @@ func cmdResume(args []string) int {
}
return 0, s.SetState(j.ID, jobs.StateRunning)
}
// Pausado sin proceso (estaba en cola): relanzar en background.
pid, err := startBackground(j.ID)
if err != nil {
return 0, err
Expand All @@ -507,7 +480,6 @@ func cmdResume(args []string) int {
})
}

// cmdCancel cancela un job pendiente o en ejecución.
func cmdCancel(args []string) int {
return signalCommand("cancel", args, func(j *jobs.Job, s *jobs.Store) (int, error) {
switch j.State {
Expand All @@ -524,7 +496,6 @@ func cmdCancel(args []string) int {
})
}

// signalCommand resuelve el id, aplica la acción y reporta el resultado.
func signalCommand(name string, args []string, action func(*jobs.Job, *jobs.Store) (int, error)) int {
if len(args) == 0 {
fmt.Fprintf(os.Stderr, "uso: git gost %s <id>\n", name)
Expand Down
4 changes: 0 additions & 4 deletions internal/cli/proc_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ var (
sigTerm = syscall.SIGTERM
)

// startBackground lanza `git-gost run <id>` como proceso independiente en su
// propio grupo de procesos, de modo que pause/resume/cancel puedan señalarlo.
func startBackground(id int64) (int, error) {
self, err := os.Executable()
if err != nil {
Expand All @@ -36,13 +34,11 @@ func startBackground(id int64) (int, error) {
if err := cmd.Start(); err != nil {
return 0, err
}
// Capturar el PID antes de Release: en Go 1.25, Release invalida Pid (-1).
pid := cmd.Process.Pid
cmd.Process.Release()
return pid, nil
}

// signalJob envía una señal a todo el grupo de procesos del job.
func signalJob(pid int, sig syscall.Signal) error {
if pid <= 0 {
return fmt.Errorf("el job no tiene proceso en background activo")
Expand Down
4 changes: 0 additions & 4 deletions internal/cli/proc_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ var (
sigTerm = syscall.Signal(0)
)

// startBackground lanza `git-gost run <id>` como proceso independiente.
func startBackground(id int64) (int, error) {
self, err := os.Executable()
if err != nil {
Expand All @@ -37,14 +36,11 @@ func startBackground(id int64) (int, error) {
if err := cmd.Start(); err != nil {
return 0, err
}
// Capturar el PID antes de Release: en Go 1.25, Release invalida Pid (-1).
pid := cmd.Process.Pid
cmd.Process.Release()
return pid, nil
}

// signalJob no está soportado en Windows en esta fase: no hay pausa real por
// señales y cancelar un proceso en ejecución requiere taskkill.
func signalJob(pid int, sig syscall.Signal) error {
return fmt.Errorf("pause/resume/cancel en ejecución no está soportado en Windows en esta fase")
}
8 changes: 0 additions & 8 deletions internal/cli/rewrite.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,19 @@ import (
"strings"
)

// ServerBase devuelve la URL base del servidor gitGost (env GITGOST_SERVER o default).
func ServerBase() string {
if v := os.Getenv("GITGOST_SERVER"); v != "" {
return strings.TrimRight(v, "/")
}
return "https://gitgost.fly.dev"
}

// hostPrefix mapea el host del repositorio al prefijo de ruta del servidor gitGost.
var hostPrefix = map[string]string{
"github.com": "gh",
"gitlab.com": "gl",
"codeberg.org": "cb",
}

// RewriteURL convierte una URL de repositorio (https o scp-like SSH) en la ruta
// equivalente del servidor gitGost: /v1/<prefix>/owner/repo. Así el tráfico de
// clone/fetch pasa por gitGost sin tocar la URL original del usuario.
func RewriteURL(base, raw string) (string, error) {
base = strings.TrimRight(base, "/")
u, err := parseRepoURL(raw)
Expand All @@ -49,7 +44,6 @@ func RewriteURL(base, raw string) (string, error) {
return fmt.Sprintf("%s/v1/%s/%s/%s", base, prefix, owner, repo), nil
}

// parseRepoURL acepta URLs https://host/owner/repo y scp-like git@host:owner/repo.git.
func parseRepoURL(raw string) (*url.URL, error) {
if strings.Contains(raw, "://") {
u, err := url.Parse(raw)
Expand All @@ -62,7 +56,6 @@ func parseRepoURL(raw string) (*url.URL, error) {
return u, nil
}

// scp-like: user@host:owner/repo(.git)
at := strings.LastIndex(raw, "@")
colon := strings.Index(raw, ":")
if at >= 0 && colon > at {
Expand All @@ -83,7 +76,6 @@ func splitPath(p string) []string {
return out
}

// validSegment valida un segmento owner/repo (alfanumérico, -, _, .).
func validSegment(s string) bool {
if len(s) == 0 || len(s) > 100 {
return false
Expand Down
1 change: 0 additions & 1 deletion internal/cli/rewrite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ func TestRewriteURL(t *testing.T) {
})
}

// La base con slash final también debe funcionar.
if got, err := RewriteURL("https://gitgost.fly.dev/", "https://github.com/foo/bar"); err != nil || got != "https://gitgost.fly.dev/v1/gh/foo/bar" {
t.Errorf("base con slash final: got=%q err=%v", got, err)
}
Expand Down
Loading