diff options
| author | bndw <ben@bdw.to> | 2026-01-23 21:52:50 -0800 |
|---|---|---|
| committer | bndw <ben@bdw.to> | 2026-01-23 21:52:50 -0800 |
| commit | 87752492d0dc7df3cf78011d5ce315a3eb0cad51 (patch) | |
| tree | 76843c127fece33f5c28dd7bd533044043478825 /cmd/deploy/host/update.go | |
| parent | 57eb67df265a7a6bb544cde83a3be5eadf53fdf2 (diff) | |
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.
Diffstat (limited to 'cmd/deploy/host/update.go')
| -rw-r--r-- | cmd/deploy/host/update.go | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/cmd/deploy/host/update.go b/cmd/deploy/host/update.go new file mode 100644 index 0000000..6f1b43b --- /dev/null +++ b/cmd/deploy/host/update.go | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | package host | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "bufio" | ||
| 5 | "fmt" | ||
| 6 | "os" | ||
| 7 | "strings" | ||
| 8 | |||
| 9 | "github.com/bdw/deploy/internal/ssh" | ||
| 10 | "github.com/bdw/deploy/internal/state" | ||
| 11 | "github.com/spf13/cobra" | ||
| 12 | ) | ||
| 13 | |||
| 14 | var updateCmd = &cobra.Command{ | ||
| 15 | Use: "update", | ||
| 16 | Short: "Update VPS packages", | ||
| 17 | Long: "Run apt update && apt upgrade on the VPS", | ||
| 18 | RunE: runUpdate, | ||
| 19 | } | ||
| 20 | |||
| 21 | func init() { | ||
| 22 | updateCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt") | ||
| 23 | } | ||
| 24 | |||
| 25 | func runUpdate(cmd *cobra.Command, args []string) error { | ||
| 26 | st, err := state.Load() | ||
| 27 | if err != nil { | ||
| 28 | return fmt.Errorf("error loading state: %w", err) | ||
| 29 | } | ||
| 30 | |||
| 31 | host, _ := cmd.Flags().GetString("host") | ||
| 32 | if host == "" { | ||
| 33 | host = st.GetDefaultHost() | ||
| 34 | } | ||
| 35 | |||
| 36 | if host == "" { | ||
| 37 | return fmt.Errorf("--host is required (no default host set)") | ||
| 38 | } | ||
| 39 | |||
| 40 | yes, _ := cmd.Flags().GetBool("yes") | ||
| 41 | if !yes { | ||
| 42 | fmt.Printf("This will run apt update && apt upgrade on %s\n", host) | ||
| 43 | fmt.Print("Continue? [y/N]: ") | ||
| 44 | reader := bufio.NewReader(os.Stdin) | ||
| 45 | response, _ := reader.ReadString('\n') | ||
| 46 | response = strings.TrimSpace(response) | ||
| 47 | if response != "y" && response != "Y" { | ||
| 48 | fmt.Println("Aborted.") | ||
| 49 | return nil | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | fmt.Printf("Connecting to %s...\n", host) | ||
| 54 | |||
| 55 | client, err := ssh.Connect(host) | ||
| 56 | if err != nil { | ||
| 57 | return fmt.Errorf("error connecting to VPS: %w", err) | ||
| 58 | } | ||
| 59 | defer client.Close() | ||
| 60 | |||
| 61 | fmt.Println("\n-> Running apt update...") | ||
| 62 | if err := client.RunSudoStream("apt update"); err != nil { | ||
| 63 | return fmt.Errorf("error running apt update: %w", err) | ||
| 64 | } | ||
| 65 | |||
| 66 | fmt.Println("\n-> Running apt upgrade...") | ||
| 67 | if err := client.RunSudoStream("DEBIAN_FRONTEND=noninteractive apt upgrade -y"); err != nil { | ||
| 68 | return fmt.Errorf("error running apt upgrade: %w", err) | ||
| 69 | } | ||
| 70 | |||
| 71 | fmt.Println() | ||
| 72 | if output, err := client.Run("[ -f /var/run/reboot-required ] && echo 'yes' || echo 'no'"); err == nil { | ||
| 73 | if output == "yes\n" { | ||
| 74 | fmt.Println("Note: A reboot is required to complete the update.") | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | fmt.Println("Update complete") | ||
| 79 | return nil | ||
| 80 | } | ||
