summaryrefslogtreecommitdiffstats
path: root/cmd/ship/env/set.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/ship/env/set.go')
-rw-r--r--cmd/ship/env/set.go132
1 files changed, 132 insertions, 0 deletions
diff --git a/cmd/ship/env/set.go b/cmd/ship/env/set.go
new file mode 100644
index 0000000..e11d2c9
--- /dev/null
+++ b/cmd/ship/env/set.go
@@ -0,0 +1,132 @@
1package env
2
3import (
4 "bufio"
5 "fmt"
6 "os"
7 "strings"
8
9 "github.com/bdw/ship/internal/ssh"
10 "github.com/bdw/ship/internal/state"
11 "github.com/spf13/cobra"
12)
13
14var setCmd = &cobra.Command{
15 Use: "set <app> KEY=VALUE...",
16 Short: "Set environment variable(s)",
17 Long: "Set one or more environment variables for an app. Variables are specified as KEY=VALUE pairs.",
18 Args: cobra.MinimumNArgs(2),
19 RunE: runSet,
20}
21
22func init() {
23 setCmd.Flags().StringP("file", "f", "", "Load environment from file")
24}
25
26func runSet(cmd *cobra.Command, args []string) error {
27 name := args[0]
28 envVars := args[1:]
29
30 st, err := state.Load()
31 if err != nil {
32 return fmt.Errorf("error loading state: %w", err)
33 }
34
35 host, _ := cmd.Flags().GetString("host")
36 if host == "" {
37 host = st.GetDefaultHost()
38 }
39
40 if host == "" {
41 return fmt.Errorf("--host is required")
42 }
43
44 app, err := st.GetApp(host, name)
45 if err != nil {
46 return err
47 }
48
49 if app.Type != "app" {
50 return fmt.Errorf("env is only available for apps, not static sites")
51 }
52
53 if app.Env == nil {
54 app.Env = make(map[string]string)
55 }
56
57 // Set variables from args
58 for _, e := range envVars {
59 parts := strings.SplitN(e, "=", 2)
60 if len(parts) == 2 {
61 app.Env[parts[0]] = parts[1]
62 fmt.Printf("Set %s\n", parts[0])
63 } else {
64 return fmt.Errorf("invalid format: %s (expected KEY=VALUE)", e)
65 }
66 }
67
68 // Set variables from file if provided
69 envFile, _ := cmd.Flags().GetString("file")
70 if envFile != "" {
71 fileEnv, err := parseEnvFile(envFile)
72 if err != nil {
73 return fmt.Errorf("error reading env file: %w", err)
74 }
75 for k, v := range fileEnv {
76 app.Env[k] = v
77 fmt.Printf("Set %s\n", k)
78 }
79 }
80
81 if err := st.Save(); err != nil {
82 return fmt.Errorf("error saving state: %w", err)
83 }
84
85 client, err := ssh.Connect(host)
86 if err != nil {
87 return fmt.Errorf("error connecting to VPS: %w", err)
88 }
89 defer client.Close()
90
91 fmt.Println("-> Updating environment file on VPS...")
92 envFilePath := fmt.Sprintf("/etc/ship/env/%s.env", name)
93 envContent := ""
94 for k, v := range app.Env {
95 envContent += fmt.Sprintf("%s=%s\n", k, v)
96 }
97 if err := client.WriteSudoFile(envFilePath, envContent); err != nil {
98 return fmt.Errorf("error updating env file: %w", err)
99 }
100
101 fmt.Println("-> Restarting service...")
102 if _, err := client.RunSudo(fmt.Sprintf("systemctl restart %s", name)); err != nil {
103 return fmt.Errorf("error restarting service: %w", err)
104 }
105
106 fmt.Println("Environment variables updated successfully")
107 return nil
108}
109
110func parseEnvFile(path string) (map[string]string, error) {
111 file, err := os.Open(path)
112 if err != nil {
113 return nil, err
114 }
115 defer file.Close()
116
117 env := make(map[string]string)
118 scanner := bufio.NewScanner(file)
119 for scanner.Scan() {
120 line := strings.TrimSpace(scanner.Text())
121 if line == "" || strings.HasPrefix(line, "#") {
122 continue
123 }
124
125 parts := strings.SplitN(line, "=", 2)
126 if len(parts) == 2 {
127 env[parts[0]] = parts[1]
128 }
129 }
130
131 return env, scanner.Err()
132}