├── .github └── workflows │ ├── assign.yml │ ├── review.yml │ └── test.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── Makefile ├── README.md ├── cache.go ├── cache_darwin.go ├── cache_other.go ├── cache_win.go ├── cmd └── xdg-sample │ └── main.go ├── config.go ├── config_darwin.go ├── config_other.go ├── config_win.go ├── data.go ├── data_darwin.go ├── data_other.go ├── data_win.go ├── doc.go ├── go.mod ├── path_test.go ├── runtime.go ├── runtime_darwin.go ├── runtime_other.go ├── runtime_win.go ├── user.go ├── user_darwin.go ├── user_others.go ├── user_win.go ├── xdg.go └── xdg_win.go /.github/workflows/assign.yml: -------------------------------------------------------------------------------- 1 | name: Issue assignment 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | jobs: 8 | auto-assign: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 'Auto-assign issue' 12 | uses: pozil/auto-assign-issue@v1 13 | with: 14 | repo-token: ${{ secrets.GITHUB_TOKEN }} 15 | assignees: kyoh86 16 | -------------------------------------------------------------------------------- /.github/workflows/review.yml: -------------------------------------------------------------------------------- 1 | name: Review 2 | 3 | on: 4 | [pull_request] 5 | 6 | jobs: 7 | lint: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: reviewdog/action-golangci-lint@v1 12 | with: 13 | level: info 14 | github_token: ${{ secrets.GITHUB_TOKEN }} 15 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: '*' 6 | 7 | jobs: 8 | test: 9 | runs-on: ${{ matrix.os }}-latest 10 | strategy: 11 | matrix: 12 | os: [ubuntu, windows, macos] 13 | steps: 14 | - uses: actions/checkout@v2 15 | - uses: actions/setup-go@v2 16 | with: 17 | go-version: 1.15.x 18 | - name: get dependencies 19 | run: go get -v -t -d ./... 20 | 21 | - name: test race 22 | run: go test -v -race ./... 23 | 24 | lint-and-cover: 25 | runs-on: ubuntu-latest 26 | steps: 27 | - uses: actions/checkout@v2 28 | - uses: actions/setup-go@v2 29 | with: 30 | go-version: 1.15.x 31 | - name: get dependencies 32 | run: go get -v -t -d ./... 33 | - name: vendoring 34 | run: go mod vendor 35 | 36 | - name: golangci-lint 37 | uses: golangci/golangci-lint-action@v2 38 | with: 39 | # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. 40 | version: v1.32 41 | 42 | - name: take coverage 43 | run: go test -coverprofile=coverage.txt -covermode=count ./... 44 | - uses: codecov/codecov-action@v1.0.3 45 | with: 46 | token: ${{ secrets.CODECOV_TOKEN }} 47 | file: coverage.txt 48 | 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - unparam 4 | - exportloopref 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 kyoh86 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: gen lint test sample 2 | 3 | VERSION := `git vertag get` 4 | COMMIT := `git rev-parse HEAD` 5 | 6 | gen: 7 | go generate ./... 8 | 9 | lint: gen 10 | golangci-lint run 11 | 12 | test: lint 13 | go test -v --race ./... 14 | 15 | sample: 16 | go run -tags=sample ./cmd/xdg-sample/main.go 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # xdg 2 | 3 | DEPRECATED: we can use "os.UserXXXDir" instead of this package. 4 | 5 | Light weight helper functions in golang to get config, 6 | data, cache and some user directories according to 7 | the [XDG Base Directory](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) and XDG User Directory Specification. 8 | 9 | [![PkgGoDev](https://pkg.go.dev/badge/kyoh86/xdg)](https://pkg.go.dev/kyoh86/xdg) 10 | [![Go Report Card](https://goreportcard.com/badge/github.com/kyoh86/xdg)](https://goreportcard.com/report/github.com/kyoh86/xdg) 11 | [![Coverage Status](https://img.shields.io/codecov/c/github/kyoh86/xdg.svg)](https://codecov.io/gh/kyoh86/xdg) 12 | [![Release](https://github.com/kyoh86/xdg/workflows/Release/badge.svg)](https://github.com/kyoh86/xdg/releases) 13 | 14 | ## Install 15 | 16 | ```console 17 | $ go get github.com/kyoh86/xdg 18 | ``` 19 | 20 | ## Usage 21 | 22 | For example: 23 | 24 | ```go 25 | package main 26 | 27 | import ( 28 | "fmt" 29 | "os" 30 | "strings" 31 | 32 | "github.com/kyoh86/xdg" 33 | ) 34 | 35 | func main() { 36 | fmt.Println("ConfigHome() will get a user level configuration directory path: ", xdg.ConfigHome()) 37 | 38 | os.Setenv(xdg.ConfigHomeEnv, "/.config") 39 | fmt.Println("...And `XDG_CONFIG_HOME` envar will be supported: ", xdg.ConfigHome()) 40 | 41 | fmt.Println(strings.Repeat("-", 48)) 42 | 43 | fmt.Println("ConfigDirs() will get system level configuration directories: ", xdg.ConfigDirs()) 44 | 45 | os.Setenv(xdg.ConfigDirsEnv, "/.config:/.config2") 46 | fmt.Println("...And `XDG_CONFIG_DIRS` envar will be able to change it:", xdg.ConfigDirs()) 47 | 48 | fmt.Println(strings.Repeat("-", 48)) 49 | 50 | fmt.Println("DataHome() will get a user level data directory path: ", xdg.DataHome()) 51 | 52 | os.Setenv(xdg.DataHomeEnv, "/.data") 53 | fmt.Println("...And `XDG_DATA_HOME` envar will be supported: ", xdg.DataHome()) 54 | 55 | fmt.Println(strings.Repeat("-", 48)) 56 | 57 | fmt.Println("DataDirs() will get system level data directories: ", xdg.DataDirs()) 58 | 59 | os.Setenv(xdg.DataDirsEnv, "/.data:/.data2") 60 | fmt.Println("...And `XDG_DATA_DIRS` envar will be able to change it:", xdg.DataDirs()) 61 | 62 | fmt.Println(strings.Repeat("-", 48)) 63 | 64 | fmt.Println("CacheHome() will get a cache directory path: ", xdg.CacheHome()) 65 | 66 | os.Setenv(xdg.CacheHomeEnv, "/.cache") 67 | fmt.Println("...And `XDG_CACHE_HOME` envar will be supported: ", xdg.CacheHome()) 68 | 69 | fmt.Println(strings.Repeat("-", 48)) 70 | 71 | fmt.Println("RuntimeDir() will get a runtime directory path: ", xdg.RuntimeDir()) 72 | 73 | os.Setenv(xdg.RuntimeDirEnv, "/.runtime") 74 | fmt.Println("...And `XDG_RUNTIME_DIR` envar will be supported: ", xdg.RuntimeDir()) 75 | 76 | fmt.Println(strings.Repeat("-", 48)) 77 | 78 | fmt.Println("DesktopDir() will get a desktop directory path: ", xdg.DesktopDir()) 79 | os.Setenv(xdg.DesktopDirEnv, "/.Desktop") 80 | fmt.Println("...And `XDG_DESKTOP_DIR` envar will be supported: ", xdg.DesktopDir()) 81 | 82 | fmt.Println("DownloadDir() will get a download directory path: ", xdg.DownloadDir()) 83 | os.Setenv(xdg.DownloadDirEnv, "/.Download ") 84 | fmt.Println("...And `XDG_Download _DIR` envar will be supported: ", xdg.DownloadDir()) 85 | 86 | fmt.Println("DocumentsDir() will get a documents directory path: ", xdg.DocumentsDir()) 87 | os.Setenv(xdg.DocumentsDirEnv, "/.Documents ") 88 | fmt.Println("...And `XDG_Documents _DIR` envar will be supported: ", xdg.DocumentsDir()) 89 | 90 | fmt.Println("MusicDir() will get a music directory path: ", xdg.MusicDir()) 91 | os.Setenv(xdg.MusicDirEnv, "/.Music ") 92 | fmt.Println("...And `XDG_Music _DIR` envar will be supported: ", xdg.MusicDir()) 93 | 94 | fmt.Println("PicturesDir() will get a pictures directory path: ", xdg.PicturesDir()) 95 | os.Setenv(xdg.PicturesDirEnv, "/.Pictures ") 96 | fmt.Println("...And `XDG_Pictures _DIR` envar will be supported: ", xdg.PicturesDir()) 97 | 98 | fmt.Println("VideosDir() will get a videos directory path: ", xdg.VideosDir()) 99 | os.Setenv(xdg.VideosDirEnv, "/.Videos ") 100 | fmt.Println("...And `XDG_Videos _DIR` envar will be supported: ", xdg.VideosDir()) 101 | 102 | fmt.Println("TemplatesDir() will get a templates directory path: ", xdg.TemplatesDir()) 103 | os.Setenv(xdg.TemplatesDirEnv, "/.Templates ") 104 | fmt.Println("...And `XDG_Templates _DIR` envar will be supported: ", xdg.TemplatesDir()) 105 | 106 | fmt.Println("PublicShareDir() will get a public share directory path: ", xdg.PublicShareDir()) 107 | os.Setenv(xdg.PublicShareDirEnv, "/.PublicShare ") 108 | fmt.Println("...And `XDG_PublicShare_DIR` envar will be supported: ", xdg.PublicShareDir()) 109 | } 110 | ``` 111 | 112 | And you can run sample easily. 113 | 114 | ```console 115 | $ make sample 116 | go run -tags=sample ./cmd/xdg-sample/main.go 117 | ConfigHome() will get a user level configuration directory path: /home/kyoh86/.config/ 118 | ...And `XDG_CONFIG_HOME` envar will be supported: /.config 119 | ------------------------------------------------ 120 | ConfigDirs() will get system level configuration directories: [/etc/xdg] 121 | ...And `XDG_CONFIG_DIRS` envar will be able to change it: [/.config /.config2] 122 | ------------------------------------------------ 123 | DataHome() will get a user level data directory path: /home/kyoh86/.local/share 124 | ...And `XDG_DATA_HOME` envar will be supported: /.data 125 | ------------------------------------------------ 126 | DataDirs() will get system level data directories: [/usr/local/share /usr/share] 127 | ...And `XDG_DATA_DIRS` envar will be able to change it: [/.data /.data2] 128 | ------------------------------------------------ 129 | CacheHome() will get a cache directory path: /home/kyoh86/.cache 130 | ...And `XDG_CACHE_HOME` envar will be supported: /.cache 131 | ------------------------------------------------ 132 | RuntimeDir() will get a runtime directory path: /run/user/1000 133 | ...And `XDG_RUNTIME_DIR` envar will be supported: /.runtime 134 | ------------------------------------------------ 135 | DesktopDir() will get a desktop directory path: /home/kyoh86/Desktop 136 | ...And `XDG_DESKTOP_DIR` envar will be supported: /.Desktop 137 | DownloadDir() will get a download directory path: /home/kyoh86/Downloads 138 | ...And `XDG_Download _DIR` envar will be supported: /.Download 139 | DocumentsDir() will get a documents directory path: /home/kyoh86/Documents 140 | ...And `XDG_Documents _DIR` envar will be supported: /.Documents 141 | MusicDir() will get a music directory path: /home/kyoh86/Music 142 | ...And `XDG_Music _DIR` envar will be supported: /.Music 143 | PicturesDir() will get a pictures directory path: /home/kyoh86/Pictures 144 | ...And `XDG_Pictures _DIR` envar will be supported: /.Pictures 145 | VideosDir() will get a videos directory path: /home/kyoh86/Videos 146 | ...And `XDG_Videos _DIR` envar will be supported: /.Videos 147 | TemplatesDir() will get a templates directory path: /home/kyoh86/Templates 148 | ...And `XDG_Templates _DIR` envar will be supported: /.Templates 149 | PublicShareDir() will get a public share directory path: /home/kyoh86/Public 150 | ...And `XDG_PublicShare_DIR` envar will be supported: /.PublicShare 151 | ``` 152 | 153 | ## Default path 154 | 155 | The package defines defaults for XDG directories. 156 | 157 | #### XDG Base Directory 158 | 159 | | XDG Variable | Mac OS | Windows | Others | 160 | | :--- | :----- | :--- | :--- | 161 | | XDG_CONFIG_HOME | `~/Library/Preferences` | `%LOCALAPPDATA%` | `~/.config` | 162 | | XDG_CONFIG_DIRS | `/Library/Preferences` | `%PROGRAMDATA%` | `/etc/xdg` | 163 | | XDG_DATA_HOME | `~/Library/Application Support` | `%LOCALAPPDATA%` | `~/.local/share` | 164 | | XDG_DATA_DIRS | `/Library/Application Support` | `%APPDATA%\Roaming`, `%PROGRAMDATA%` | `/usr/local/share`, `/usr/share` | 165 | | XDG_CACHE_HOME | `~/Library/Caches` | `%LOCALAPPDATA%\cache` | `~/.cache` | 166 | | XDG_RUNTIME_DIR | `~/Library/Application Support` | `%LOCALAPPDATA%` | `/run/user/UID` | 167 | 168 | #### XDG User Directory 169 | 170 | | XDG Variable | Mac OS | Windows | Others | 171 | | :--- | :----- | :--- | :--- | 172 | | XDG_DESKTOP_DIR | `~/Desktop` | `%USERPROFILE%/Desktop` | `~/Desktop` | 173 | | XDG_DOWNLOAD_DIR | `~/Downloads` | `%USERPROFILE%/Downloads` | `~/Downloads` | 174 | | XDG_DOCUMENTS_DIR | `~/Documents` | `%USERPROFILE%/Documents` | `~/Documents` | 175 | | XDG_PICTURES_DIR | `~/Pictures` | `%USERPROFILE%/Pictures` | `~/Pictures` | 176 | | XDG_MUSIC_DIR | `~/Music` | `%USERPROFILE%/Music` | `~/Music` | 177 | | XDG_VIDEOS_DIR | `~/Movies` | `%USERPROFILE%/Videos` | `~/Videos` | 178 | | XDG_TEMPLATES_DIR | `~/Templates` | `%USERPROFILE%/Templates` | `~/Templates` | 179 | | XDG_PUBLICSHARE_DIR | `~/Public` | `%PUBLIC%` | `~/Public` | 180 | 181 | # LICENSE 182 | 183 | [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg)](http://www.opensource.org/licenses/MIT) 184 | 185 | This is distributed under the [MIT License](http://www.opensource.org/licenses/MIT). 186 | -------------------------------------------------------------------------------- /cache.go: -------------------------------------------------------------------------------- 1 | package xdg 2 | 3 | const ( 4 | // CacheHomeEnv is the name of the environment variable holding a cache directory path. 5 | CacheHomeEnv = "XDG_CACHE_HOME" 6 | ) 7 | 8 | // FindCacheFile finds a file from the XDG data directory. 9 | // If one cannot be found, an error `ErrNotFound` be returned. 10 | func FindCacheFile(rel ...string) (string, error) { 11 | return findFile([]string{CacheHome()}, rel) 12 | } 13 | -------------------------------------------------------------------------------- /cache_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | ) 8 | 9 | // CacheHome returns a XDG cache directory (XDG_CACHE_HOME). 10 | func CacheHome() string { 11 | return altHome(os.Getenv(CacheHomeEnv), "Library", "Caches") 12 | } 13 | -------------------------------------------------------------------------------- /cache_other.go: -------------------------------------------------------------------------------- 1 | // +build !windows,!darwin 2 | 3 | package xdg 4 | 5 | import "os" 6 | 7 | // CacheHome returns a XDG cache directory (XDG_CACHE_HOME). 8 | func CacheHome() string { 9 | return altHome(os.Getenv(CacheHomeEnv), ".cache") 10 | } 11 | -------------------------------------------------------------------------------- /cache_win.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // CacheHome returns a XDG cache directory (XDG_CACHE_HOME). 11 | func CacheHome() string { 12 | return alternate(os.Getenv(CacheHomeEnv), filepath.Join(os.Getenv("LOCALAPPDATA"), "cache")) 13 | } 14 | -------------------------------------------------------------------------------- /cmd/xdg-sample/main.go: -------------------------------------------------------------------------------- 1 | // +build sample 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | "strings" 9 | 10 | "github.com/kyoh86/xdg" 11 | ) 12 | 13 | func main() { 14 | fmt.Println("ConfigHome() will get a user level configuration directory path: ", xdg.ConfigHome()) 15 | 16 | os.Setenv(xdg.ConfigHomeEnv, "/.config") 17 | fmt.Println("...And `XDG_CONFIG_HOME` envar will be supported: ", xdg.ConfigHome()) 18 | 19 | fmt.Println(strings.Repeat("-", 48)) 20 | 21 | fmt.Println("ConfigDirs() will get system level configuration directories: ", xdg.ConfigDirs()) 22 | 23 | os.Setenv(xdg.ConfigDirsEnv, "/.config:/.config2") 24 | fmt.Println("...And `XDG_CONFIG_DIRS` envar will be able to change it:", xdg.ConfigDirs()) 25 | 26 | fmt.Println(strings.Repeat("-", 48)) 27 | 28 | fmt.Println("DataHome() will get a user level data directory path: ", xdg.DataHome()) 29 | 30 | os.Setenv(xdg.DataHomeEnv, "/.data") 31 | fmt.Println("...And `XDG_DATA_HOME` envar will be supported: ", xdg.DataHome()) 32 | 33 | fmt.Println(strings.Repeat("-", 48)) 34 | 35 | fmt.Println("DataDirs() will get system level data directories: ", xdg.DataDirs()) 36 | 37 | os.Setenv(xdg.DataDirsEnv, "/.data:/.data2") 38 | fmt.Println("...And `XDG_DATA_DIRS` envar will be able to change it:", xdg.DataDirs()) 39 | 40 | fmt.Println(strings.Repeat("-", 48)) 41 | 42 | fmt.Println("CacheHome() will get a cache directory path: ", xdg.CacheHome()) 43 | 44 | os.Setenv(xdg.CacheHomeEnv, "/.cache") 45 | fmt.Println("...And `XDG_CACHE_HOME` envar will be supported: ", xdg.CacheHome()) 46 | 47 | fmt.Println(strings.Repeat("-", 48)) 48 | 49 | fmt.Println("RuntimeDir() will get a runtime directory path: ", xdg.RuntimeDir()) 50 | 51 | os.Setenv(xdg.RuntimeDirEnv, "/.runtime") 52 | fmt.Println("...And `XDG_RUNTIME_DIR` envar will be supported: ", xdg.RuntimeDir()) 53 | 54 | fmt.Println(strings.Repeat("-", 48)) 55 | 56 | fmt.Println("DesktopDir() will get a desktop directory path: ", xdg.DesktopDir()) 57 | os.Setenv(xdg.DesktopDirEnv, "/.Desktop") 58 | fmt.Println("...And `XDG_DESKTOP_DIR` envar will be supported: ", xdg.DesktopDir()) 59 | 60 | fmt.Println("DownloadDir() will get a download directory path: ", xdg.DownloadDir()) 61 | os.Setenv(xdg.DownloadDirEnv, "/.Download ") 62 | fmt.Println("...And `XDG_Download _DIR` envar will be supported: ", xdg.DownloadDir()) 63 | 64 | fmt.Println("DocumentsDir() will get a documents directory path: ", xdg.DocumentsDir()) 65 | os.Setenv(xdg.DocumentsDirEnv, "/.Documents ") 66 | fmt.Println("...And `XDG_Documents _DIR` envar will be supported: ", xdg.DocumentsDir()) 67 | 68 | fmt.Println("MusicDir() will get a music directory path: ", xdg.MusicDir()) 69 | os.Setenv(xdg.MusicDirEnv, "/.Music ") 70 | fmt.Println("...And `XDG_Music _DIR` envar will be supported: ", xdg.MusicDir()) 71 | 72 | fmt.Println("PicturesDir() will get a pictures directory path: ", xdg.PicturesDir()) 73 | os.Setenv(xdg.PicturesDirEnv, "/.Pictures ") 74 | fmt.Println("...And `XDG_Pictures _DIR` envar will be supported: ", xdg.PicturesDir()) 75 | 76 | fmt.Println("VideosDir() will get a videos directory path: ", xdg.VideosDir()) 77 | os.Setenv(xdg.VideosDirEnv, "/.Videos ") 78 | fmt.Println("...And `XDG_Videos _DIR` envar will be supported: ", xdg.VideosDir()) 79 | 80 | fmt.Println("TemplatesDir() will get a templates directory path: ", xdg.TemplatesDir()) 81 | os.Setenv(xdg.TemplatesDirEnv, "/.Templates ") 82 | fmt.Println("...And `XDG_Templates _DIR` envar will be supported: ", xdg.TemplatesDir()) 83 | 84 | fmt.Println("PublicShareDir() will get a public share directory path: ", xdg.PublicShareDir()) 85 | os.Setenv(xdg.PublicShareDirEnv, "/.PublicShare ") 86 | fmt.Println("...And `XDG_PublicShare_DIR` envar will be supported: ", xdg.PublicShareDir()) 87 | } 88 | -------------------------------------------------------------------------------- /config.go: -------------------------------------------------------------------------------- 1 | package xdg 2 | 3 | const ( 4 | // ConfigHomeEnv is the name of the environment variable holding a user configuration directory path. 5 | ConfigHomeEnv = "XDG_CONFIG_HOME" 6 | // ConfigDirsEnv is the name of the environment variable holding system configuration directory paths. 7 | ConfigDirsEnv = "XDG_CONFIG_DIRS" 8 | ) 9 | 10 | // AllConfigDirs returns all XDG configuration directories. 11 | func AllConfigDirs() []string { 12 | var dirs []string 13 | 14 | // XDG_CONFIG_HOME 15 | if home := ConfigHome(); home != "" { 16 | dirs = append(dirs, home) 17 | } 18 | 19 | // XDG_CONFIG_DIRS 20 | dirs = append(dirs, ConfigDirs()...) 21 | 22 | return dirs 23 | } 24 | 25 | // FindConfigFile finds a file from the XDG configuration directory. 26 | // If one cannot be found, an error `ErrNotFound` be returned. 27 | func FindConfigFile(rel ...string) (string, error) { 28 | return findFile(AllConfigDirs(), rel) 29 | } 30 | -------------------------------------------------------------------------------- /config_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // ConfigHome returns a user XDG configuration directory (XDG_CONFIG_HOME). 11 | func ConfigHome() string { 12 | return altHome(os.Getenv(ConfigHomeEnv), "Library", "Preferences") 13 | } 14 | 15 | // ConfigDirs returns system XDG data directories (XDG_CONFIG_DIRS). 16 | func ConfigDirs() []string { 17 | // XDG_CONFIG_DIRS 18 | xdgDirs := filepath.SplitList(os.Getenv(ConfigDirsEnv)) 19 | if len(xdgDirs) != 0 { 20 | return xdgDirs 21 | } 22 | return []string{ 23 | filepath.Join("/", "Library", "Preferences"), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /config_other.go: -------------------------------------------------------------------------------- 1 | // +build !windows,!darwin 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // ConfigHome returns a user XDG configuration directory (XDG_CONFIG_HOME). 11 | func ConfigHome() string { 12 | return altHome(os.Getenv(ConfigHomeEnv), ".config") 13 | } 14 | 15 | // ConfigDirs returns system XDG configuration directories (XDG_CONFIG_DIRS). 16 | func ConfigDirs() []string { 17 | // XDG_CONFIG_DIRS 18 | xdgDirs := filepath.SplitList(os.Getenv(ConfigDirsEnv)) 19 | if len(xdgDirs) != 0 { 20 | return xdgDirs 21 | } 22 | return []string{ 23 | filepath.Join("/", "etc", "xdg"), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /config_win.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // ConfigHome returns a user XDG configuration directory (XDG_CONFIG_HOME). 11 | func ConfigHome() string { 12 | return alternate(os.Getenv(ConfigHomeEnv), os.Getenv("LOCALAPPDATA")) 13 | } 14 | 15 | // ConfigDirs returns system XDG configuration directories (XDG_CONFIG_DIRS). 16 | func ConfigDirs() []string { 17 | // XDG_CONFIG_DIRS 18 | xdgDirs := filepath.SplitList(os.Getenv(ConfigDirsEnv)) 19 | if len(xdgDirs) != 0 { 20 | return xdgDirs 21 | } 22 | return []string{ 23 | os.Getenv("PROGRAMDATA"), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data.go: -------------------------------------------------------------------------------- 1 | package xdg 2 | 3 | const ( 4 | // DataHomeEnv is the name of the environment variable holding a user data directory path. 5 | DataHomeEnv = "XDG_DATA_HOME" 6 | // DataDirsEnv is the name of the environment variable holding system data directory paths. 7 | DataDirsEnv = "XDG_DATA_DIRS" 8 | ) 9 | 10 | // AllDataDirs returns all XDG data directories. 11 | func AllDataDirs() []string { 12 | var dirs []string 13 | 14 | // XDG_DATA_HOME 15 | if home := DataHome(); home != "" { 16 | dirs = append(dirs, home) 17 | } 18 | 19 | // XDG_DATA_DIRS 20 | dirs = append(dirs, DataDirs()...) 21 | 22 | return dirs 23 | } 24 | 25 | // FindDataFile finds a file from the XDG data directory. 26 | // If one cannot be found, an error `ErrNotFound` be returned. 27 | func FindDataFile(rel ...string) (string, error) { 28 | return findFile(AllDataDirs(), rel) 29 | } 30 | -------------------------------------------------------------------------------- /data_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // DataHome returns a user XDG data directory (XDG_DATA_HOME). 11 | func DataHome() string { 12 | return altHome(os.Getenv(DataHomeEnv), "Library", "Application Support") 13 | } 14 | 15 | // DataDirs returns system XDG data directories (XDG_DATA_DIRS). 16 | func DataDirs() []string { 17 | // XDG_DATA_DIRS 18 | xdgDirs := filepath.SplitList(os.Getenv(DataDirsEnv)) 19 | if len(xdgDirs) != 0 { 20 | return xdgDirs 21 | } 22 | return []string{ 23 | filepath.Join("/", "Library", "Application Support"), 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /data_other.go: -------------------------------------------------------------------------------- 1 | // +build !windows,!darwin 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // DataHome returns a user XDG data directory (XDG_DATA_HOME). 11 | func DataHome() string { 12 | return altHome(os.Getenv(DataHomeEnv), ".local", "share") 13 | } 14 | 15 | // DataDirs returns system XDG data directories (XDG_DATA_DIRS). 16 | func DataDirs() []string { 17 | // XDG_DATA_DIRS 18 | xdgDirs := filepath.SplitList(os.Getenv(DataDirsEnv)) 19 | if len(xdgDirs) != 0 { 20 | return xdgDirs 21 | } 22 | return []string{ 23 | filepath.Join("/", "usr", "local", "share"), 24 | filepath.Join("/", "usr", "share"), 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /data_win.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // DataHome returns a user XDG data directory (XDG_DATA_HOME). 11 | func DataHome() string { 12 | return alternate(os.Getenv(DataHomeEnv), os.Getenv("LOCALAPPDATA")) 13 | } 14 | 15 | // DataDirs returns system XDG data directories (XDG_DATA_DIRS). 16 | func DataDirs() []string { 17 | // XDG_DATA_DIRS 18 | xdgDirs := filepath.SplitList(os.Getenv(DataDirsEnv)) 19 | if len(xdgDirs) != 0 { 20 | return xdgDirs 21 | } 22 | return []string{ 23 | filepath.Join(os.Getenv("APPDATA"), "Roaming"), 24 | os.Getenv("PROGRAMDATA"), 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package xdg Light weight helper functions in golang to get config, data and cache files according to the XDG Base Directory Specification 3 | */ 4 | package xdg 5 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kyoh86/xdg 2 | 3 | go 1.12 4 | -------------------------------------------------------------------------------- /path_test.go: -------------------------------------------------------------------------------- 1 | package xdg 2 | 3 | import "testing" 4 | 5 | func TestPath(t *testing.T) { 6 | t.Log(CacheHome()) 7 | t.Log(DataHome()) 8 | t.Log(DataDirs()) 9 | t.Log(ConfigHome()) 10 | t.Log(ConfigDirs()) 11 | t.Log(RuntimeDir()) 12 | t.Log(DesktopDir()) 13 | t.Log(DownloadDir()) 14 | t.Log(DocumentsDir()) 15 | t.Log(MusicDir()) 16 | t.Log(PicturesDir()) 17 | t.Log(VideosDir()) 18 | t.Log(TemplatesDir()) 19 | t.Log(PublicShareDir()) 20 | } 21 | -------------------------------------------------------------------------------- /runtime.go: -------------------------------------------------------------------------------- 1 | package xdg 2 | 3 | const ( 4 | // RuntimeDirEnv is the name of the environment variable holding a runtime directory path. 5 | RuntimeDirEnv = "XDG_RUNTIME_DIR" 6 | ) 7 | 8 | // FindRuntimeFile finds a file from the XDG runtime directory. 9 | // If one cannot be found, an error `ErrNotFound` be returned. 10 | func FindRuntimeFile(rel ...string) (string, error) { 11 | return findFile([]string{RuntimeDir()}, rel) 12 | } 13 | -------------------------------------------------------------------------------- /runtime_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | ) 8 | 9 | // RuntimeDir returns XDG runtime directory. 10 | func RuntimeDir() string { 11 | // XDG_RUNTIME_DIR 12 | return altHome(os.Getenv(RuntimeDirEnv), "Library", "Application Support") 13 | } 14 | -------------------------------------------------------------------------------- /runtime_other.go: -------------------------------------------------------------------------------- 1 | // +build !windows,!darwin 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | "strconv" 9 | ) 10 | 11 | // RuntimeDir returns XDG runtime directory. 12 | func RuntimeDir() string { 13 | // XDG_RUNTIME_DIR 14 | return alternate( 15 | os.Getenv(RuntimeDirEnv), 16 | filepath.Join("/", "run", "user", strconv.Itoa(os.Getuid())), 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /runtime_win.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | ) 8 | 9 | // RuntimeDir returns XDG runtime directory. 10 | func RuntimeDir() string { 11 | // XDG_RUNTIME_DIR 12 | return alternate(os.Getenv(RuntimeDirEnv), os.Getenv("LOCALAPPDATA")) 13 | } 14 | -------------------------------------------------------------------------------- /user.go: -------------------------------------------------------------------------------- 1 | package xdg 2 | 3 | const ( 4 | // DesktopDirEnv is the name of the environment variable holding a user desktop directory path. 5 | DesktopDirEnv = "XDG_DESKTOP_DIR" 6 | // DownloadDirEnv is the name of the environment variable holding a user download directory path. 7 | DownloadDirEnv = "XDG_DOWNLOAD_DIR" 8 | // DocumentsDirEnv is the name of the environment variable holding a user documents directory path. 9 | DocumentsDirEnv = "XDG_DOCUMENTS_DIR" 10 | // MusicDirEnv is the name of the environment variable holding a user music directory path. 11 | MusicDirEnv = "XDG_MUSIC_DIR" 12 | // PicturesDirEnv is the name of the environment variable holding a user pictures directory path. 13 | PicturesDirEnv = "XDG_PICTURES_DIR" 14 | // VideosDirEnv is the name of the environment variable holding a user videos directory path. 15 | VideosDirEnv = "XDG_VIDEOS_DIR" 16 | // TemplatesDirEnv is the name of the environment variable holding a user templates directory path. 17 | TemplatesDirEnv = "XDG_TEMPLATES_DIR" 18 | // PublicShareDirEnv is the name of the environment variable holding a user public share directory path. 19 | PublicShareDirEnv = "XDG_PUBLICSHARE_DIR" 20 | ) 21 | -------------------------------------------------------------------------------- /user_darwin.go: -------------------------------------------------------------------------------- 1 | // +build darwin 2 | 3 | package xdg 4 | 5 | import "os" 6 | 7 | func DesktopDir() string { return altHome(os.Getenv(DesktopDirEnv), "Desktop") } 8 | func DownloadDir() string { return altHome(os.Getenv(DownloadDirEnv), "Downloads") } 9 | func DocumentsDir() string { return altHome(os.Getenv(DocumentsDirEnv), "Documents") } 10 | func MusicDir() string { return altHome(os.Getenv(MusicDirEnv), "Music") } 11 | func PicturesDir() string { return altHome(os.Getenv(PicturesDirEnv), "Pictures") } 12 | func VideosDir() string { return altHome(os.Getenv(VideosDirEnv), "Movies") } 13 | func TemplatesDir() string { return altHome(os.Getenv(TemplatesDirEnv), "Templates") } 14 | func PublicShareDir() string { return altHome(os.Getenv(PublicShareDirEnv), "Public") } 15 | -------------------------------------------------------------------------------- /user_others.go: -------------------------------------------------------------------------------- 1 | // +build !windows,!darwin 2 | 3 | package xdg 4 | 5 | import "os" 6 | 7 | func DesktopDir() string { return altHome(os.Getenv(DesktopDirEnv), "Desktop") } 8 | func DownloadDir() string { return altHome(os.Getenv(DownloadDirEnv), "Downloads") } 9 | func DocumentsDir() string { return altHome(os.Getenv(DocumentsDirEnv), "Documents") } 10 | func MusicDir() string { return altHome(os.Getenv(MusicDirEnv), "Music") } 11 | func PicturesDir() string { return altHome(os.Getenv(PicturesDirEnv), "Pictures") } 12 | func VideosDir() string { return altHome(os.Getenv(VideosDirEnv), "Videos") } 13 | func TemplatesDir() string { return altHome(os.Getenv(TemplatesDirEnv), "Templates") } 14 | func PublicShareDir() string { return altHome(os.Getenv(PublicShareDirEnv), "Public") } 15 | -------------------------------------------------------------------------------- /user_win.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package xdg 4 | 5 | import "os" 6 | 7 | func DesktopDir() string { return altUserProfile(os.Getenv(DesktopDirEnv), "Desktop") } 8 | func DownloadDir() string { return altUserProfile(os.Getenv(DownloadDirEnv), "Downloads") } 9 | func DocumentsDir() string { return altUserProfile(os.Getenv(DocumentsDirEnv), "Documents") } 10 | func MusicDir() string { return altUserProfile(os.Getenv(MusicDirEnv), "Music") } 11 | func PicturesDir() string { return altUserProfile(os.Getenv(PicturesDirEnv), "Pictures") } 12 | func VideosDir() string { return altUserProfile(os.Getenv(VideosDirEnv), "Videos") } 13 | func TemplatesDir() string { return altUserProfile(os.Getenv(TemplatesDirEnv), "Templates") } 14 | func PublicShareDir() string { return alternate(os.Getenv(PublicShareDirEnv), os.Getenv("PUBLIC")) } 15 | -------------------------------------------------------------------------------- /xdg.go: -------------------------------------------------------------------------------- 1 | package xdg 2 | 3 | import ( 4 | "errors" 5 | "os" 6 | "path/filepath" 7 | ) 8 | 9 | // ErrNotFound indicates that a file cannot be found in any directory. 10 | var ErrNotFound = errors.New("not found") 11 | 12 | func alternate(str, alt string) string { 13 | if str == "" { 14 | return alt 15 | } 16 | return str 17 | } 18 | 19 | func altHome(path string, suffix ...string) string { 20 | if path != "" { 21 | return path 22 | } 23 | home := os.Getenv("HOME") 24 | if home != "" { 25 | return filepath.Join(append([]string{home}, suffix...)...) 26 | } 27 | return "" 28 | } 29 | 30 | func findFile(paths []string, rel []string) (string, error) { 31 | for _, dir := range paths { 32 | if !filepath.IsAbs(dir) { 33 | // XDG Base Directory Specification supports only Absolute paths 34 | continue 35 | } 36 | 37 | fpath := filepath.Join(append([]string{dir}, rel...)...) 38 | if isFile(fpath) { 39 | return fpath, nil 40 | } 41 | } 42 | 43 | return "", ErrNotFound 44 | } 45 | 46 | func isFile(p string) bool { 47 | stat, err := os.Stat(p) 48 | return err == nil && !stat.IsDir() 49 | } 50 | -------------------------------------------------------------------------------- /xdg_win.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package xdg 4 | 5 | import ( 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | func altUserProfile(path string, suffix ...string) string { 11 | if path != "" { 12 | return path 13 | } 14 | home := os.Getenv("USERPROFILE") 15 | if home != "" { 16 | return filepath.Join(append([]string{home}, suffix...)...) 17 | } 18 | return "" 19 | } 20 | --------------------------------------------------------------------------------