feat: Enhance configuration management and build scripts

- Updated `go.mod` to include new dependencies for color output.
- Refactored `main.go` to improve `StorageConfig` structure and add new methods for configuration management.
- Implemented a progress spinner and error handling for file operations.
- Enhanced build scripts (`build_all.bat` and `build_all.sh`) for better output and error handling, including versioning and cleanup processes.
- Removed obsolete binary files for various platforms.
- Updated VSCode settings for spell checking.

This commit improves the overall functionality and user experience of the Cursor ID Modifier tool.
This commit is contained in:
Xx 2024-12-10 22:19:20 +08:00
parent fb2358c86f
commit a1c2203752
14 changed files with 559 additions and 110 deletions

11
.vscode/settings.json vendored
View File

@ -1,7 +1,16 @@
{
"cSpell.words": [
"buildmode",
"endlocal",
"errorlevel",
"fatih",
"gcflags",
"GOARCH",
"ldflags",
"LOCALAPPDATA",
"pkill",
"taskkill"
"setlocal",
"taskkill",
"trimpath"
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

8
go.mod
View File

@ -1,3 +1,11 @@
module go-cursor-help
go 1.22.0
require github.com/fatih/color v1.18.0
require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/sys v0.25.0 // indirect
)

11
go.sum Normal file
View File

@ -0,0 +1,11 @@
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=

400
main.go
View File

@ -1,21 +1,41 @@
package main
import (
"bufio"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/fatih/color"
)
// StorageConfig 存储配置结构体
// StorageConfig 存储配置结构体优化
type StorageConfig struct {
TelemetryMacMachineId string `json:"telemetry.macMachineId"`
TelemetryMachineId string `json:"telemetry.machineId"`
TelemetryDevDeviceId string `json:"telemetry.devDeviceId"`
LastModified time.Time `json:"lastModified"`
Version string `json:"version"`
}
// NewStorageConfig 创建新的配置实例
func NewStorageConfig() *StorageConfig {
return &StorageConfig{
TelemetryMacMachineId: generateMacMachineId(),
TelemetryMachineId: generateMachineId(),
TelemetryDevDeviceId: generateDevDeviceId(),
LastModified: time.Now(),
Version: "1.0.1",
}
}
// 生成类似原始machineId的字符串 (64位小写hex)
@ -37,7 +57,7 @@ func generateMacMachineId() string {
return generateMachineId() // 使用相同的格式
}
// 生成类似原始devDeviceId的字符 (标准UUID格式)
// 生成类似原始devDeviceId的字符 (标准UUID格式)
func generateDevDeviceId() string {
// 生成 UUID v4
uuid := make([]byte, 16)
@ -81,7 +101,7 @@ func getConfigPath() (string, error) {
return filepath.Join(configDir, "storage.json"), nil
}
// 修改件权限
// 修改件权限
func setFilePermissions(filePath string) error {
if runtime.GOOS == "windows" {
// Windows 使用 ACL 权限系统,这里仅设置为只读
@ -92,86 +112,320 @@ func setFilePermissions(filePath string) error {
}
}
// 获取Cursor可执行文件路径
func getCursorExePath() (string, error) {
switch runtime.GOOS {
case "windows":
// Windows下通常在LocalAppData目录
localAppData := os.Getenv("LOCALAPPDATA")
return filepath.Join(localAppData, "Programs", "Cursor", "Cursor.exe"), nil
case "darwin":
// macOS下通常在Applications目录
return "/Applications/Cursor.app/Contents/MacOS/Cursor", nil
case "linux":
// Linux下可能在usr/bin目录
return "/usr/bin/cursor", nil
default:
return "", fmt.Errorf("不支持的操作系统: %s", runtime.GOOS)
func printCyberpunkBanner() {
cyan := color.New(color.FgCyan, color.Bold)
yellow := color.New(color.FgYellow, color.Bold)
magenta := color.New(color.FgMagenta, color.Bold)
banner := `
`
cyan.Println(banner)
yellow.Println("\t\t>> Cursor ID Modifier v1.0 <<")
magenta.Println("\t\t [ By Pancake Fruit Rolled Shark Chili ]")
}
type ProgressSpinner struct {
frames []string
current int
message string
}
func NewProgressSpinner(message string) *ProgressSpinner {
return &ProgressSpinner{
frames: []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"},
message: message,
}
}
func (s *ProgressSpinner) Spin() {
frame := s.frames[s.current%len(s.frames)]
s.current++
fmt.Printf("\r%s %s", color.CyanString(frame), s.message)
}
func (s *ProgressSpinner) Stop() {
fmt.Println()
}
// 定义错误类型
type AppError struct {
Op string
Path string
Err error
}
func (e *AppError) Error() string {
if e.Path != "" {
return fmt.Sprintf("%s: %v [路径: %s]", e.Op, e.Err, e.Path)
}
return fmt.Sprintf("%s: %v", e.Op, e.Err)
}
// 文件操作包装函数
func safeWriteFile(path string, data []byte, perm os.FileMode) error {
// 创建临时文件
tmpPath := path + ".tmp"
if err := os.WriteFile(tmpPath, data, perm); err != nil {
return &AppError{"写入临时文件", tmpPath, err}
}
// 重命名临时文件
if err := os.Rename(tmpPath, path); err != nil {
os.Remove(tmpPath) // 清理临时文件
return &AppError{"重命名文件", path, err}
}
return nil
}
// clearScreen 清除终端屏幕
func clearScreen() {
if runtime.GOOS == "windows" {
cmd := exec.Command("cmd", "/c", "cls")
cmd.Stdout = os.Stdout
cmd.Run()
} else {
cmd := exec.Command("clear")
cmd.Stdout = os.Stdout
cmd.Run()
}
}
// showProgress 显示进度
func showProgress(message string) {
spinner := NewProgressSpinner(message)
for i := 0; i < 15; i++ {
spinner.Spin()
time.Sleep(100 * time.Millisecond)
}
spinner.Stop()
}
// saveConfig 保存配置到文件
func saveConfig(config *StorageConfig) error {
configPath, err := getConfigPath()
if err != nil {
return err
}
// 转换为JSON
content, err := json.MarshalIndent(config, "", " ")
if err != nil {
return &AppError{"生成JSON", "", err}
}
// 确保文件可写
err = os.Chmod(configPath, 0666)
if err != nil {
return &AppError{"修改文件权限", configPath, err}
}
// 安全写入文件
if err := safeWriteFile(configPath, content, 0666); err != nil {
return err
}
// 设置为只读
return setFilePermissions(configPath)
}
// showSuccess 显示成功信息
func showSuccess() {
text := texts[currentLanguage]
color.Green(text.SuccessMessage)
color.Yellow(text.RestartMessage)
}
// 修改 loadAndUpdateConfig 函数使用 configPath
func loadAndUpdateConfig() (*StorageConfig, error) {
configPath, err := getConfigPath()
if err != nil {
return nil, err
}
text := texts[currentLanguage]
showProgress(text.ReadingConfig)
// 读取原始文件内容
_, err = os.ReadFile(configPath)
if err != nil && !os.IsNotExist(err) {
return nil, &AppError{"读取配置文件", configPath, err}
}
showProgress(text.GeneratingIds)
config := NewStorageConfig()
return config, nil
}
// 修改 waitExit 函数,正确初始化 reader
func waitExit() {
reader := bufio.NewReader(os.Stdin)
color.Cyan("\n" + texts[currentLanguage].PressEnterToExit)
reader.ReadString('\n')
}
func main() {
// 获取配置文件路径
configPath, err := getConfigPath()
currentLanguage = detectLanguage()
defer func() {
if err := recover(); err != nil {
color.Red(texts[currentLanguage].ErrorPrefix, err)
waitExit()
}
}()
// 添加权限检查
isAdmin, err := checkAdminPrivileges()
if err != nil {
fmt.Printf("获取配置文件路径失败: %v\n", err)
handleError("权限检查失败", err)
waitExit()
return
}
if !isAdmin {
showPrivilegeError()
waitExit()
return
}
// 读取原始文件内容
content, err := os.ReadFile(configPath)
setupProgram()
config, err := loadAndUpdateConfig()
if err != nil {
fmt.Printf("读取配置文件失败: %v\n", err)
handleError("配置更新失败", err)
return
}
if err := saveConfig(config); err != nil {
handleError("保存配置失败", err)
return
}
// 备份配置文件
backupPath := configPath + ".bak"
err = os.WriteFile(backupPath, content, 0666)
if err != nil {
fmt.Printf("备份配置文件失败: %v\n", err)
return
}
// 解析 JSON
var config map[string]interface{}
if err := json.Unmarshal(content, &config); err != nil {
fmt.Printf("解析 JSON 失败: %v\n", err)
return
}
// 修改指定字段,使用更准确的生成方法
config["telemetry.macMachineId"] = generateMacMachineId()
config["telemetry.machineId"] = generateMachineId()
config["telemetry.devDeviceId"] = generateDevDeviceId()
// 转换回 JSON保持原有的格式
newContent, err := json.MarshalIndent(config, "", " ")
if err != nil {
fmt.Printf("生成 JSON 失败: %v\n", err)
return
}
// 先确保文件可写
err = os.Chmod(configPath, 0666)
if err != nil {
fmt.Printf("修改文件权限失败: %v\n", err)
return
}
// 写入文件
err = os.WriteFile(configPath, newContent, 0666)
if err != nil {
fmt.Printf("写入文件失败: %v\n", err)
return
}
// 设置文件为只读
err = setFilePermissions(configPath)
if err != nil {
fmt.Printf("设置文件只读权限失败: %v\n", err)
return
}
fmt.Println("配置文件已成功更新请手动重启Cursor以使更改生效。")
showSuccess()
waitExit()
}
func setupProgram() {
clearScreen()
printCyberpunkBanner()
}
func handleError(msg string, err error) {
if appErr, ok := err.(*AppError); ok {
color.Red("%s: %v", msg, appErr)
} else {
color.Red("%s: %v", msg, err)
}
}
func checkAdminPrivileges() (bool, error) {
switch runtime.GOOS {
case "windows":
// Windows 管理员权限检查
cmd := exec.Command("net", "session")
err := cmd.Run()
return err == nil, nil
case "darwin", "linux":
// Unix 系统检查 root 权限
currentUser, err := user.Current()
if err != nil {
return false, fmt.Errorf("获取当前用户失败: %v", err)
}
return currentUser.Uid == "0", nil
default:
return false, fmt.Errorf("不支持的操作系统: %s", runtime.GOOS)
}
}
func showPrivilegeError() {
text := texts[currentLanguage]
red := color.New(color.FgRed, color.Bold)
yellow := color.New(color.FgYellow)
red.Println(text.PrivilegeError)
if runtime.GOOS == "windows" {
yellow.Println(text.RunAsAdmin)
} else {
yellow.Println(text.RunWithSudo)
yellow.Printf(text.SudoExample, os.Args[0])
}
}
// 在文件开头添加新的类型和变量定义
type Language string
const (
CN Language = "cn"
EN Language = "en"
)
// TextResource 存储多语言文本
type TextResource struct {
SuccessMessage string
RestartMessage string
ReadingConfig string
GeneratingIds string
PressEnterToExit string
ErrorPrefix string
PrivilegeError string
RunAsAdmin string
RunWithSudo string
SudoExample string
}
var (
currentLanguage = CN // 默认使用中文
texts = map[Language]TextResource{
CN: {
SuccessMessage: "[√] 配置文件已成功更新!",
RestartMessage: "[!] 请手动重启 Cursor 以使更改生效",
ReadingConfig: "正在读取配置文件...",
GeneratingIds: "正在生成新的标识符...",
PressEnterToExit: "按回车键退出程序...",
ErrorPrefix: "程序发生严重错误: %v",
PrivilegeError: "\n[!] 错误:需要管理员权限",
RunAsAdmin: "请右键点击程序,选择「以管理员身份运行」",
RunWithSudo: "请使用 sudo 命令运行此程序",
SudoExample: "示例: sudo %s",
},
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",
},
}
)
// 添加语言检测函数
func detectLanguage() Language {
// 获取系统语言环境
lang := os.Getenv("LANG")
if lang == "" {
lang = os.Getenv("LANGUAGE")
}
// 如果包含 zh 则使用中文,否则使用英文
if strings.Contains(strings.ToLower(lang), "zh") {
return CN
}
return EN
}

View File

@ -1,28 +1,116 @@
@echo off
echo Creating bin directory...
if not exist "..\bin" mkdir "..\bin"
setlocal EnableDelayedExpansion
echo Building for all platforms...
:: 设置版本信息
set VERSION=1.0.0
echo Building for Windows AMD64...
set GOOS=windows
set GOARCH=amd64
go build -o ../bin/cursor_id_modifier.exe ../main.go
:: 设置颜色代码
set "GREEN=[32m"
set "RED=[31m"
set "YELLOW=[33m"
set "RESET=[0m"
echo Building for macOS AMD64...
set GOOS=darwin
set GOARCH=amd64
go build -o ../bin/cursor_id_modifier_mac ../main.go
:: 设置编译优化标志
set "LDFLAGS=-s -w"
set "BUILDMODE=pie"
set "GCFLAGS=-N -l"
echo Building for macOS ARM64...
set GOOS=darwin
set GOARCH=arm64
go build -o ../bin/cursor_id_modifier_mac_arm64 ../main.go
:: 检查是否安装了必要的交叉编译工具
where gcc >nul 2>nul
if %errorlevel% neq 0 (
echo %RED%错误: 未找到 gcc这可能会影响 Mac 系统的交叉编译%RESET%
echo %YELLOW%请安装 MinGW-w64 或其他 gcc 工具链%RESET%
pause
exit /b 1
)
echo Building for Linux AMD64...
set GOOS=linux
set GOARCH=amd64
go build -o ../bin/cursor_id_modifier_linux ../main.go
:: 设置 CGO
set CGO_ENABLED=0
echo All builds completed!
pause
:: 显示编译信息
echo %YELLOW%开始构建 version %VERSION%%RESET%
echo %YELLOW%使用优化标志: LDFLAGS=%LDFLAGS%, BUILDMODE=%BUILDMODE%%RESET%
echo %YELLOW%CGO_ENABLED=%CGO_ENABLED%%RESET%
:: 仅在必要时清理旧文件
if "%1"=="clean" (
echo 清理旧构建文件...
if exist "..\bin" rd /s /q "..\bin"
)
:: 创建输出目录
if not exist "..\bin" mkdir "..\bin" 2>nul
:: 定义目标平台数组
set platforms[0].os=windows
set platforms[0].arch=amd64
set platforms[0].ext=.exe
set platforms[1].os=darwin
set platforms[1].arch=amd64
set platforms[1].ext=
set platforms[2].os=darwin
set platforms[2].arch=arm64
set platforms[2].ext=
set platforms[3].os=linux
set platforms[3].arch=amd64
set platforms[3].ext=
:: 设置开始时间
set start_time=%time%
:: 编译所有目标
echo 开始编译所有平台...
for /L %%i in (0,1,3) do (
set "os=!platforms[%%i].os!"
set "arch=!platforms[%%i].arch!"
set "ext=!platforms[%%i].ext!"
echo.
echo Building for !os! !arch!...
set GOOS=!os!
set GOARCH=!arch!
:: 为 darwin 系统设置特殊编译参数和文件名
if "!os!"=="darwin" (
set "extra_flags=-tags ios"
if "!arch!"=="amd64" (
set "outfile=..\bin\cursor_id_modifier_v%VERSION%_mac_intel!ext!"
) else (
set "outfile=..\bin\cursor_id_modifier_v%VERSION%_mac_m1!ext!"
)
) else (
set "extra_flags="
set "outfile=..\bin\cursor_id_modifier_v%VERSION%_!os!_!arch!!ext!"
)
go build -trimpath !extra_flags! -buildmode=%BUILDMODE% -ldflags="%LDFLAGS%" -gcflags="%GCFLAGS%" -o "!outfile!" ..\main.go
if !errorlevel! equ 0 (
echo %GREEN%Build successful: !outfile!%RESET%
) else (
echo %RED%Build failed for !os! !arch!%RESET%
echo %YELLOW%如果是 Mac 系统编译失败,请确保:%RESET%
echo %YELLOW%1. 已安装 MinGW-w64%RESET%
echo %YELLOW%2. 已设置 GOARCH 和 GOOS%RESET%
echo %YELLOW%3. CGO_ENABLED=0%RESET%
)
)
:: 计算总耗时
set end_time=%time%
set options="tokens=1-4 delims=:.,"
for /f %options% %%a in ("%start_time%") do set start_s=%%a&set start_m=%%b&set start_h=%%c
for /f %options% %%a in ("%end_time%") do set end_s=%%a&set end_m=%%b&set end_h=%%c
set /a duration = (end_h - start_h) * 3600 + (end_m - start_m) * 60 + (end_s - start_s)
echo.
echo %GREEN%所有构建完成! 总耗时: %duration%%RESET%
if exist "..\bin" dir /b "..\bin"
pause
endlocal

View File

@ -1,22 +1,101 @@
#!/bin/bash
# 创建bin目录如果不存在
mkdir -p ../bin
# 设置颜色代码
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Windows
echo "Building for Windows..."
GOOS=windows GOARCH=amd64 go build -o ../bin/cursor_id_modifier.exe ../main.go
# 版本信息
VERSION="1.0.0"
# macOS (Intel)
echo "Building for macOS (Intel)..."
GOOS=darwin GOARCH=amd64 go build -o ../bin/cursor_id_modifier_mac ../main.go
# 错误处理函数
handle_error() {
echo -e "${RED}Error: $1${NC}"
exit 1
}
# macOS (Apple Silicon)
echo "Building for macOS (ARM64)..."
GOOS=darwin GOARCH=arm64 go build -o ../bin/cursor_id_modifier_mac_arm64 ../main.go
# 清理函数
cleanup() {
echo "Cleaning old builds..."
rm -rf ../bin
}
# Linux
echo "Building for Linux..."
GOOS=linux GOARCH=amd64 go build -o ../bin/cursor_id_modifier_linux ../main.go
# 创建输出目录
create_output_dir() {
echo "Creating bin directory..."
mkdir -p ../bin || handle_error "Failed to create bin directory"
}
echo "All builds completed!"
# 构建函数
build() {
local os=$1
local arch=$2
local suffix=$3
echo -e "\nBuilding for $os ($arch)..."
output_name="../bin/cursor_id_modifier_v${VERSION}_${os}_${arch}${suffix}"
GOOS=$os GOARCH=$arch go build -o "$output_name" ../main.go
if [ $? -eq 0 ]; then
echo -e "${GREEN}✓ Successfully built: ${output_name}${NC}"
else
echo -e "${RED}✗ Failed to build for $os $arch${NC}"
return 1
fi
}
# 主函数
main() {
# 显示构建信息
echo "Starting build process for version ${VERSION}"
# 清理旧文件
cleanup
# 创建输出目录
create_output_dir
# 定义构建目标
declare -A targets=(
["windows_amd64"]=".exe"
["darwin_amd64"]=""
["darwin_arm64"]=""
["linux_amd64"]=""
)
# 构建计数器
local success_count=0
local fail_count=0
# 遍历所有目标进行构建
for target in "${!targets[@]}"; do
os=${target%_*}
arch=${target#*_}
suffix=${targets[$target]}
if build "$os" "$arch" "$suffix"; then
((success_count++))
else
((fail_count++))
fi
done
# 显示构建结果
echo -e "\nBuild Summary:"
echo -e "${GREEN}Successful builds: $success_count${NC}"
if [ $fail_count -gt 0 ]; then
echo -e "${RED}Failed builds: $fail_count${NC}"
fi
# 显示生成的文件列表
echo -e "\nGenerated files:"
ls -1 ../bin
}
# 捕获错误信号
trap 'echo -e "\n${RED}Build process interrupted${NC}"; exit 1' INT TERM
# 执行主函数
main