Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for XDG_BIN_HOME #96

Merged
merged 5 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ Provides an implementation of the [XDG Base Directory Specification](https://spe
The specification defines a set of standard paths for storing application files,
including data and configuration files. For portability and flexibility reasons,
applications should use the XDG defined locations instead of hardcoding paths.
The package also includes the locations of well known [user directories](https://wiki.archlinux.org/index.php/XDG_user_directories), as well as
other common directories such as fonts and applications.

The package also includes the locations of well known [user directories](https://wiki.archlinux.org/index.php/XDG_user_directories),
support for the non-standard `XDG_BIN_HOME` directory, as well as other common directories such as fonts and applications.

The current implementation supports **most flavors of Unix**, **Windows**, **macOS** and **Plan 9**.
On Windows, where XDG environment variables are not usually set, the package uses [Known Folders](https://docs.microsoft.com/en-us/windows/win32/shell/known-folders)
Expand Down Expand Up @@ -79,6 +80,7 @@ Sensible fallback locations are used for the folders which are not set.
| <kbd><b>XDG_STATE_HOME</b></kbd> | <kbd>~/.local/state</kbd> | <kbd>~/Library/Application&nbsp;Support</kbd> | <kbd>$home/lib/state</kbd> |
| <kbd><b>XDG_CACHE_HOME</b></kbd> | <kbd>~/.cache</kbd> | <kbd>~/Library/Caches</kbd> | <kbd>$home/lib/cache</kbd> |
| <kbd><b>XDG_RUNTIME_DIR</b></kbd> | <kbd>/run/user/UID</kbd> | <kbd>~/Library/Application&nbsp;Support</kbd> | <kbd>/tmp</kbd> |
| <kbd><b>XDG_BIN_HOME</b></kbd> | <kbd>~/.local/bin</kbd> | <kbd>~/.local/bin</kbd> | <kbd>$home/bin</kbd> |

</details>

Expand All @@ -95,6 +97,7 @@ Sensible fallback locations are used for the folders which are not set.
| <kbd><b>XDG_STATE_HOME</b></kbd> | <kbd>LocalAppData</kbd> | <kbd>%LOCALAPPDATA%</kbd> |
| <kbd><b>XDG_CACHE_HOME</b></kbd> | <kbd>LocalAppData\cache</kbd> | <kbd>%LOCALAPPDATA%\cache</kbd> |
| <kbd><b>XDG_RUNTIME_DIR</b></kbd> | <kbd>LocalAppData</kbd> | <kbd>%LOCALAPPDATA%</kbd> |
| <kbd><b>XDG_BIN_HOME</b></kbd> | <kbd>UserProgramFiles</kbd> | <kbd>%LOCALAPPDATA%/Programs</kbd> |

</details>

Expand Down Expand Up @@ -163,11 +166,11 @@ as shown in the following tables.
<summary><strong>Microsoft Windows</strong></summary>
<br/>

| <a href="#other-directories"><img width="400" height="0"></a> | <a href="#other-directories"><img width="300" height="0"></a><p>Known&nbsp;Folder(s)</p> | <a href="#other-directories"><img width="1300" height="0"></a><p>Fallback(s)</p> |
| :-----------------------------------------------------------: | :--------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: |
| <kbd><b>Home</b></kbd> | <kbd>Profile</kbd> | <kbd>%USERPROFILE%</kbd> |
| <kbd><b>Applications</b></kbd> | <kbd>Programs</kbd><br/><kbd>CommonPrograms</kbd> | <kbd>%APPDATA%\Microsoft\Windows\Start&nbsp;Menu\Programs</kbd><br/><kbd>%ProgramData%\Microsoft\Windows\Start&nbsp;Menu\Programs</kbd> |
| <kbd><b>Fonts</b></kbd> | <kbd>Fonts</kbd> | <kbd>%SystemRoot%\Fonts</kbd><br/><kbd>%LOCALAPPDATA%\Microsoft\Windows\Fonts</kbd> |
| <a href="#other-directories"><img width="400" height="0"></a> | <a href="#other-directories"><img width="300" height="0"></a><p>Known&nbsp;Folder(s)</p> | <a href="#other-directories"><img width="1300" height="0"></a><p>Fallback(s)</p> |
| :-----------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
| <kbd><b>Home</b></kbd> | <kbd>Profile</kbd> | <kbd>%USERPROFILE%</kbd> |
| <kbd><b>Applications</b></kbd> | <kbd>Programs</kbd><br/><kbd>CommonPrograms</kbd> <br/><kbd>ProgramFiles</kbd><br/><kbd>ProgramFilesCommon</kbd><br/><kbd>UserProgramFiles</kbd><br/><kbd>UserProgramFilesCommon</kbd> | <kbd>%APPDATA%\Microsoft\Windows\Start&nbsp;Menu\Programs</kbd><br/><kbd>%ProgramData%\Microsoft\Windows\Start&nbsp;Menu\Programs</kbd><br/><kbd>%ProgramFiles%</kbd><br/><kbd>%ProgramFiles%\Common Files</kbd><br/><kbd>%LOCALAPPDATA%\Programs</kbd><br/><kbd>%LOCALAPPDATA%\Programs\Common</kbd>|
| <kbd><b>Fonts</b></kbd> | <kbd>Fonts</kbd> | <kbd>%SystemRoot%\Fonts</kbd><br/><kbd>%LOCALAPPDATA%\Microsoft\Windows\Fonts</kbd> |

</details>

Expand All @@ -193,6 +196,7 @@ func main() {
log.Println("Home state directory:", xdg.StateHome)
log.Println("Cache directory:", xdg.CacheHome)
log.Println("Runtime directory:", xdg.RuntimeDir)
log.Println("Home binaries directory:", xdg.BinHome)

// Other common directories.
log.Println("Home directory:", xdg.Home)
Expand Down
6 changes: 5 additions & 1 deletion base_dirs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ const (
envStateHome = "XDG_STATE_HOME"
envCacheHome = "XDG_CACHE_HOME"
envRuntimeDir = "XDG_RUNTIME_DIR"

// Non-standard.
envBinHome = "XDG_BIN_HOME"
)

type baseDirectories struct {
Expand All @@ -22,7 +25,8 @@ type baseDirectories struct {
cacheHome string
runtime string

// Non-standard directories.
// Non-standard.
binHome string
fonts []string
applications []string
}
Expand Down
5 changes: 4 additions & 1 deletion doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ The current implementation supports most flavors of Unix, Windows, Mac OS and Pl
For more information regarding the Windows Known Folders see:
https://docs.microsoft.com/en-us/windows/win32/shell/known-folders

Usage
# Usage

XDG Base Directory

package main

import (
Expand All @@ -36,6 +37,7 @@ XDG Base Directory
log.Println("Home state directory:", xdg.StateHome)
log.Println("Cache directory:", xdg.CacheHome)
log.Println("Runtime directory:", xdg.RuntimeDir)
log.Println("Home binaries directory:", xdg.BinHome)

// Other common directories.
log.Println("Home directory:", xdg.Home)
Expand Down Expand Up @@ -76,6 +78,7 @@ XDG Base Directory
}

XDG user directories

package main

import (
Expand Down
2 changes: 2 additions & 0 deletions paths_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ func initBaseDirs(home string) {
baseDirs.runtime = pathutil.EnvPath(envRuntimeDir, homeAppSupport)

// Initialize non-standard directories.
baseDirs.binHome = pathutil.EnvPath(envBinHome, filepath.Join(home, ".local", "bin"))

baseDirs.applications = []string{
"/Applications",
}
Expand Down
33 changes: 25 additions & 8 deletions paths_darwin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ func TestDefaultBaseDirs(t *testing.T) {
expected: homeAppSupport,
actual: &xdg.RuntimeDir,
},
&envSample{
name: "XDG_BIN_HOME",
expected: filepath.Join(home, ".local", "bin"),
actual: &xdg.BinHome,
},
&envSample{
name: "XDG_APPLICATION_DIRS",
expected: []string{
Expand Down Expand Up @@ -87,10 +92,13 @@ func TestCustomBaseDirs(t *testing.T) {
actual: &xdg.DataHome,
},
&envSample{
name: "XDG_DATA_DIRS",
value: "~/Library/data:/Library/Application Support",
expected: []string{filepath.Join(home, "Library/data"), "/Library/Application Support"},
actual: &xdg.DataDirs,
name: "XDG_DATA_DIRS",
value: "~/Library/data:/Library/Application Support",
expected: []string{
filepath.Join(home, "Library/data"),
"/Library/Application Support",
},
actual: &xdg.DataDirs,
},
&envSample{
name: "XDG_CONFIG_HOME",
Expand All @@ -99,10 +107,13 @@ func TestCustomBaseDirs(t *testing.T) {
actual: &xdg.ConfigHome,
},
&envSample{
name: "XDG_CONFIG_DIRS",
value: "~/Library/config:/Library/Preferences",
expected: []string{filepath.Join(home, "Library/config"), "/Library/Preferences"},
actual: &xdg.ConfigDirs,
name: "XDG_CONFIG_DIRS",
value: "~/Library/config:/Library/Preferences",
expected: []string{
filepath.Join(home, "Library/config"),
"/Library/Preferences",
},
actual: &xdg.ConfigDirs,
},
&envSample{
name: "XDG_STATE_HOME",
Expand All @@ -122,6 +133,12 @@ func TestCustomBaseDirs(t *testing.T) {
expected: filepath.Join(home, "Library/runtime"),
actual: &xdg.RuntimeDir,
},
&envSample{
name: "XDG_BIN_HOME",
value: "~/Library/bin",
expected: filepath.Join(home, "Library/bin"),
actual: &xdg.BinHome,
},
)
}

Expand Down
2 changes: 2 additions & 0 deletions paths_plan9.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ func initBaseDirs(home string) {
baseDirs.runtime = pathutil.EnvPath(envRuntimeDir, "/tmp")

// Initialize non-standard directories.
baseDirs.binHome = pathutil.EnvPath(envBinHome, filepath.Join(home, "bin"))

baseDirs.applications = []string{
filepath.Join(home, "bin"),
"/bin",
Expand Down
11 changes: 11 additions & 0 deletions paths_plan9_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ func TestDefaultBaseDirs(t *testing.T) {
expected: "/tmp",
actual: &xdg.RuntimeDir,
},
&envSample{
name: "XDG_BIN_HOME",
expected: filepath.Join(home, "bin"),
actual: &xdg.BinHome,
},
&envSample{
name: "XDG_APPLICATION_DIRS",
expected: []string{
Expand Down Expand Up @@ -115,6 +120,12 @@ func TestCustomBaseDirs(t *testing.T) {
expected: filepath.Join(homeLib, "runtime"),
actual: &xdg.RuntimeDir,
},
&envSample{
name: "XDG_BIN_HOME",
value: filepath.Join(homeLib, "bin"),
expected: filepath.Join(homeLib, "bin"),
actual: &xdg.BinHome,
},
)
}

Expand Down
2 changes: 2 additions & 0 deletions paths_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ func initBaseDirs(home string) {
baseDirs.runtime = pathutil.EnvPath(envRuntimeDir, filepath.Join("/run/user", strconv.Itoa(os.Getuid())))

// Initialize non-standard directories.
baseDirs.binHome = pathutil.EnvPath(envBinHome, filepath.Join(home, ".local", "bin"))

appDirs := []string{
filepath.Join(baseDirs.dataHome, "applications"),
filepath.Join(home, ".local/share/applications"),
Expand Down
33 changes: 25 additions & 8 deletions paths_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ func TestDefaultBaseDirs(t *testing.T) {
expected: filepath.Join("/run/user", strconv.Itoa(os.Getuid())),
actual: &xdg.RuntimeDir,
},
&envSample{
name: "XDG_BIN_HOME",
expected: filepath.Join(home, ".local", "bin"),
actual: &xdg.BinHome,
},
&envSample{
name: "XDG_APPLICATION_DIRS",
expected: []string{
Expand Down Expand Up @@ -85,10 +90,13 @@ func TestCustomBaseDirs(t *testing.T) {
actual: &xdg.DataHome,
},
&envSample{
name: "XDG_DATA_DIRS",
value: "~/.local/data:/usr/share",
expected: []string{filepath.Join(home, ".local/data"), "/usr/share"},
actual: &xdg.DataDirs,
name: "XDG_DATA_DIRS",
value: "~/.local/data:/usr/share",
expected: []string{
filepath.Join(home, ".local/data"),
"/usr/share",
},
actual: &xdg.DataDirs,
},
&envSample{
name: "XDG_CONFIG_HOME",
Expand All @@ -97,10 +105,13 @@ func TestCustomBaseDirs(t *testing.T) {
actual: &xdg.ConfigHome,
},
&envSample{
name: "XDG_CONFIG_DIRS",
value: "~/.local/config:/etc/xdg",
expected: []string{filepath.Join(home, ".local/config"), "/etc/xdg"},
actual: &xdg.ConfigDirs,
name: "XDG_CONFIG_DIRS",
value: "~/.local/config:/etc/xdg",
expected: []string{
filepath.Join(home, ".local/config"),
"/etc/xdg",
},
actual: &xdg.ConfigDirs,
},
&envSample{
name: "XDG_STATE_HOME",
Expand All @@ -120,6 +131,12 @@ func TestCustomBaseDirs(t *testing.T) {
expected: filepath.Join(home, ".local/runtime"),
actual: &xdg.RuntimeDir,
},
&envSample{
name: "XDG_BIN_HOME",
value: "~/bin",
expected: filepath.Join(home, "bin"),
actual: &xdg.BinHome,
},
)
}

Expand Down
71 changes: 53 additions & 18 deletions paths_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,17 @@ func initBaseDirs(home string, kf *knownFolders) {
baseDirs.runtime = pathutil.EnvPath(envRuntimeDir, kf.localAppData)

// Initialize non-standard directories.
baseDirs.binHome = pathutil.EnvPath(envBinHome, kf.userProgramFiles)

baseDirs.applications = []string{
kf.programs,
kf.commonPrograms,
kf.programFiles,
kf.programFilesCommon,
kf.userProgramFiles,
kf.userProgramFilesCommon,
}

baseDirs.fonts = []string{
kf.fonts,
filepath.Join(kf.localAppData, "Microsoft", "Windows", "Fonts"),
Expand All @@ -47,24 +54,28 @@ func initUserDirs(home string, kf *knownFolders) {
}

type knownFolders struct {
systemDrive string
systemRoot string
programData string
userProfile string
userProfiles string
roamingAppData string
localAppData string
desktop string
downloads string
documents string
music string
pictures string
videos string
templates string
public string
fonts string
programs string
commonPrograms string
systemDrive string
systemRoot string
programData string
userProfile string
userProfiles string
roamingAppData string
localAppData string
desktop string
downloads string
documents string
music string
pictures string
videos string
templates string
public string
fonts string
programs string
commonPrograms string
programFiles string
programFilesCommon string
userProgramFiles string
userProgramFilesCommon string
}

func initKnownFolders(home string) *knownFolders {
Expand Down Expand Up @@ -156,6 +167,30 @@ func initKnownFolders(home string) *knownFolders {
nil,
[]string{filepath.Join(kf.programData, "Microsoft", "Windows", "Start Menu", "Programs")},
)
kf.programFiles = pathutil.KnownFolder(
windows.FOLDERID_ProgramFiles,
[]string{"ProgramFiles"},
[]string{filepath.Join(kf.systemDrive, "Program Files")},
)
kf.programFilesCommon = pathutil.KnownFolder(
windows.FOLDERID_ProgramFilesCommon,
nil,
[]string{filepath.Join(kf.programFiles, "Common Files")},
)
kf.userProgramFiles = pathutil.KnownFolder(
windows.FOLDERID_UserProgramFiles,
nil,
[]string{
filepath.Join(kf.localAppData, "Programs"),
},
)
kf.userProgramFilesCommon = pathutil.KnownFolder(
windows.FOLDERID_UserProgramFilesCommon,
nil,
[]string{
filepath.Join(kf.userProgramFiles, "Common"),
},
)

return kf
}
Loading
Loading