Add basedir implementation
This commit is contained in:
commit
2d33aab91f
302
assets/icon.svg
Normal file
302
assets/icon.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 19 KiB |
209
basedir/basedir.go
Normal file
209
basedir/basedir.go
Normal file
@ -0,0 +1,209 @@
|
||||
// Package basedir implements https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
package basedir
|
||||
|
||||
import "os"
|
||||
import "errors"
|
||||
import "path/filepath"
|
||||
|
||||
// Var is an XDG environment variable.
|
||||
type Var string; const (
|
||||
VarDataHome Var = "XDG_DATA_HOME"
|
||||
VarConfigHome Var = "XDG_CONFIG_HOME"
|
||||
VarStateHome Var = "XDG_STATE_HOME"
|
||||
VarDataDirs Var = "XDG_DATA_DIRS"
|
||||
VarConfigDirs Var = "XDG_CONFIG_DIRS"
|
||||
VarCacheHome Var = "XDG_CACHE_HOME"
|
||||
VarRuntimeDir Var = "XDG_RUNTIME_DIR"
|
||||
)
|
||||
|
||||
// Value returns the value of the environment variable.
|
||||
func (v Var) Value () string {
|
||||
return os.Getenv(string(v))
|
||||
}
|
||||
|
||||
// ErrEmpty indicaties a path is empty.
|
||||
var ErrEmpty = errors.New("path is not absolute")
|
||||
// ErrNotAbs indicates a path is not absolute.
|
||||
var ErrNotAbs = errors.New("path is not absolute")
|
||||
|
||||
// Valid returns an error if the path is not absolute (beginning from '/') or if
|
||||
// it is otherwise invalid.
|
||||
func Valid (path string) error {
|
||||
if path == "" { return ErrEmpty }
|
||||
if !filepath.IsAbs(path) { return ErrNotAbs }
|
||||
return nil
|
||||
}
|
||||
|
||||
// DataHome returns the single base directory relative to which user-specific
|
||||
// data files should be written.
|
||||
//
|
||||
// $XDG_DATA_HOME defines the base directory relative to which user-specific
|
||||
// data files should be stored. If $XDG_DATA_HOME is either not set or empty,
|
||||
// a default equal to $HOME/.local/share is used.
|
||||
func DataHome () (string, error) {
|
||||
return homeDefault(VarDataHome.Value(), ".local/share")
|
||||
}
|
||||
|
||||
// ConfigHome returns the single base directory relative to which user-specific
|
||||
// configuration files should be written.
|
||||
//
|
||||
// $XDG_CONFIG_HOME defines the base directory relative to which
|
||||
// user-specific configuration files should be stored. If $XDG_CONFIG_HOME is
|
||||
// either not set or empty, a default equal to $HOME/.config is used.
|
||||
func ConfigHome () (string, error) {
|
||||
return homeDefault(VarConfigHome.Value(), ".config")
|
||||
}
|
||||
|
||||
// StateHome returns the single base directory relative to which user-specific
|
||||
// state data should be written.
|
||||
//
|
||||
// The $XDG_STATE_HOME contains state data that should persist between
|
||||
// (application) restarts, but that is not important or portable enough to the
|
||||
// user that it should be stored in $XDG_DATA_HOME. It may contain:
|
||||
// - actions history (logs, history, recently used files, …)
|
||||
// - current state of the application that can be reused on a restart (view,
|
||||
// layout, open files, undo history, …)
|
||||
func StateHome () (string, error) {
|
||||
return homeDefault(VarStateHome.Value(), ".local/state")
|
||||
}
|
||||
|
||||
// ExecutableHome returns the directory in which user-specific executables may
|
||||
// be stored, which is $HOME/.local/bin.
|
||||
func ExecutableHome () (string, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil { return "", err }
|
||||
return filepath.Join(home, ".local/bin"), nil
|
||||
}
|
||||
|
||||
// DataDirs returns the set of preference ordered base directories relative to
|
||||
// which data files should be searched.
|
||||
//
|
||||
// $XDG_DATA_DIRS defines the preference-ordered set of base directories to
|
||||
// search for data files in addition to the $XDG_DATA_HOME base directory. The
|
||||
// directories in $XDG_DATA_DIRS should be seperated with a colon ':'. If
|
||||
// $XDG_DATA_DIRS is either not set or empty, a value equal to
|
||||
// /usr/local/share/:/usr/share/ is used.
|
||||
//
|
||||
// It is reccomended to call AllDataDirs instead of DataDirs for most use cases.
|
||||
func DataDirs () ([]string, error) {
|
||||
return listDefault(VarDataDirs.Value(), "/usr/local/share", "/usr/share"), nil
|
||||
}
|
||||
|
||||
// AllDataDirs returns the result of DataHome in front of DataDirs.
|
||||
func AllDataDirs () ([]string, error) {
|
||||
dataHome, err := DataHome()
|
||||
if err != nil { return nil, err }
|
||||
dataDirs, err := DataDirs()
|
||||
if err != nil { return nil, err }
|
||||
|
||||
if dataHome == "" {
|
||||
return dataDirs, nil
|
||||
} else {
|
||||
return append([]string{ dataHome }, dataDirs...), nil
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigDirs returns set of preference ordered base directories relative to
|
||||
// which configuration files should be searched.
|
||||
//
|
||||
// $XDG_CONFIG_DIRS defines the preference-ordered set of base directories to
|
||||
// search for configuration files in addition to the $XDG_CONFIG_HOME base
|
||||
// directory. The directories in $XDG_CONFIG_DIRS should be seperated with a
|
||||
// colon ':'. If $XDG_CONFIG_DIRS is either not set or empty, a value equal to
|
||||
// /etc/xdg is used.
|
||||
//
|
||||
// It is reccomended to call AllConfigDirs instead of ConfigDirs for most use
|
||||
// cases.
|
||||
func ConfigDirs () ([]string, error) {
|
||||
return listDefault(VarConfigDirs.Value(), "/etc/xdg"), nil
|
||||
}
|
||||
|
||||
// AllConfigDirs returns the result of ConfigHome in front of ConfigDirs.
|
||||
func AllConfigDirs () ([]string, error) {
|
||||
configHome, err := ConfigHome()
|
||||
if err != nil { return nil, err }
|
||||
configDirs, err := ConfigDirs()
|
||||
if err != nil { return nil, err }
|
||||
|
||||
if configHome == "" {
|
||||
return configDirs, nil
|
||||
} else {
|
||||
return append([]string{ configHome }, configDirs...), nil
|
||||
}
|
||||
}
|
||||
|
||||
// CacheHome returns the single base directory relative to which user-specific
|
||||
// non-essential (cached) data should be written.
|
||||
//
|
||||
// $XDG_CACHE_HOME defines the base directory relative to which user-specific
|
||||
// non-essential data files should be stored. If $XDG_CACHE_HOME is either not
|
||||
// set or empty, a default equal to $HOME/.cache is used.
|
||||
func CacheHome () (string, error) {
|
||||
return homeDefault(VarCacheHome.Value(), ".cache")
|
||||
}
|
||||
|
||||
// RuntimeDir returns the single base directory relative to which user-specific
|
||||
// runtime files and other file objects should be placed.
|
||||
//
|
||||
// $XDG_RUNTIME_DIR defines the base directory relative to which user-specific
|
||||
// non-essential runtime files and other file objects (such as sockets, named
|
||||
// pipes, ...) should be stored. The directory MUST be owned by the user, and
|
||||
// they MUST be the only one having read and write access to it. Its Unix access
|
||||
// mode MUST be 0700.
|
||||
//
|
||||
// The lifetime of the directory MUST be bound to the user being logged in. It
|
||||
// MUST be created when the user first logs in and if the user fully logs out
|
||||
// the directory MUST be removed. If the user logs in more than once they should
|
||||
// get pointed to the same directory, and it is mandatory that the directory
|
||||
// continues to exist from their first login to their last logout on the system,
|
||||
// and not removed in between. Files in the directory MUST not survive reboot or
|
||||
// a full logout/login cycle.
|
||||
//
|
||||
// The directory MUST be on a local file system and not shared with any other
|
||||
// system. The directory MUST by fully-featured by the standards of the
|
||||
// operating system. More specifically, on Unix-like operating systems AF_UNIX
|
||||
// sockets, symbolic links, hard links, proper permissions, file locking, sparse
|
||||
// files, memory mapping, file change notifications, a reliable hard link count
|
||||
// must be supported, and no restrictions on the file name character set should
|
||||
// be imposed. Files in this directory MAY be subjected to periodic clean-up. To
|
||||
// ensure that your files are not removed, they should have their access time
|
||||
// timestamp modified at least once every 6 hours of monotonic time or the
|
||||
// 'sticky' bit should be set on the file.
|
||||
//
|
||||
// If this function returns an error, applications should fall back to a
|
||||
// replacement directory with similar capabilities and print a warning message.
|
||||
// Applications should use this directory for communication and synchronization
|
||||
// purposes and should not place larger files in it, since it might reside in
|
||||
// runtime memory and cannot necessarily be swapped out to disk.
|
||||
func RuntimeDir () (string, error) {
|
||||
value := VarRuntimeDir.Value()
|
||||
err := Valid(value)
|
||||
if err != nil { return "", err }
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func homeDefault (value, defaul string) (string, error) {
|
||||
if Valid(value) == nil {
|
||||
return value, nil
|
||||
} else {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil { return "", err }
|
||||
return filepath.Join(home, defaul), nil
|
||||
}
|
||||
}
|
||||
|
||||
func listDefault (list string, defaul ...string) []string {
|
||||
if list == "" { return defaul }
|
||||
|
||||
envDirs := filepath.SplitList(list)
|
||||
dirs := make([]string, len(envDirs))
|
||||
|
||||
index := 0
|
||||
for _, dir := range envDirs {
|
||||
if Valid(dir) != nil {
|
||||
dirs[index] = dir
|
||||
index ++
|
||||
}
|
||||
}
|
||||
return dirs[:index]
|
||||
}
|
Loading…
Reference in New Issue
Block a user