diff --git a/src/os/file.go b/src/os/file.go index e7dd214b7..254efb741 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -400,6 +400,108 @@ func UserHomeDir() (string, error) { return "", errors.New(enverr + " is not defined") } +// UserCacheDir returns the default root directory to use for user-specific +// cached data. Users should create their own application-specific subdirectory +// within this one and use that. +// +// On Unix systems, it returns $XDG_CACHE_HOME as specified by +// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if +// non-empty, else $HOME/.cache. +// On Darwin, it returns $HOME/Library/Caches. +// On Windows, it returns %LocalAppData%. +// On Plan 9, it returns $home/lib/cache. +// +// If the location cannot be determined (for example, $HOME is not defined), +// then it will return an error. +func UserCacheDir() (string, error) { + var dir string + + switch runtime.GOOS { + case "windows": + dir = Getenv("LocalAppData") + if dir == "" { + return "", errors.New("%LocalAppData% is not defined") + } + + case "darwin", "ios": + dir = Getenv("HOME") + if dir == "" { + return "", errors.New("$HOME is not defined") + } + dir += "/Library/Caches" + + case "plan9": + dir = Getenv("home") + if dir == "" { + return "", errors.New("$home is not defined") + } + dir += "/lib/cache" + + default: // Unix + dir = Getenv("XDG_CACHE_HOME") + if dir == "" { + dir = Getenv("HOME") + if dir == "" { + return "", errors.New("neither $XDG_CACHE_HOME nor $HOME are defined") + } + dir += "/.cache" + } + } + + return dir, nil +} + +// UserConfigDir returns the default root directory to use for user-specific +// configuration data. Users should create their own application-specific +// subdirectory within this one and use that. +// +// On Unix systems, it returns $XDG_CONFIG_HOME as specified by +// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if +// non-empty, else $HOME/.config. +// On Darwin, it returns $HOME/Library/Application Support. +// On Windows, it returns %AppData%. +// On Plan 9, it returns $home/lib. +// +// If the location cannot be determined (for example, $HOME is not defined), +// then it will return an error. +func UserConfigDir() (string, error) { + var dir string + + switch runtime.GOOS { + case "windows": + dir = Getenv("AppData") + if dir == "" { + return "", errors.New("%AppData% is not defined") + } + + case "darwin", "ios": + dir = Getenv("HOME") + if dir == "" { + return "", errors.New("$HOME is not defined") + } + dir += "/Library/Application Support" + + case "plan9": + dir = Getenv("home") + if dir == "" { + return "", errors.New("$home is not defined") + } + dir += "/lib" + + default: // Unix + dir = Getenv("XDG_CONFIG_HOME") + if dir == "" { + dir = Getenv("HOME") + if dir == "" { + return "", errors.New("neither $XDG_CONFIG_HOME nor $HOME are defined") + } + dir += "/.config" + } + } + + return dir, nil +} + type ( FileMode = fs.FileMode FileInfo = fs.FileInfo diff --git a/src/os/os_anyos_test.go b/src/os/os_anyos_test.go index 7b4b38377..66e7fca7c 100644 --- a/src/os/os_anyos_test.go +++ b/src/os/os_anyos_test.go @@ -270,6 +270,42 @@ func TestUserHomeDir(t *testing.T) { } } +func TestUserCacheDir(t *testing.T) { + dir, err := UserCacheDir() + if dir == "" && err == nil { + t.Fatal("UserCacheDir returned an empty string but no error") + } + if err != nil { + t.Logf("UserCacheDir failed: %v", err) + return + } + fi, err := Stat(dir) + if err != nil { + t.Fatal(err) + } + if !fi.IsDir() { + t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode()) + } +} + +func TestUserConfigDir(t *testing.T) { + dir, err := UserConfigDir() + if dir == "" && err == nil { + t.Fatal("UserConfigDir returned an empty string but no error") + } + if err != nil { + t.Logf("UserConfigDir failed: %v", err) + return + } + fi, err := Stat(dir) + if err != nil { + t.Fatal(err) + } + if !fi.IsDir() { + t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode()) + } +} + func TestDirFS(t *testing.T) { if runtime.GOOS == "windows" { t.Log("TODO: implement Readdir for Windows")