From 87752492d0dc7df3cf78011d5ce315a3eb0cad51 Mon Sep 17 00:00:00 2001 From: bndw Date: Fri, 23 Jan 2026 21:52:50 -0800 Subject: Restructure CLI with Cobra Replace custom switch-based routing with Cobra for cleaner command hierarchy. Reorganize commands into logical groups: - Root command handles deployment (--binary, --static, --domain, etc.) - App management at top level: list, logs, status, restart, remove - env subcommand group: list, set, unset - host subcommand group: init, status, update, ssh - Standalone: ui (renamed from webui), version Add version command with ldflags support for build info. --- cmd/deploy/manage.go | 306 --------------------------------------------------- 1 file changed, 306 deletions(-) delete mode 100644 cmd/deploy/manage.go (limited to 'cmd/deploy/manage.go') diff --git a/cmd/deploy/manage.go b/cmd/deploy/manage.go deleted file mode 100644 index 1f52b92..0000000 --- a/cmd/deploy/manage.go +++ /dev/null @@ -1,306 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "os" - - "github.com/bdw/deploy/internal/ssh" - "github.com/bdw/deploy/internal/state" -) - -func runRemove(args []string) { - fs := flag.NewFlagSet("remove", flag.ExitOnError) - host := fs.String("host", "", "VPS host (SSH config alias or user@host)") - fs.Parse(args) - - if len(fs.Args()) == 0 { - fmt.Fprintf(os.Stderr, "Error: app name is required\n") - fmt.Fprintf(os.Stderr, "Usage: deploy remove --host user@vps-ip\n") - os.Exit(1) - } - - name := fs.Args()[0] - - // Load state - st, err := state.Load() - if err != nil { - fmt.Fprintf(os.Stderr, "Error loading state: %v\n", err) - os.Exit(1) - } - - // Get host from flag or state default - if *host == "" { - *host = st.GetDefaultHost() - } - - if *host == "" { - fmt.Fprintf(os.Stderr, "Error: --host is required\n") - fs.Usage() - os.Exit(1) - } - - // Get app info - app, err := st.GetApp(*host, name) - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - - fmt.Printf("Removing deployment: %s\n", name) - - // Connect to VPS - client, err := ssh.Connect(*host) - if err != nil { - fmt.Fprintf(os.Stderr, "Error connecting to VPS: %v\n", err) - os.Exit(1) - } - defer client.Close() - - if app.Type == "app" { - // Stop and disable service - fmt.Println("→ Stopping service...") - client.RunSudo(fmt.Sprintf("systemctl stop %s", name)) - client.RunSudo(fmt.Sprintf("systemctl disable %s", name)) - - // Remove systemd unit - client.RunSudo(fmt.Sprintf("rm -f /etc/systemd/system/%s.service", name)) - client.RunSudo("systemctl daemon-reload") - - // Remove binary - client.RunSudo(fmt.Sprintf("rm -f /usr/local/bin/%s", name)) - - // Remove working directory - client.RunSudo(fmt.Sprintf("rm -rf /var/lib/%s", name)) - - // Remove env file - client.RunSudo(fmt.Sprintf("rm -f /etc/deploy/env/%s.env", name)) - - // Remove user - client.RunSudo(fmt.Sprintf("userdel %s", name)) - } else { - // Remove static site files - fmt.Println("→ Removing files...") - client.RunSudo(fmt.Sprintf("rm -rf /var/www/%s", name)) - } - - // Remove Caddy config - fmt.Println("→ Removing Caddy config...") - client.RunSudo(fmt.Sprintf("rm -f /etc/caddy/sites-enabled/%s.caddy", name)) - - // Reload Caddy - fmt.Println("→ Reloading Caddy...") - if _, err := client.RunSudo("systemctl reload caddy"); err != nil { - fmt.Fprintf(os.Stderr, "Warning: Error reloading Caddy: %v\n", err) - } - - // Update state - if err := st.RemoveApp(*host, name); err != nil { - fmt.Fprintf(os.Stderr, "Error updating state: %v\n", err) - os.Exit(1) - } - if err := st.Save(); err != nil { - fmt.Fprintf(os.Stderr, "Error saving state: %v\n", err) - os.Exit(1) - } - - fmt.Printf("✓ Deployment removed successfully\n") -} - -func runLogs(args []string) { - fs := flag.NewFlagSet("logs", flag.ExitOnError) - host := fs.String("host", "", "VPS host (SSH config alias or user@host)") - follow := fs.Bool("f", false, "Follow logs") - lines := fs.Int("n", 50, "Number of lines to show") - fs.Parse(args) - - if len(fs.Args()) == 0 { - fmt.Fprintf(os.Stderr, "Error: app name is required\n") - fmt.Fprintf(os.Stderr, "Usage: deploy logs --host user@vps-ip\n") - os.Exit(1) - } - - name := fs.Args()[0] - - // Load state - st, err := state.Load() - if err != nil { - fmt.Fprintf(os.Stderr, "Error loading state: %v\n", err) - os.Exit(1) - } - - // Get host from flag or state default - if *host == "" { - *host = st.GetDefaultHost() - } - - if *host == "" { - fmt.Fprintf(os.Stderr, "Error: --host is required\n") - fs.Usage() - os.Exit(1) - } - - app, err := st.GetApp(*host, name) - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - - if app.Type != "app" { - fmt.Fprintf(os.Stderr, "Error: logs are only available for apps, not static sites\n") - os.Exit(1) - } - - // Connect to VPS - client, err := ssh.Connect(*host) - if err != nil { - fmt.Fprintf(os.Stderr, "Error connecting to VPS: %v\n", err) - os.Exit(1) - } - defer client.Close() - - // Build journalctl command - cmd := fmt.Sprintf("journalctl -u %s -n %d", name, *lines) - if *follow { - cmd += " -f" - } - - // Run command - if *follow { - // Stream output for follow mode (no sudo needed for journalctl) - if err := client.RunStream(cmd); err != nil { - fmt.Fprintf(os.Stderr, "Error fetching logs: %v\n", err) - os.Exit(1) - } - } else { - // Buffer output for non-follow mode (no sudo needed for journalctl) - output, err := client.Run(cmd) - if err != nil { - fmt.Fprintf(os.Stderr, "Error fetching logs: %v\n", err) - os.Exit(1) - } - fmt.Print(output) - } -} - -func runStatus(args []string) { - fs := flag.NewFlagSet("status", flag.ExitOnError) - host := fs.String("host", "", "VPS host (SSH config alias or user@host)") - fs.Parse(args) - - if len(fs.Args()) == 0 { - fmt.Fprintf(os.Stderr, "Error: app name is required\n") - fmt.Fprintf(os.Stderr, "Usage: deploy status --host user@vps-ip\n") - os.Exit(1) - } - - name := fs.Args()[0] - - // Load state - st, err := state.Load() - if err != nil { - fmt.Fprintf(os.Stderr, "Error loading state: %v\n", err) - os.Exit(1) - } - - // Get host from flag or state default - if *host == "" { - *host = st.GetDefaultHost() - } - - if *host == "" { - fmt.Fprintf(os.Stderr, "Error: --host is required\n") - fs.Usage() - os.Exit(1) - } - - app, err := st.GetApp(*host, name) - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - - if app.Type != "app" { - fmt.Fprintf(os.Stderr, "Error: status is only available for apps, not static sites\n") - os.Exit(1) - } - - // Connect to VPS - client, err := ssh.Connect(*host) - if err != nil { - fmt.Fprintf(os.Stderr, "Error connecting to VPS: %v\n", err) - os.Exit(1) - } - defer client.Close() - - // Get status - output, err := client.RunSudo(fmt.Sprintf("systemctl status %s", name)) - if err != nil { - // systemctl status returns non-zero for non-active services - // but we still want to show the output - fmt.Print(output) - return - } - - fmt.Print(output) -} - -func runRestart(args []string) { - fs := flag.NewFlagSet("restart", flag.ExitOnError) - host := fs.String("host", "", "VPS host (SSH config alias or user@host)") - fs.Parse(args) - - if len(fs.Args()) == 0 { - fmt.Fprintf(os.Stderr, "Error: app name is required\n") - fmt.Fprintf(os.Stderr, "Usage: deploy restart --host user@vps-ip\n") - os.Exit(1) - } - - name := fs.Args()[0] - - // Load state - st, err := state.Load() - if err != nil { - fmt.Fprintf(os.Stderr, "Error loading state: %v\n", err) - os.Exit(1) - } - - // Get host from flag or state default - if *host == "" { - *host = st.GetDefaultHost() - } - - if *host == "" { - fmt.Fprintf(os.Stderr, "Error: --host is required\n") - fs.Usage() - os.Exit(1) - } - - app, err := st.GetApp(*host, name) - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - - if app.Type != "app" { - fmt.Fprintf(os.Stderr, "Error: restart is only available for apps, not static sites\n") - os.Exit(1) - } - - // Connect to VPS - client, err := ssh.Connect(*host) - if err != nil { - fmt.Fprintf(os.Stderr, "Error connecting to VPS: %v\n", err) - os.Exit(1) - } - defer client.Close() - - // Restart service - fmt.Printf("Restarting %s...\n", name) - if _, err := client.RunSudo(fmt.Sprintf("systemctl restart %s", name)); err != nil { - fmt.Fprintf(os.Stderr, "Error restarting service: %v\n", err) - os.Exit(1) - } - - fmt.Println("✓ Service restarted successfully") -} -- cgit v1.2.3