diff --git a/.vscode/settings.json b/.vscode/settings.json index b9d69bd..4c8bd49 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -6,12 +6,18 @@ "fatih", "gcflags", "GOARCH", + "IMAGENAME", "ldflags", "LOCALAPPDATA", + "mktemp", + "msys", + "pgrep", "pkill", "runas", "setlocal", "taskkill", - "trimpath" + "tasklist", + "trimpath", + "xattr" ] } \ No newline at end of file diff --git a/bin/cursor_id_modifier_v2.0.0_linux_amd64 b/bin/cursor_id_modifier_v2.0.0_linux_amd64 index eb17572..9532b92 100644 Binary files a/bin/cursor_id_modifier_v2.0.0_linux_amd64 and b/bin/cursor_id_modifier_v2.0.0_linux_amd64 differ diff --git a/bin/cursor_id_modifier_v2.0.0_mac_intel b/bin/cursor_id_modifier_v2.0.0_mac_intel deleted file mode 100644 index e87a90e..0000000 Binary files a/bin/cursor_id_modifier_v2.0.0_mac_intel and /dev/null differ diff --git a/bin/cursor_id_modifier_v2.0.0_mac_m1 b/bin/cursor_id_modifier_v2.0.0_mac_m1 deleted file mode 100644 index 5d9b82d..0000000 Binary files a/bin/cursor_id_modifier_v2.0.0_mac_m1 and /dev/null differ diff --git a/bin/cursor_id_modifier_v2.0.0_windows_amd64.exe b/bin/cursor_id_modifier_v2.0.0_windows_amd64.exe index e6310a6..22784c3 100644 Binary files a/bin/cursor_id_modifier_v2.0.0_windows_amd64.exe and b/bin/cursor_id_modifier_v2.0.0_windows_amd64.exe differ diff --git a/go.mod b/go.mod index 27ba945..6b674f1 100644 --- a/go.mod +++ b/go.mod @@ -2,12 +2,10 @@ module cursor-id-modifier go 1.21 -require ( - github.com/fatih/color v1.15.0 - golang.org/x/sys v0.13.0 -) +require github.com/fatih/color v1.15.0 require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect + golang.org/x/sys v0.13.0 // indirect ) diff --git a/install.sh b/install.sh index e412e31..8cb8da0 100644 --- a/install.sh +++ b/install.sh @@ -1,75 +1,141 @@ #!/bin/bash -# Error handling function / 错误处理函数 +# Version / 版本号 +VERSION="v2.0.0" + +# Bilingual message functions / 双语消息函数 error() { - echo "Error/错误: $1" >&2 + echo "❌ Error: $1" + echo "❌ 错误:$2" exit 1 } +info() { + echo "ℹ️ $1" + echo "ℹ️ $2" +} + +success() { + echo "✅ $1" + echo "✅ $2" +} + # Detect OS and architecture / 检测操作系统和架构 detect_platform() { - # Get lowercase OS name and architecture / 获取小写操作系统名称和架构 OS=$(uname -s | tr '[:upper:]' '[:lower:]') ARCH=$(uname -m) - # Set binary name based on platform / 根据平台设置二进制文件名 case "$OS" in linux*) case "$ARCH" in - x86_64) BINARY_NAME="cursor_id_modifier_v2.0.0_linux_amd64" ;; - *) error "Unsupported Linux architecture/不支持的Linux架构: $ARCH" ;; + x86_64) BINARY_NAME="cursor_id_modifier_${VERSION}_linux_amd64" ;; + *) error "Unsupported Linux architecture: $ARCH" "不支持的Linux架构:$ARCH" ;; esac ;; darwin*) case "$ARCH" in - x86_64) BINARY_NAME="cursor_id_modifier_v2.0.0_mac_intel" ;; - arm64) BINARY_NAME="cursor_id_modifier_v2.0.0_mac_m1" ;; - *) error "Unsupported macOS architecture/不支持的macOS架构: $ARCH" ;; + x86_64) BINARY_NAME="cursor_id_modifier_${VERSION}_darwin_amd64_intel" ;; + arm64) BINARY_NAME="cursor_id_modifier_${VERSION}_darwin_arm64_m1" ;; + *) error "Unsupported macOS architecture: $ARCH" "不支持的macOS架构:$ARCH" ;; + esac + ;; + msys*|mingw*|cygwin*) + case "$ARCH" in + x86_64) BINARY_NAME="cursor_id_modifier_${VERSION}_windows_amd64.exe" ;; + *) error "Unsupported Windows architecture: $ARCH" "不支持的Windows架构:$ARCH" ;; esac ;; *) - error "Unsupported operating system/不支持的操作系统: $OS" + error "Unsupported operating system: $OS" "不支持的操作系统:$OS" ;; esac } -# Check root privileges / 检查root权限 -if [ "$(id -u)" -ne 0 ]; then - error "This script must be run with sudo or as root/此脚本必须使用sudo或root权限运行" -fi +# Check system requirements / 检查系统要求 +check_requirements() { + info "Checking system requirements..." "正在检查系统要求..." + + # Check curl + if ! command -v curl >/dev/null 2>&1; then + error "curl is required. Please install curl first." \ + "需要安装 curl。请先安装 curl 后再运行此脚本。" + fi + + # Check write permissions / 检查写入权限 + if [ ! -w "$INSTALL_DIR" ]; then + error "No write permission for $INSTALL_DIR. Please run with sudo." \ + "没有 $INSTALL_DIR 的写入权限。请使用 sudo 运行此脚本。" + } +} -# Initialize installation / 初始化安装 -detect_platform -INSTALL_DIR="/usr/local/bin" -[ -d "$INSTALL_DIR" ] || mkdir -p "$INSTALL_DIR" +# Verify binary / 验证二进制文件 +verify_binary() { + info "Verifying binary..." "正在验证二进制文件..." + if [ ! -f "$TEMP_DIR/$BINARY_NAME" ]; then + error "Binary file download failed or does not exist" \ + "二进制文件下载失败或不存在" + fi + + # Check file size / 检查文件大小 + local size=$(wc -c < "$TEMP_DIR/$BINARY_NAME") + if [ "$size" -lt 1000000 ]; then # At least 1MB / 至少1MB + error "Downloaded file size is abnormal, download might be incomplete" \ + "下载的文件大小异常,可能下载不完整" + } +} -# Download binary / 下载二进制文件 -echo "Downloading cursor-id-modifier for/正在下载 $OS ($ARCH)..." -TEMP_DIR=$(mktemp -d) -DOWNLOAD_URL="https://github.com/yuaotian/go-cursor-help/raw/main/bin/$BINARY_NAME" +# Main installation process / 主安装流程 +main() { + info "Starting installation of cursor-id-modifier ${VERSION}..." \ + "开始安装 cursor-id-modifier ${VERSION}..." + + # Initialize installation / 初始化安装 + detect_platform + INSTALL_DIR="/usr/local/bin" + [ -d "$INSTALL_DIR" ] || mkdir -p "$INSTALL_DIR" + + # Check requirements / 检查要求 + check_requirements + + # Create temp directory / 创建临时目录 + TEMP_DIR=$(mktemp -d) + trap 'rm -rf "$TEMP_DIR"' EXIT + + # Download binary / 下载二进制文件 + info "Downloading cursor-id-modifier ($OS-$ARCH)..." \ + "正在下载 cursor-id-modifier ($OS-$ARCH)..." + DOWNLOAD_URL="https://github.com/yuaotian/go-cursor-help/raw/main/bin/$BINARY_NAME" + + if ! curl -fsSL "$DOWNLOAD_URL" -o "$TEMP_DIR/$BINARY_NAME"; then + error "Failed to download binary" "下载二进制文件失败" + fi + + # Verify download / 验证下载 + verify_binary + + # Set permissions / 设置权限 + info "Setting execution permissions..." "正在设置执行权限..." + if ! chmod +x "$TEMP_DIR/$BINARY_NAME"; then + error "Failed to set executable permissions" "无法设置可执行权限" + fi + + # Handle macOS security / 处理macOS安全设置 + if [ "$OS" = "darwin" ]; then + info "Handling macOS security settings..." "正在处理macOS安全设置..." + xattr -d com.apple.quarantine "$TEMP_DIR/$BINARY_NAME" 2>/dev/null || true + fi + + # Install binary / 安装二进制文件 + info "Installing binary..." "正在安装二进制文件..." + if ! mv "$TEMP_DIR/$BINARY_NAME" "$INSTALL_DIR/cursor-id-modifier"; then + error "Failed to install binary" "安装二进制文件失败" + fi + + success "Installation successful! You can now run 'cursor-id-modifier' from anywhere." \ + "安装成功!现在可以在任何位置运行 'cursor-id-modifier'。" + success "For help, run 'cursor-id-modifier --help'" \ + "如需帮助,请运行 'cursor-id-modifier --help'" +} -if ! curl -fsSL "$DOWNLOAD_URL" -o "$TEMP_DIR/$BINARY_NAME"; then - error "Failed to download binary/下载二进制文件失败" -fi - -# Set permissions / 设置权限 -if ! chmod +x "$TEMP_DIR/$BINARY_NAME"; then - error "Failed to make binary executable/无法设置可执行权限" -fi - -# Handle macOS security / 处理macOS安全设置 -if [ "$OS" = "darwin" ]; then - echo "Removing macOS quarantine attribute/移除macOS隔离属性..." - xattr -d com.apple.quarantine "$TEMP_DIR/$BINARY_NAME" 2>/dev/null || true -fi - -# Install binary / 安装二进制文件 -if ! mv "$TEMP_DIR/$BINARY_NAME" "$INSTALL_DIR/cursor-id-modifier"; then - error "Failed to install binary/安装二进制文件失败" -fi - -# Cleanup / 清理 -rm -rf "$TEMP_DIR" - -echo "✅ Installation successful! You can now run 'cursor-id-modifier' from anywhere." -echo "✅ 安装成功!现在可以在任何位置运行 'cursor-id-modifier'。" \ No newline at end of file +# Start installation / 开始安装 +main \ No newline at end of file diff --git a/main.go b/main.go index b0ce95d..cb3bfbb 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,3 @@ -// 主程序包 / Main package package main // 导入所需的包 / Import required packages @@ -9,6 +8,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "log" "os" "os/exec" "os/user" @@ -16,9 +16,10 @@ import ( "runtime" "strings" "time" - "github.com/fatih/color" - "golang.org/x/sys/windows" + "context" + "errors" + "runtime/debug" ) // 语言类型和常量 / Language type and constants @@ -30,6 +31,12 @@ const ( // Version constant Version = "1.0.1" + + // 定义错误类型常量 + ErrPermission = "permission_error" + ErrConfig = "config_error" + ErrProcess = "process_error" + ErrSystem = "system_error" ) // TextResource 存储多语言文本 / TextResource stores multilingual text @@ -57,9 +64,11 @@ type StorageConfig struct { // AppError 定义错误类型 / AppError defines error types type AppError struct { - Op string - Path string - Err error + Type string + Op string + Path string + Err error + Context map[string]interface{} } // ProgressSpinner 用于显示进度动画 / ProgressSpinner for showing progress animation @@ -69,6 +78,14 @@ type ProgressSpinner struct { message string } +// SpinnerConfig 定义进度条配置 +type SpinnerConfig struct { + Frames []string + Delay time.Duration +} + + + // 全局变量 / Global variables var ( currentLanguage = CN // 默认为中文 / Default to Chinese @@ -103,13 +120,13 @@ var ( // Error implementation for AppError func (e *AppError) Error() string { - if e.Path != "" { - return fmt.Sprintf("%s: %v [Path: %s]", e.Op, e.Err, e.Path) + if e.Context != nil { + return fmt.Sprintf("[%s] %s: %v (context: %v)", e.Type, e.Op, e.Err, e.Context) } - return fmt.Sprintf("%s: %v", e.Op, e.Err) + return fmt.Sprintf("[%s] %s: %v", e.Type, e.Op, e.Err) } -// NewStorageConfig 创建新的配置实例 / Creates a new configuration instance +// NewStorageConfig 创建新的实例 / Creates a new configuration instance func NewStorageConfig() *StorageConfig { return &StorageConfig{ TelemetryMacMachineId: generateMachineId(), @@ -120,7 +137,7 @@ func NewStorageConfig() *StorageConfig { } } -// 生成类似原始machineId的字符串(64位小写十六进制) / Generate a string similar to the original machineId (64-bit lowercase hex) +// 生成类似原始machineId的字符串(64位小十六进制) / Generate a string similar to the original machineId (64-bit lowercase hex) func generateMachineId() string { data := make([]byte, 32) if _, err := rand.Read(data); err != nil { @@ -168,6 +185,11 @@ func (s *ProgressSpinner) Stop() { fmt.Println() } +// Start starts the spinner animation +func (s *ProgressSpinner) Start() { + s.current = 0 +} + // File and system operations func getConfigPath() (string, error) { @@ -196,17 +218,32 @@ func getConfigPath() (string, error) { func safeWriteFile(path string, data []byte, perm os.FileMode) error { dir := filepath.Dir(path) if err := os.MkdirAll(dir, 0755); err != nil { - return &AppError{"create directory", dir, err} + return &AppError{ + Type: ErrSystem, + Op: "create directory", + Path: dir, + Err: err, + } } tmpPath := path + ".tmp" if err := os.WriteFile(tmpPath, data, perm); err != nil { - return &AppError{"write temporary file", tmpPath, err} + return &AppError{ + Type: ErrSystem, + Op: "write temporary file", + Path: tmpPath, + Err: err, + } } if err := os.Rename(tmpPath, path); err != nil { os.Remove(tmpPath) - return &AppError{"rename file", path, err} + return &AppError{ + Type: ErrSystem, + Op: "rename file", + Path: path, + Err: err, + } } return nil @@ -218,22 +255,34 @@ func setFilePermissions(filePath string) error { // Process management functions -func killCursorProcesses() error { - if runtime.GOOS == "windows" { - // First try graceful shutdown - exec.Command("taskkill", "/IM", "Cursor.exe").Run() - exec.Command("taskkill", "/IM", "cursor.exe").Run() +type ProcessManager struct { + config *SystemConfig +} - time.Sleep(time.Second) +func (pm *ProcessManager) killCursorProcesses() error { + ctx, cancel := context.WithTimeout(context.Background(), pm.config.Timeout) + defer cancel() - // Force kill any remaining instances - exec.Command("taskkill", "/F", "/IM", "Cursor.exe").Run() - exec.Command("taskkill", "/F", "/IM", "cursor.exe").Run() - } else { - exec.Command("pkill", "-f", "Cursor").Run() - exec.Command("pkill", "-f", "cursor").Run() + for attempt := 0; attempt < pm.config.RetryAttempts; attempt++ { + if err := pm.killProcess(ctx); err != nil { + time.Sleep(pm.config.RetryDelay) + continue + } + return nil } - return nil + + return &AppError{ + Type: ErrProcess, + Op: "kill_processes", + Err: errors.New("failed to kill all Cursor processes after retries"), + } +} + +func (pm *ProcessManager) killProcess(ctx context.Context) error { + if runtime.GOOS == "windows" { + return pm.killWindowsProcess(ctx) + } + return pm.killUnixProcess(ctx) } func checkCursorRunning() bool { @@ -278,11 +327,11 @@ func printCyberpunkBanner() { banner := ` ██████╗██╗ ██╗██████╗ ███████╗ ██████╗ ██████╗ - ██╔════╝██║ ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗ + ██╔════╝██║ ██║██╔══██╗██╔════╝█╔═══██╗██╔══██╗ ██║ ██║ ██║██████╔╝███████╗██║ ██║██████╔╝ - ██║ ██║ ██║██╔══██╗╚════██║██║ ██║██╔══██╗ + ██║ ██║ ██║██╔══██╗╚════██ ██║ ██║██╔══██╗ ╚██████╗╚██████╔╝██║ ██║███████║╚██████╔╝██║ ██║ - ╚════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═╝ ╚═╝ + ╚════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ╚════╝ ╚═╝ ╚═╝ ` cyan.Println(banner) yellow.Println("\t\t>> Cursor ID Modifier v1.0 <<") @@ -350,11 +399,21 @@ func saveConfig(config *StorageConfig) error { content, err := json.MarshalIndent(config, "", " ") if err != nil { - return &AppError{"generate JSON", "", err} + return &AppError{ + Type: ErrSystem, + Op: "generate JSON", + Path: "", + Err: err, + } } if err := os.Chmod(configPath, 0666); err != nil && !os.IsNotExist(err) { - return &AppError{"modify file permissions", configPath, err} + return &AppError{ + Type: ErrSystem, + Op: "modify file permissions", + Path: configPath, + Err: err, + } } if err := safeWriteFile(configPath, content, 0666); err != nil { @@ -386,18 +445,23 @@ func readExistingConfig() (*StorageConfig, error) { return &config, nil } -func loadAndUpdateConfig() (*StorageConfig, error) { +func loadAndUpdateConfig(ui *UI) (*StorageConfig, error) { configPath, err := getConfigPath() if err != nil { return nil, err } text := texts[currentLanguage] - showProgress(text.ReadingConfig) + ui.showProgress(text.ReadingConfig) _, err = os.ReadFile(configPath) if err != nil && !os.IsNotExist(err) { - return nil, &AppError{"read config file", configPath, err} + return nil, &AppError{ + Type: ErrSystem, + Op: "read config file", + Path: configPath, + Err: err, + } } showProgress(text.GeneratingIds) @@ -409,49 +473,26 @@ func loadAndUpdateConfig() (*StorageConfig, error) { func checkAdminPrivileges() (bool, error) { switch runtime.GOOS { case "windows": - cmd := exec.Command("net", "session") - err := cmd.Run() - return err == nil, nil - + cmd := exec.Command("whoami", "/groups") + output, err := cmd.Output() + if err != nil { + return false, err + } + return strings.Contains(string(output), "S-1-16-12288") || + strings.Contains(string(output), "S-1-5-32-544"), nil + case "darwin", "linux": currentUser, err := user.Current() if err != nil { return false, fmt.Errorf("failed to get current user: %v", err) } return currentUser.Uid == "0", nil - + default: return false, fmt.Errorf("unsupported operating system: %s", runtime.GOOS) } } -func selfElevate() error { - verb := "runas" - exe, err := os.Executable() - if err != nil { - return err - } - - cwd, err := os.Getwd() - if err != nil { - return err - } - // 将字符串转换为UTF-16指针 - verbPtr, _ := windows.UTF16PtrFromString(verb) - exePtr, _ := windows.UTF16PtrFromString(exe) - cwdPtr, _ := windows.UTF16PtrFromString(cwd) - argPtr, _ := windows.UTF16PtrFromString("") - - var showCmd int32 = 1 //SW_NORMAL - - err = windows.ShellExecute(0, verbPtr, exePtr, argPtr, cwdPtr, showCmd) - if err != nil { - return err - } - os.Exit(0) - return nil -} - // Utility functions func detectLanguage() Language { @@ -472,31 +513,57 @@ func waitExit() { bufio.NewReader(os.Stdin).ReadString('\n') } -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 handleError(err error) { + if err == nil { + return + } + + logger := log.New(os.Stderr, "", log.LstdFlags) + + switch e := err.(type) { + case *AppError: + logger.Printf("[ERROR] %v\n", e) + if e.Type == ErrPermission { + showPrivilegeError() + } + default: + logger.Printf("[ERROR] Unexpected error: %v\n", err) } } // Main program entry func main() { + // 初始化错误恢复 defer func() { if r := recover(); r != nil { - color.Red(texts[currentLanguage].ErrorPrefix, r) - fmt.Println("\nAn error occurred! / 发生错误!") + log.Printf("Panic recovered: %v\n", r) + debug.PrintStack() waitExit() } }() + // 始化配置 + config := initConfig() + + // 初始化组件 + ui := NewUI(&config.UI) + pm := &ProcessManager{ + config: &SystemConfig{ + RetryAttempts: 3, + RetryDelay: time.Second, + Timeout: 30 * time.Second, + }, + } + + // 权限检查 os.Stdout.Sync() currentLanguage = detectLanguage() isAdmin, err := checkAdminPrivileges() if err != nil { - handleError("permission check failed", err) + handleError(err) waitExit() return } @@ -504,7 +571,7 @@ func main() { if !isAdmin && runtime.GOOS == "windows" { fmt.Println("Requesting administrator privileges... / 请求管理员权限...") if err := selfElevate(); err != nil { - handleError("failed to elevate privileges", err) + handleError(err) showPrivilegeError() waitExit() return @@ -518,7 +585,7 @@ func main() { if checkCursorRunning() { fmt.Println("\nDetected running Cursor instance(s). Closing... / 检测到正在运行的 Cursor 实例,正在关闭...") - if err := killCursorProcesses(); err != nil { + if err := pm.killCursorProcesses(); err != nil { fmt.Println("Warning: Could not close all Cursor instances. Please close them manually. / 警告:无法关闭所有 Cursor 实例,请手动关闭。") waitExit() return @@ -540,17 +607,17 @@ func main() { oldConfig = nil } - config, err := loadAndUpdateConfig() + storageConfig, err := loadAndUpdateConfig(ui) if err != nil { - handleError("configuration update failed", err) + handleError(err) waitExit() return } - showIdComparison(oldConfig, config) + showIdComparison(oldConfig, storageConfig) - if err := saveConfig(config); err != nil { - handleError("failed to save configuration", err) + if err := saveConfig(storageConfig); err != nil { + handleError(err) waitExit() return } @@ -559,3 +626,118 @@ func main() { fmt.Println("\nOperation completed! / 操作完成!") waitExit() } + +// 优化配置结构 +type Config struct { + Storage StorageConfig + UI UIConfig + System SystemConfig +} + +type UIConfig struct { + Language Language + Theme string + Spinner SpinnerConfig +} + +type SystemConfig struct { + RetryAttempts int + RetryDelay time.Duration + Timeout time.Duration +} + +// 配置初始化函数 +func initConfig() *Config { + return &Config{ + Storage: StorageConfig{ + Version: Version, + }, + UI: UIConfig{ + Language: detectLanguage(), + Theme: "default", + Spinner: SpinnerConfig{ + Frames: []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"}, + Delay: 100 * time.Millisecond, + }, + }, + System: SystemConfig{ + RetryAttempts: 3, + RetryDelay: time.Second, + Timeout: 30 * time.Second, + }, + } +} + +// UI 组件���化 +type UI struct { + config *UIConfig + spinner *ProgressSpinner +} + +func NewUI(config *UIConfig) *UI { + return &UI{ + config: config, + spinner: NewProgressSpinner(""), + } +} + +func (ui *UI) showProgress(message string) { + ui.spinner.message = message + ui.spinner.Start() + defer ui.spinner.Stop() + + ticker := time.NewTicker(ui.config.Spinner.Delay) + defer ticker.Stop() + + for i := 0; i < 15; i++ { + <-ticker.C + ui.spinner.Spin() + } +} + +func (pm *ProcessManager) killWindowsProcess(ctx context.Context) error { + // 使用 taskkill 命令结束进程 + exec.CommandContext(ctx, "taskkill", "/IM", "Cursor.exe").Run() + time.Sleep(pm.config.RetryDelay) + exec.CommandContext(ctx, "taskkill", "/F", "/IM", "Cursor.exe").Run() + return nil +} + +func (pm *ProcessManager) killUnixProcess(ctx context.Context) error { + exec.CommandContext(ctx, "pkill", "-f", "Cursor").Run() + exec.CommandContext(ctx, "pkill", "-f", "cursor").Run() + return nil +} + +func selfElevate() error { + switch runtime.GOOS { + case "windows": + // 使用 cmd 实现 Windows 下的提权 + verb := "runas" + exe, _ := os.Executable() + cwd, _ := os.Getwd() + args := strings.Join(os.Args[1:], " ") + + cmd := exec.Command("cmd", "/C", "start", verb, exe, args) + cmd.Dir = cwd + return cmd.Run() + + case "darwin", "linux": + // Unix 系统使用 sudo + exe, err := os.Executable() + if err != nil { + return err + } + + cmd := exec.Command("sudo", append([]string{exe}, os.Args[1:]...)...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() + + default: + return fmt.Errorf("unsupported operating system: %s", runtime.GOOS) + } +} + + diff --git a/scripts/build_all.bat b/scripts/build_all.bat index d0a6a5f..79ca60c 100644 --- a/scripts/build_all.bat +++ b/scripts/build_all.bat @@ -15,15 +15,6 @@ set "LDFLAGS=-s -w" set "BUILDMODE=pie" set "GCFLAGS=-N -l" -:: 检查是否安装了必要的交叉编译工具 -where gcc >nul 2>nul -if %errorlevel% neq 0 ( - echo %RED%错误: 未找到 gcc,这可能会影响 Mac 系统的交叉编译%RESET% - echo %YELLOW%请安装 MinGW-w64 或其他 gcc 工具链%RESET% - pause - exit /b 1 -) - :: 设置 CGO set CGO_ENABLED=0 @@ -32,31 +23,38 @@ 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" +:: 清理旧的构建文件 +echo %YELLOW%清理旧的构建文件...%RESET% +if exist "..\bin" ( + rd /s /q "..\bin" + echo %GREEN%清理完成%RESET% +) else ( + echo %YELLOW%bin 目录不存在,无需清理%RESET% ) :: 创建输出目录 -if not exist "..\bin" mkdir "..\bin" 2>nul +mkdir "..\bin" 2>nul :: 定义目标平台数组 set platforms[0].os=windows set platforms[0].arch=amd64 set platforms[0].ext=.exe +set platforms[0].suffix= set platforms[1].os=darwin set platforms[1].arch=amd64 set platforms[1].ext= +set platforms[1].suffix=_intel set platforms[2].os=darwin set platforms[2].arch=arm64 set platforms[2].ext= +set platforms[2].suffix=_m1 set platforms[3].os=linux set platforms[3].arch=amd64 set platforms[3].ext= +set platforms[3].suffix= :: 设置开始时间 set start_time=%time% @@ -68,6 +66,7 @@ for /L %%i in (0,1,3) do ( set "os=!platforms[%%i].os!" set "arch=!platforms[%%i].arch!" set "ext=!platforms[%%i].ext!" + set "suffix=!platforms[%%i].suffix!" echo. echo Building for !os! !arch!... @@ -75,38 +74,22 @@ for /L %%i in (0,1,3) do ( 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!" - ) + :: 构建输出文件名 + set "outfile=..\bin\cursor_id_modifier_v%VERSION%_!os!_!arch!!suffix!!ext!" - go build -trimpath !extra_flags! -buildmode=%BUILDMODE% -ldflags="%LDFLAGS%" -gcflags="%GCFLAGS%" -o "!outfile!" ..\main.go + :: 执行构建 + go build -trimpath -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) +set /a duration = %end_time:~0,2% * 3600 + %end_time:~3,2% * 60 + %end_time:~6,2% - (%start_time:~0,2% * 3600 + %start_time:~3,2% * 60 + %start_time:~6,2%) echo. echo %GREEN%所有构建完成! 总耗时: %duration% 秒%RESET%