package env import ( "bufio" "fmt" "os" "strings" "github.com/bdw/deploy/internal/ssh" "github.com/bdw/deploy/internal/state" "github.com/spf13/cobra" ) var setCmd = &cobra.Command{ Use: "set KEY=VALUE...", Short: "Set environment variable(s)", Long: "Set one or more environment variables for an app. Variables are specified as KEY=VALUE pairs.", Args: cobra.MinimumNArgs(2), RunE: runSet, } func init() { setCmd.Flags().StringP("file", "f", "", "Load environment from file") } func runSet(cmd *cobra.Command, args []string) error { name := args[0] envVars := args[1:] 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") } app, err := st.GetApp(host, name) if err != nil { return err } if app.Type != "app" { return fmt.Errorf("env is only available for apps, not static sites") } if app.Env == nil { app.Env = make(map[string]string) } // Set variables from args for _, e := range envVars { parts := strings.SplitN(e, "=", 2) if len(parts) == 2 { app.Env[parts[0]] = parts[1] fmt.Printf("Set %s\n", parts[0]) } else { return fmt.Errorf("invalid format: %s (expected KEY=VALUE)", e) } } // Set variables from file if provided envFile, _ := cmd.Flags().GetString("file") if envFile != "" { fileEnv, err := parseEnvFile(envFile) if err != nil { return fmt.Errorf("error reading env file: %w", err) } for k, v := range fileEnv { app.Env[k] = v fmt.Printf("Set %s\n", k) } } if err := st.Save(); err != nil { return fmt.Errorf("error saving state: %w", err) } client, err := ssh.Connect(host) if err != nil { return fmt.Errorf("error connecting to VPS: %w", err) } defer client.Close() fmt.Println("-> Updating environment file on VPS...") envFilePath := fmt.Sprintf("/etc/deploy/env/%s.env", name) envContent := "" for k, v := range app.Env { envContent += fmt.Sprintf("%s=%s\n", k, v) } if err := client.WriteSudoFile(envFilePath, envContent); err != nil { return fmt.Errorf("error updating env file: %w", err) } fmt.Println("-> Restarting service...") if _, err := client.RunSudo(fmt.Sprintf("systemctl restart %s", name)); err != nil { return fmt.Errorf("error restarting service: %w", err) } fmt.Println("Environment variables updated successfully") return nil } func parseEnvFile(path string) (map[string]string, error) { file, err := os.Open(path) if err != nil { return nil, err } defer file.Close() env := make(map[string]string) scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } parts := strings.SplitN(line, "=", 2) if len(parts) == 2 { env[parts[0]] = parts[1] } } return env, scanner.Err() }