返回 DeepSeek-Reasonix
dotenv.go
根目录 / desktop / dotenv.go
1 package main
2
3 import (
4 "os"
5 "path/filepath"
6 "strings"
7
8 "reasonix/internal/config"
9 "reasonix/internal/fileutil"
10 )
11
12 // upsertDotEnv stores KEY=value in Reasonix's global .env and applies it to the
13 // running process so a rebuild picks it up without a restart.
14 func upsertDotEnv(key, value string) error {
15 _, err := config.SetCredential(key, value)
16 return err
17 }
18
19 func removeDotEnv(key string) error {
20 return config.RemoveCredential(key)
21 }
22
23 // upsertEnvFile merges KEY=value into a KEY=value file at path, preserving
24 // comments and unrelated lines, writing atomically via a sibling temp + rename.
25 func upsertEnvFile(path, key, value string) error {
26 key = strings.TrimSpace(key)
27 if key == "" {
28 return nil
29 }
30 var lines []string
31 if b, err := readFileUTF8(path); err == nil {
32 lines = strings.Split(strings.TrimRight(string(b), "\n"), "\n")
33 }
34 replaced := false
35 for i, ln := range lines {
36 t := strings.TrimSpace(ln)
37 if t == "" || strings.HasPrefix(t, "#") {
38 continue
39 }
40 if k, _, ok := strings.Cut(t, "="); ok && strings.TrimSpace(k) == key {
41 lines[i] = key + "=" + value
42 replaced = true
43 break
44 }
45 }
46 if !replaced {
47 lines = append(lines, key+"="+value)
48 }
49 out := strings.Join(lines, "\n") + "\n"
50
51 dir := filepath.Dir(path)
52 if dir != "" && dir != "." {
53 if err := os.MkdirAll(dir, 0o755); err != nil {
54 return err
55 }
56 }
57 tmp, err := os.CreateTemp(dir, "credentials.*.tmp")
58 if err != nil {
59 return err
60 }
61 tmpPath := tmp.Name()
62 if _, err := tmp.WriteString(out); err != nil {
63 tmp.Close()
64 os.Remove(tmpPath)
65 return err
66 }
67 if err := tmp.Close(); err != nil {
68 os.Remove(tmpPath)
69 return err
70 }
71 if err := fileutil.ReplaceFile(tmpPath, path); err != nil {
72 os.Remove(tmpPath)
73 return err
74 }
75 return os.Setenv(key, value)
76 }
77
78 func removeEnvFile(path, key string) error {
79 key = strings.TrimSpace(key)
80 if key == "" {
81 return nil
82 }
83 data, err := readFileUTF8(path)
84 if err != nil {
85 if os.IsNotExist(err) {
86 return os.Unsetenv(key)
87 }
88 return err
89 }
90 lines := strings.Split(strings.TrimRight(string(data), "\n"), "\n")
91 outLines := make([]string, 0, len(lines))
92 for _, ln := range lines {
93 t := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(ln), "export "))
94 if t == "" || strings.HasPrefix(t, "#") {
95 outLines = append(outLines, ln)
96 continue
97 }
98 if k, _, ok := strings.Cut(t, "="); ok && strings.TrimSpace(k) == key {
99 continue
100 }
101 outLines = append(outLines, ln)
102 }
103 out := ""
104 if len(outLines) > 0 {
105 out = strings.Join(outLines, "\n") + "\n"
106 }
107
108 dir := filepath.Dir(path)
109 if dir != "" && dir != "." {
110 if err := os.MkdirAll(dir, 0o755); err != nil {
111 return err
112 }
113 }
114 tmp, err := os.CreateTemp(dir, "credentials.*.tmp")
115 if err != nil {
116 return err
117 }
118 tmpPath := tmp.Name()
119 if _, err := tmp.WriteString(out); err != nil {
120 tmp.Close()
121 os.Remove(tmpPath)
122 return err
123 }
124 if err := tmp.Close(); err != nil {
125 os.Remove(tmpPath)
126 return err
127 }
128 if err := fileutil.ReplaceFile(tmpPath, path); err != nil {
129 os.Remove(tmpPath)
130 return err
131 }
132 return os.Unsetenv(key)
133 }
134
134 lines GO