99 "encoding/hex"
1010 "encoding/json"
1111 "errors"
12+ "flag"
1213 "fmt"
1314 "log"
1415 "os"
@@ -45,21 +46,22 @@ const (
4546type (
4647 // TextResource stores multilingual text / 存储多语言文本
4748 TextResource struct {
48- SuccessMessage string
49- RestartMessage string
50- ReadingConfig string
51- GeneratingIds string
52- PressEnterToExit string
53- ErrorPrefix string
54- PrivilegeError string
55- RunAsAdmin string
56- RunWithSudo string
57- SudoExample string
58- ConfigLocation string
59- CheckingProcesses string
60- ClosingProcesses string
61- ProcessesClosed string
62- PleaseWait string
49+ SuccessMessage string
50+ RestartMessage string
51+ ReadingConfig string
52+ GeneratingIds string
53+ PressEnterToExit string
54+ ErrorPrefix string
55+ PrivilegeError string
56+ RunAsAdmin string
57+ RunWithSudo string
58+ SudoExample string
59+ ConfigLocation string
60+ CheckingProcesses string
61+ ClosingProcesses string
62+ ProcessesClosed string
63+ PleaseWait string
64+ SetReadOnlyMessage string
6365 }
6466
6567 // StorageConfig optimized storage configuration / 优化的存储配置
@@ -117,42 +119,46 @@ var (
117119
118120 texts = map [Language ]TextResource {
119121 CN : {
120- SuccessMessage : "[√] 配置文件已成功更新!" ,
121- RestartMessage : "[!] 请手动重启 Cursor 以使更新生效" ,
122- ReadingConfig : "正在读取配置文件..." ,
123- GeneratingIds : "正在生成新的标识符..." ,
124- PressEnterToExit : "按回车键退出程序..." ,
125- ErrorPrefix : "程序发生严重错误: %v" ,
126- PrivilegeError : "\n [!] 错误:需要管理员权限" ,
127- RunAsAdmin : "请右键点击程序,选择「以管理员身份运行」" ,
128- RunWithSudo : "请使用 sudo 命令运行此程序" ,
129- SudoExample : "示例: sudo %s" ,
130- ConfigLocation : "配置文件位置:" ,
131- CheckingProcesses : "正在检查运行中的 Cursor 实例..." ,
132- ClosingProcesses : "正在关闭 Cursor 实例..." ,
133- ProcessesClosed : "所有 Cursor 实例已关闭" ,
134- PleaseWait : "请稍候..." ,
122+ SuccessMessage : "[√] 配置文件已成功更新!" ,
123+ RestartMessage : "[!] 请手动重启 Cursor 以使更新生效" ,
124+ ReadingConfig : "正在读取配置文件..." ,
125+ GeneratingIds : "正在生成新的标识符..." ,
126+ PressEnterToExit : "按回车键退出程序..." ,
127+ ErrorPrefix : "程序发生严重错误: %v" ,
128+ PrivilegeError : "\n [!] 错误:需要管理员权限" ,
129+ RunAsAdmin : "请右键点击程序,选择「以管理员身份运行」" ,
130+ RunWithSudo : "请使用 sudo 命令运行此程序" ,
131+ SudoExample : "示例: sudo %s" ,
132+ ConfigLocation : "配置文件位置:" ,
133+ CheckingProcesses : "正在检查运行中的 Cursor 实例..." ,
134+ ClosingProcesses : "正在关闭 Cursor 实例..." ,
135+ ProcessesClosed : "所有 Cursor 实例已关闭" ,
136+ PleaseWait : "请稍候..." ,
137+ SetReadOnlyMessage : "设置 storage.json 为只读模式, 这将导致 workspace 记录信息丢失等问题" ,
135138 },
136139 EN : {
137- SuccessMessage : "[√] Configuration file updated successfully!" ,
138- RestartMessage : "[!] Please restart Cursor manually for changes to take effect" ,
139- ReadingConfig : "Reading configuration file..." ,
140- GeneratingIds : "Generating new identifiers..." ,
141- PressEnterToExit : "Press Enter to exit..." ,
142- ErrorPrefix : "Program encountered a serious error: %v" ,
143- PrivilegeError : "\n [!] Error: Administrator privileges required" ,
144- RunAsAdmin : "Please right-click and select 'Run as Administrator'" ,
145- RunWithSudo : "Please run this program with sudo" ,
146- SudoExample : "Example: sudo %s" ,
147- ConfigLocation : "Config file location:" ,
148- CheckingProcesses : "Checking for running Cursor instances..." ,
149- ClosingProcesses : "Closing Cursor instances..." ,
150- ProcessesClosed : "All Cursor instances have been closed" ,
151- PleaseWait : "Please wait..." ,
140+ SuccessMessage : "[√] Configuration file updated successfully!" ,
141+ RestartMessage : "[!] Please restart Cursor manually for changes to take effect" ,
142+ ReadingConfig : "Reading configuration file..." ,
143+ GeneratingIds : "Generating new identifiers..." ,
144+ PressEnterToExit : "Press Enter to exit..." ,
145+ ErrorPrefix : "Program encountered a serious error: %v" ,
146+ PrivilegeError : "\n [!] Error: Administrator privileges required" ,
147+ RunAsAdmin : "Please right-click and select 'Run as Administrator'" ,
148+ RunWithSudo : "Please run this program with sudo" ,
149+ SudoExample : "Example: sudo %s" ,
150+ ConfigLocation : "Config file location:" ,
151+ CheckingProcesses : "Checking for running Cursor instances..." ,
152+ ClosingProcesses : "Closing Cursor instances..." ,
153+ ProcessesClosed : "All Cursor instances have been closed" ,
154+ PleaseWait : "Please wait..." ,
155+ SetReadOnlyMessage : "Set storage.json to read-only mode, which will cause issues such as lost workspace records" ,
152156 },
153157 }
154158)
155159
160+ var setReadOnly * bool = flag .Bool ("r" , false , "set storage.json to read-only mode" )
161+
156162// Error Implementation / 错误实现
157163func (e * AppError ) Error () string {
158164 if e .Context != nil {
@@ -225,16 +231,6 @@ func saveConfig(config *StorageConfig, username string) error { // Modified to t
225231 return err
226232 }
227233
228- content , err := json .MarshalIndent (config , "" , " " )
229- if err != nil {
230- return & AppError {
231- Type : ErrSystem ,
232- Op : "generate JSON" ,
233- Path : "" ,
234- Err : err ,
235- }
236- }
237-
238234 // Create parent directories with proper permissions
239235 dir := filepath .Dir (configPath )
240236 if err := os .MkdirAll (dir , 0755 ); err != nil {
@@ -256,9 +252,53 @@ func saveConfig(config *StorageConfig, username string) error { // Modified to t
256252 }
257253 }
258254
255+ originalFileStat , err := os .Stat (configPath )
256+ if err != nil {
257+ return & AppError {
258+ Type : ErrSystem ,
259+ Op : "get file mode" ,
260+ Path : configPath ,
261+ Err : err ,
262+ }
263+ }
264+ originalFileMode := originalFileStat .Mode ()
265+
266+ originalFileContent , err := os .ReadFile (configPath )
267+ if err != nil {
268+ return & AppError {
269+ Type : ErrSystem ,
270+ Op : "read original file" ,
271+ Path : configPath ,
272+ Err : err ,
273+ }
274+ }
275+
276+ var originalFile map [string ]any
277+ if err := json .Unmarshal (originalFileContent , & originalFile ); err != nil {
278+ return & AppError {
279+ Type : ErrSystem ,
280+ Op : "unmarshal original file" ,
281+ Path : configPath ,
282+ Err : err ,
283+ }
284+ }
285+ originalFile ["telemetry.sqmId" ] = config .TelemetrySqmId
286+ originalFile ["telemetry.macMachineId" ] = config .TelemetryMacMachineId
287+ originalFile ["telemetry.machineId" ] = config .TelemetryMachineId
288+ originalFile ["telemetry.devDeviceId" ] = config .TelemetryDevDeviceId
289+ newFileContent , err := json .MarshalIndent (originalFile , "" , " " )
290+ if err != nil {
291+ return & AppError {
292+ Type : ErrSystem ,
293+ Op : "marshal new file" ,
294+ Path : configPath ,
295+ Err : err ,
296+ }
297+ }
298+
259299 // Write to temporary file first
260300 tmpPath := configPath + ".tmp"
261- if err := os .WriteFile (tmpPath , content , 0666 ); err != nil {
301+ if err := os .WriteFile (tmpPath , newFileContent , 0666 ); err != nil {
262302 return & AppError {
263303 Type : ErrSystem ,
264304 Op : "write temporary file" ,
@@ -267,8 +307,12 @@ func saveConfig(config *StorageConfig, username string) error { // Modified to t
267307 }
268308 }
269309
310+ if * setReadOnly {
311+ originalFileMode = 0444
312+ }
313+
270314 // Ensure proper permissions on temporary file
271- if err := os .Chmod (tmpPath , 0444 ); err != nil {
315+ if err := os .Chmod (tmpPath , originalFileMode ); err != nil {
272316 os .Remove (tmpPath )
273317 return & AppError {
274318 Type : ErrSystem ,
@@ -495,6 +539,15 @@ func showSuccess() {
495539 }
496540}
497541
542+ func showReadOnlyMessage () {
543+ if * setReadOnly {
544+ warningColor := color .New (color .FgYellow , color .Bold )
545+ warningColor .Printf ("%s\n " , texts [currentLanguage ].SetReadOnlyMessage )
546+ fmt .Println ("Press Enter to continue..." )
547+ bufio .NewReader (os .Stdin ).ReadString ('\n' )
548+ }
549+ }
550+
498551func showPrivilegeError () {
499552 text := texts [currentLanguage ]
500553 red := color .New (color .FgRed , color .Bold )
@@ -691,6 +744,9 @@ func main() {
691744 }
692745 }()
693746
747+ flag .Parse ()
748+ showReadOnlyMessage ()
749+
694750 var username string
695751 if username = os .Getenv ("SUDO_USER" ); username == "" {
696752 user , err := user .Current ()
0 commit comments