Skip to content

Commit

Permalink
Merge pull request #96 from adrg/xdg-bin-home
Browse files Browse the repository at this point in the history
Add support for XDG_BIN_HOME
  • Loading branch information
adrg authored Oct 14, 2024
2 parents 94dba3f + b09cff4 commit 0d710b1
Show file tree
Hide file tree
Showing 12 changed files with 177 additions and 51 deletions.
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

0 comments on commit 0d710b1

Please sign in to comment.