package spm import ( "fmt" "math/rand" "os" "path/filepath" "runtime" "sync" ) // global sync and variable for generated temp dir var ( tempDirOnce sync.Once tempDirPath string ) // global variables for install dir var ( installMu sync.Mutex installedDir string installEnvVar = "SPITFIRE_INSTALL_DIR" ) // GetTempDir generates or retrieves a unique temp dir. func GetTempDir() string { tempDirOnce.Do(func() { // Generate a unique temp dir name tempDirPath = filepath.Join(os.TempDir(), fmt.Sprintf("spm_temp_%d", rand.Intn(1000000))) // Ensure the dir exists if err := os.MkdirAll(tempDirPath, os.ModePerm); err != nil { fmt.Printf("[ERROR] Failed to create temp directory: %v\n", err) } else { fmt.Printf("[INFO] Using temp directory: %s\n", tempDirPath) } }) return tempDirPath } // GetDefaultInstallDir generates the default installation dir // based on the OS and environment, then also sets it via SetInstallDir. // // Please use GetInstallDir() instead of GetDefaultInstallDir() when interacting with spm. func GetDefaultInstallDir() (string, error) { var installDir string switch runtime.GOOS { case "windows": // Use C:\Program Files programFiles := os.Getenv("ProgramFiles") if programFiles == "" { return "", fmt.Errorf("unable to determine default install directory on Windows") } installDir = filepath.Join(programFiles, "Spitfire") case "darwin": // Use ~/Library/Application Support on macOS homeDir, err := os.UserHomeDir() if err != nil { return "", fmt.Errorf("unable to determine home directory on macOS: %w", err) } installDir = filepath.Join(homeDir, "Library", "Application Support", "Spitfire") case "linux": // Use ~/.local/share/Spitfire on Linux homeDir, err := os.UserHomeDir() if err != nil { return "", fmt.Errorf("unable to determine home directory on Linux: %w", err) } installDir = filepath.Join(homeDir, ".local", "share", "Spitfire") default: return "", fmt.Errorf("unsupported operating system: %s", runtime.GOOS) } // Also store it globally so future calls to GetInstallDir() return the same SetInstallDir(installDir) return installDir, nil } // SetDownloadFolder ensures customDir exists, returns it func SetDownloadFolder(customDir string) (string, error) { if err := os.MkdirAll(customDir, os.ModePerm); err != nil { return "", err } return customDir, nil } // SetInstallDir sets the global install dir variable and updates the persistent environment variable. func SetInstallDir(path string) error { installMu.Lock() defer installMu.Unlock() installedDir = path // Persist the environment variable on Windows if runtime.GOOS == "windows" { err := persistSystemEnvVar(installEnvVar, path) if err != nil { return err } } else { // For non-Windows platforms, just set it in the current process environment err := os.Setenv(installEnvVar, path) if err != nil { return err } } return nil } // GetInstallDir returns the currently set install dir if available. // Otherwise, it calls GetDefaultInstallDir() and sets that. func GetInstallDir() (string, error) { // If already set, return it if installedDir != "" { return installedDir, nil } // Check if it's stored in the system environment variable if envDir := os.Getenv(installEnvVar); envDir != "" { installedDir = envDir return installedDir, nil } // Compute and store the default dir if not already set defDir, err := GetDefaultInstallDir() if err != nil { return "", err } installedDir = defDir // Persist the default dir as an environment variable on Windows if runtime.GOOS == "windows" { _ = persistSystemEnvVar(installEnvVar, defDir) } else { _ = os.Setenv(installEnvVar, defDir) } return defDir, nil }