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 base support for XDG base user executable dir #28

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
23 changes: 16 additions & 7 deletions base_dirs.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ const (
)

type baseDirectories struct {
dataHome string
data []string
configHome string
config []string
stateHome string
cacheHome string
runtime string
dataHome string
data []string
configHome string
config []string
stateHome string
cacheHome string
executableHome string
runtime string

// Non-standard directories.
fonts []string
Expand All @@ -43,6 +44,10 @@ func (bd baseDirectories) cacheFile(relPath string) (string, error) {
return pathutil.Create(relPath, []string{bd.cacheHome})
}

func (bd baseDirectories) executableFile(relPath string) (string, error) {
return pathutil.Create(relPath, []string{bd.executableHome})
}

func (bd baseDirectories) runtimeFile(relPath string) (string, error) {
return pathutil.Create(relPath, []string{bd.runtime})
}
Expand All @@ -63,6 +68,10 @@ func (bd baseDirectories) searchCacheFile(relPath string) (string, error) {
return pathutil.Search(relPath, []string{bd.cacheHome})
}

func (bd baseDirectories) searchExecutableFile(relPath string) (string, error) {
return pathutil.Search(relPath, []string{bd.executableHome})
}

func (bd baseDirectories) searchRuntimeFile(relPath string) (string, error) {
return pathutil.Search(relPath, []string{bd.runtime})
}
1 change: 1 addition & 0 deletions paths_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func initBaseDirs(home string) {
baseDirs.config = xdgPaths(envConfigDirs, "/etc/xdg")
baseDirs.stateHome = xdgPath(envStateHome, filepath.Join(home, ".local", "state"))
baseDirs.cacheHome = xdgPath(envCacheHome, filepath.Join(home, ".cache"))
baseDirs.executableHome = filepath.Join(home, ".local", "bin")
baseDirs.runtime = xdgPath(envRuntimeDir, filepath.Join("/run/user", strconv.Itoa(os.Getuid())))

// Initialize non-standard directories.
Expand Down
6 changes: 6 additions & 0 deletions paths_unix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,12 @@ func TestCustomBaseDirs(t *testing.T) {
expected: filepath.Join(home, ".local/cache"),
actual: &xdg.CacheHome,
},
&envSample{
name: "__UNUSED__",
value: "__UNUSED__",
expected: filepath.Join(home, ".local/bin"),
actual: &xdg.ExecutableHome,
},
&envSample{
name: "XDG_RUNTIME_DIR",
value: "~/.local/runtime",
Expand Down
24 changes: 24 additions & 0 deletions xdg.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ var (
// is not set, a default equal to $HOME/.cache should be used.
CacheHome string

// ExecutableHome defines the base directory relative to which user-specific
// executable files should be written. This directory is not defined by
// any specific environment variable; it defaults to $HOME/.local/bin.
ExecutableHome string

// RuntimeDir defines the base directory relative to which user-specific
// non-essential runtime files and other file objects (such as sockets,
// named pipes, etc.) should be stored. This directory is defined by the
Expand Down Expand Up @@ -100,6 +105,7 @@ func Reload() {
ConfigDirs = baseDirs.config
StateHome = baseDirs.stateHome
CacheHome = baseDirs.cacheHome
ExecutableHome = baseDirs.executableHome
RuntimeDir = baseDirs.runtime

// Set non-standard directories.
Expand Down Expand Up @@ -149,6 +155,15 @@ func CacheFile(relPath string) (string, error) {
return baseDirs.cacheFile(relPath)
}

// ExecutableFile returns a suitable location for the specified user
// specific executable file. The relPath parameter must contain the name of
// the runtime file, without any parent directories. On failure, an error
// containing the attempted path is returned.
func ExecutableFile(relPath string) (string, error) {
// TODO: fail if relPath contains parent dirs
return baseDirs.executableFile(relPath)
}

// RuntimeFile returns a suitable location for the specified runtime file.
// The relPath parameter must contain the name of the runtime file, and
// optionally, a set of parent directories (e.g. appname/app.pid).
Expand Down Expand Up @@ -191,6 +206,15 @@ func SearchCacheFile(relPath string) (string, error) {
return baseDirs.searchCacheFile(relPath)
}

// SearchExecutableFile searches for the specified file in the user specific
// executable path. The relPath parameter must contain the name of the cache
// file, without any parent directories. If the file cannot be found, an
// error specifying the searched path is returned.
func SearchExecutableFile(relPath string) (string, error) {
// TODO: fail if relPath contains parent dirs
return baseDirs.searchExecutableFile(relPath)
}

// SearchRuntimeFile searches for the specified file in the runtime search path.
// The relPath parameter must contain the name of the runtime file, and
// optionally, a set of parent directories (e.g. appname/app.pid). If the
Expand Down
6 changes: 6 additions & 0 deletions xdg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ func TestBaseDirFuncs(t *testing.T) {
pathFunc: xdg.CacheFile,
searchFunc: xdg.SearchCacheFile,
},
{
relPaths: []string{"app"},
pathFunc: xdg.ExecutableFile,
searchFunc: xdg.SearchExecutableFile,
},
{
relPaths: []string{"app.pid", "appname/app.pid"},
pathFunc: xdg.RuntimeFile,
Expand Down Expand Up @@ -174,6 +179,7 @@ func TestInvalidPaths(t *testing.T) {
"appname\000/app.yaml": xdg.ConfigFile,
"appname/\000/app.state": xdg.StateFile,
"\000appname/app.cache": xdg.CacheFile,
"appname/app": xdg.ExecutableFile,
"\000/appname/app.pid": xdg.RuntimeFile,
}

Expand Down