package host import ( "bufio" "fmt" "os" "strings" "github.com/bdw/deploy/internal/ssh" "github.com/bdw/deploy/internal/state" "github.com/spf13/cobra" ) var updateCmd = &cobra.Command{ Use: "update", Short: "Update VPS packages", Long: "Run apt update && apt upgrade on the VPS", RunE: runUpdate, } func init() { updateCmd.Flags().BoolP("yes", "y", false, "Skip confirmation prompt") } func runUpdate(cmd *cobra.Command, args []string) error { st, err := state.Load() if err != nil { return fmt.Errorf("error loading state: %w", err) } host, _ := cmd.Flags().GetString("host") if host == "" { host = st.GetDefaultHost() } if host == "" { return fmt.Errorf("--host is required (no default host set)") } yes, _ := cmd.Flags().GetBool("yes") if !yes { fmt.Printf("This will run apt update && apt upgrade on %s\n", host) fmt.Print("Continue? [y/N]: ") reader := bufio.NewReader(os.Stdin) response, _ := reader.ReadString('\n') response = strings.TrimSpace(response) if response != "y" && response != "Y" { fmt.Println("Aborted.") return nil } } fmt.Printf("Connecting to %s...\n", host) client, err := ssh.Connect(host) if err != nil { return fmt.Errorf("error connecting to VPS: %w", err) } defer client.Close() fmt.Println("\n-> Running apt update...") if err := client.RunSudoStream("apt update"); err != nil { return fmt.Errorf("error running apt update: %w", err) } fmt.Println("\n-> Running apt upgrade...") if err := client.RunSudoStream("DEBIAN_FRONTEND=noninteractive apt upgrade -y"); err != nil { return fmt.Errorf("error running apt upgrade: %w", err) } fmt.Println() if output, err := client.Run("[ -f /var/run/reboot-required ] && echo 'yes' || echo 'no'"); err == nil { if output == "yes\n" { fmt.Println("Note: A reboot is required to complete the update.") } } fmt.Println("Update complete") return nil }