Browse Source

feat: add option to set storage.json as read-only.

1. Default does not set storage.json file to read-only mode
2. Default retains other configuration information in storage.json
pull/48/head
Ricky 6 months ago
parent
commit
791156055f
  1. 170
      main.go

170
main.go

@ -9,6 +9,7 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
"flag"
"fmt" "fmt"
"log" "log"
"os" "os"
@ -45,21 +46,22 @@ const (
type ( type (
// TextResource stores multilingual text / 存储多语言文本 // TextResource stores multilingual text / 存储多语言文本
TextResource struct { TextResource struct {
SuccessMessage string
RestartMessage string
ReadingConfig string
GeneratingIds string
PressEnterToExit string
ErrorPrefix string
PrivilegeError string
RunAsAdmin string
RunWithSudo string
SudoExample string
ConfigLocation string
CheckingProcesses string
ClosingProcesses string
ProcessesClosed string
PleaseWait string
SuccessMessage string
RestartMessage string
ReadingConfig string
GeneratingIds string
PressEnterToExit string
ErrorPrefix string
PrivilegeError string
RunAsAdmin string
RunWithSudo string
SudoExample string
ConfigLocation string
CheckingProcesses string
ClosingProcesses string
ProcessesClosed string
PleaseWait string
SetReadOnlyMessage string
} }
// StorageConfig optimized storage configuration / 优化的存储配置 // StorageConfig optimized storage configuration / 优化的存储配置
@ -117,42 +119,46 @@ var (
texts = map[Language]TextResource{ texts = map[Language]TextResource{
CN: { CN: {
SuccessMessage: "[√] 配置文件已成功更新!",
RestartMessage: "[!] 请手动重启 Cursor 以使更新生效",
ReadingConfig: "正在读取配置文件...",
GeneratingIds: "正在生成新的标识符...",
PressEnterToExit: "按回车键退出程序...",
ErrorPrefix: "程序发生严重错误: %v",
PrivilegeError: "\n[!] 错误:需要管理员权限",
RunAsAdmin: "请右键点击程序,选择「以管理员身份运行」",
RunWithSudo: "请使用 sudo 命令运行此程序",
SudoExample: "示例: sudo %s",
ConfigLocation: "配置文件位置:",
CheckingProcesses: "正在检查运行中的 Cursor 实例...",
ClosingProcesses: "正在关闭 Cursor 实例...",
ProcessesClosed: "所有 Cursor 实例已关闭",
PleaseWait: "请稍候...",
SuccessMessage: "[√] 配置文件已成功更新!",
RestartMessage: "[!] 请手动重启 Cursor 以使更新生效",
ReadingConfig: "正在读取配置文件...",
GeneratingIds: "正在生成新的标识符...",
PressEnterToExit: "按回车键退出程序...",
ErrorPrefix: "程序发生严重错误: %v",
PrivilegeError: "\n[!] 错误:需要管理员权限",
RunAsAdmin: "请右键点击程序,选择「以管理员身份运行」",
RunWithSudo: "请使用 sudo 命令运行此程序",
SudoExample: "示例: sudo %s",
ConfigLocation: "配置文件位置:",
CheckingProcesses: "正在检查运行中的 Cursor 实例...",
ClosingProcesses: "正在关闭 Cursor 实例...",
ProcessesClosed: "所有 Cursor 实例已关闭",
PleaseWait: "请稍候...",
SetReadOnlyMessage: "设置 storage.json 为只读模式, 这将导致 workspace 记录信息丢失等问题",
}, },
EN: { EN: {
SuccessMessage: "[√] Configuration file updated successfully!",
RestartMessage: "[!] Please restart Cursor manually for changes to take effect",
ReadingConfig: "Reading configuration file...",
GeneratingIds: "Generating new identifiers...",
PressEnterToExit: "Press Enter to exit...",
ErrorPrefix: "Program encountered a serious error: %v",
PrivilegeError: "\n[!] Error: Administrator privileges required",
RunAsAdmin: "Please right-click and select 'Run as Administrator'",
RunWithSudo: "Please run this program with sudo",
SudoExample: "Example: sudo %s",
ConfigLocation: "Config file location:",
CheckingProcesses: "Checking for running Cursor instances...",
ClosingProcesses: "Closing Cursor instances...",
ProcessesClosed: "All Cursor instances have been closed",
PleaseWait: "Please wait...",
SuccessMessage: "[√] Configuration file updated successfully!",
RestartMessage: "[!] Please restart Cursor manually for changes to take effect",
ReadingConfig: "Reading configuration file...",
GeneratingIds: "Generating new identifiers...",
PressEnterToExit: "Press Enter to exit...",
ErrorPrefix: "Program encountered a serious error: %v",
PrivilegeError: "\n[!] Error: Administrator privileges required",
RunAsAdmin: "Please right-click and select 'Run as Administrator'",
RunWithSudo: "Please run this program with sudo",
SudoExample: "Example: sudo %s",
ConfigLocation: "Config file location:",
CheckingProcesses: "Checking for running Cursor instances...",
ClosingProcesses: "Closing Cursor instances...",
ProcessesClosed: "All Cursor instances have been closed",
PleaseWait: "Please wait...",
SetReadOnlyMessage: "Set storage.json to read-only mode, which will cause issues such as lost workspace records",
}, },
} }
) )
var setReadOnly *bool = flag.Bool("r", false, "set storage.json to read-only mode")
// Error Implementation / 错误实现 // Error Implementation / 错误实现
func (e *AppError) Error() string { func (e *AppError) Error() string {
if e.Context != nil { if e.Context != nil {
@ -225,16 +231,6 @@ func saveConfig(config *StorageConfig, username string) error { // Modified to t
return err return err
} }
content, err := json.MarshalIndent(config, "", " ")
if err != nil {
return &AppError{
Type: ErrSystem,
Op: "generate JSON",
Path: "",
Err: err,
}
}
// Create parent directories with proper permissions // Create parent directories with proper permissions
dir := filepath.Dir(configPath) dir := filepath.Dir(configPath)
if err := os.MkdirAll(dir, 0755); err != nil { if err := os.MkdirAll(dir, 0755); err != nil {
@ -256,9 +252,53 @@ func saveConfig(config *StorageConfig, username string) error { // Modified to t
} }
} }
originalFileStat, err := os.Stat(configPath)
if err != nil {
return &AppError{
Type: ErrSystem,
Op: "get file mode",
Path: configPath,
Err: err,
}
}
originalFileMode := originalFileStat.Mode()
originalFileContent, err := os.ReadFile(configPath)
if err != nil {
return &AppError{
Type: ErrSystem,
Op: "read original file",
Path: configPath,
Err: err,
}
}
var originalFile map[string]any
if err := json.Unmarshal(originalFileContent, &originalFile); err != nil {
return &AppError{
Type: ErrSystem,
Op: "unmarshal original file",
Path: configPath,
Err: err,
}
}
originalFile["telemetry.sqmId"] = config.TelemetrySqmId
originalFile["telemetry.macMachineId"] = config.TelemetryMacMachineId
originalFile["telemetry.machineId"] = config.TelemetryMachineId
originalFile["telemetry.devDeviceId"] = config.TelemetryDevDeviceId
newFileContent, err := json.MarshalIndent(originalFile, "", " ")
if err != nil {
return &AppError{
Type: ErrSystem,
Op: "marshal new file",
Path: configPath,
Err: err,
}
}
// Write to temporary file first // Write to temporary file first
tmpPath := configPath + ".tmp" tmpPath := configPath + ".tmp"
if err := os.WriteFile(tmpPath, content, 0666); err != nil {
if err := os.WriteFile(tmpPath, newFileContent, 0666); err != nil {
return &AppError{ return &AppError{
Type: ErrSystem, Type: ErrSystem,
Op: "write temporary file", Op: "write temporary file",
@ -267,8 +307,12 @@ func saveConfig(config *StorageConfig, username string) error { // Modified to t
} }
} }
if *setReadOnly {
originalFileMode = 0444
}
// Ensure proper permissions on temporary file // Ensure proper permissions on temporary file
if err := os.Chmod(tmpPath, 0444); err != nil {
if err := os.Chmod(tmpPath, originalFileMode); err != nil {
os.Remove(tmpPath) os.Remove(tmpPath)
return &AppError{ return &AppError{
Type: ErrSystem, Type: ErrSystem,
@ -495,6 +539,15 @@ func showSuccess() {
} }
} }
func showReadOnlyMessage() {
if *setReadOnly {
warningColor := color.New(color.FgYellow, color.Bold)
warningColor.Printf("%s\n", texts[currentLanguage].SetReadOnlyMessage)
fmt.Println("Press Enter to continue...")
bufio.NewReader(os.Stdin).ReadString('\n')
}
}
func showPrivilegeError() { func showPrivilegeError() {
text := texts[currentLanguage] text := texts[currentLanguage]
red := color.New(color.FgRed, color.Bold) red := color.New(color.FgRed, color.Bold)
@ -691,6 +744,9 @@ func main() {
} }
}() }()
flag.Parse()
showReadOnlyMessage()
var username string var username string
if username = os.Getenv("SUDO_USER"); username == "" { if username = os.Getenv("SUDO_USER"); username == "" {
user, err := user.Current() user, err := user.Current()

Loading…
Cancel
Save