Description
Go 1.11 added os.UserCacheDir
in #22536, and 1.12 is adding os.UserHomeDir
in #26463. This is great, and it covers plenty of common use cases.
UserCacheDir
is particularly interesting, as its behavior changes greatly between platforms. For example, on Unix-y systems it tries $XDG_CACHE_HOME
and falls back to $HOME/.cache
, and on Windows it uses %LocalAppData%
.
With those two functions, I believe there's only one piece missing; a configuration directory. Too many applications write "dot files" under the user's home directory, and that's bad practice. Some others hard-code $HOME/.config
, which is only marginally better as it doesn't do the right thing on Windows/Mac.
Relying on XDG base directory vars like $XDG_CONFIG_HOME
is no good either, as those don't exist on most systems.
We're only left with third-party libraries like https://github.com/shibukawa/configdir, which are moderately popular. In practice, popular software tends to write their own implementations. Below are some examples:
- https://github.com/uber-archive/gg/blob/77ecd52e4c4234a760ab90f3d977912ce6fae7d2/internal/gg/driver.go#L82
- https://github.com/peco/peco/blob/9542898d4c12b61cb2773a35193f7048bc3de154/config.go#L175
- https://github.com/helm/helm/pull/5166/files
- https://github.com/xetys/hetzner-kube/blob/0c180caa561414088872a9e33d2bad3c77aca760/cmd/root.go#L71
- Move .dockercfg to $XDG_CONFIG_HOME (a.k.a. ~/.config) moby/moby#20693
- Use xdg basedir spec on linux hashicorp/terraform#15389
- XDG Base Directory Specification rackspace/rack#338
- https://github.com/keybase/client/blob/b01c1c7aec87fe33fd1c332dcb24e00e1bde0a67/go/libkb/home.go#L81
I propose adding func UserConfigDir() (string, error)
, which would return:
$XDG_CONFIG_HOME
or$HOME/.config
on Unix-y systems%APPDATA%
on Windows, which is described as "Contains the full path to the Application Data directory of the logged-in user" (unlike%LOCALAPPDATA%
, it's not for temporary files)$HOME/Library/Preferences
on Mac
I don't know about plan9, but given that the cache dir is $home/lib/cache
, perhaps $home/lib/config
would work.
Please note that I'm not suggesting adding support for XDG base directories into the os
package. Most notably, adding UserConfigDir
might lead to some users requesting UserDataDir
. However, I can think of multiple reasons why they're not equally important:
- Mac and Windows don't obey XDG, so they only have one persistent per-user directory
- Even on Linux, most apps store all their data in their config dir. For example: Chromium, Libreoffice, GIMP, and gcloud all seem to ignore
XDG_DATA_HOME
- Most programs only need one persistent per-user directory, and it's often for config files; see the links above for examples
The only disadvantage I see with adding this API is that one could say we'd be encouraging users to store data files into XDG_CONFIG_HOME
instead of XDG_DATA_HOME
on XDG systems. However, those few programs that wish to differentiate their data directory from their config directory could simply do:
func userDataDir() (string, error)
if dir := os.Getenv("XDG_DATA_HOME"); dir != "" {
return dir, nil
}
// fall back to something sane on all platforms
return os.UserConfigDir()
}
/cc @kolyshkin @bradfitz @rsc @ianlancetaylor @stapelberg @robpike