package appdata import ( "os" "os/user" "path/filepath" "runtime" "strings" "unicode" ) // GetDataDir returns an operating system specific directory to be used for // storing application data for an application. // See Dir for more details. This unexported version takes an operating system argument primarily to enable the testing // package to properly test the function by forcing an operating system that is not the currently one. func GetDataDir(goos, appName string, roaming bool) string { if appName == "" || appName == "." { return "." } // The caller really shouldn't prepend the appName with a period, but if they do, handle it gracefully by trimming // it. appName = strings.TrimPrefix(appName, ".") appNameUpper := string(unicode.ToUpper(rune(appName[0]))) + appName[1:] appNameLower := string(unicode.ToLower(rune(appName[0]))) + appName[1:] // Get the OS specific home directory via the Go standard lib. var homeDir string var usr *user.User var e error if usr, e = user.Current(); e == nil { homeDir = usr.HomeDir } // Fall back to standard HOME environment variable that works for most POSIX OSes if the directory from the Go // standard lib failed. if e != nil || homeDir == "" { homeDir = os.Getenv("HOME") } switch goos { // Attempt to use the LOCALAPPDATA or APPDATA environment variable on Windows. case "windows": // Windows XP and before didn't have a LOCALAPPDATA, so fallback to regular APPDATA when LOCALAPPDATA is not // set. appData := os.Getenv("LOCALAPPDATA") if roaming || appData == "" { appData = os.Getenv("APPDATA") } if appData != "" { return filepath.Join(appData, appNameUpper) } case "darwin": if homeDir != "" { return filepath.Join( homeDir, "Library", "Application Support", appNameUpper, ) } case "plan9": if homeDir != "" { return filepath.Join(homeDir, appNameLower) } default: if homeDir != "" { return filepath.Join(homeDir, "."+appNameLower) } } // Fall back to the current directory if all else fails. return "." } // Dir returns an operating system specific directory to be used for storing application data for an application. The // appName parameter is the name of the application the data directory is being requested for. This function will // prepend a period to the appName for POSIX style operating systems since that is standard practice. // // An empty appName or one with a single dot is treated as requesting the current directory so only "." will be // returned. Further, the first character of appName will be made lowercase for POSIX style operating systems and // uppercase for Mac and Windows since that is standard practice. // // The roaming parameter only applies to Windows where it specifies the roaming application data profile (%APPDATA%) // should be used instead of the local one (%LOCALAPPDATA%) that is used by default. Example results: // // dir := Dir("myapp", false) // // POSIX (Linux/BSD): ~/.myapp // Mac OS: $HOME/Library/Application Support/Myapp // Windows: %LOCALAPPDATA%\Myapp // Plan 9: $home/myapp func Dir(appName string, roaming bool) string { return GetDataDir(runtime.GOOS, appName, roaming) }