Class: Toys::Utils::XDG

Inherits:
Object
  • Object
show all
Defined in:
lib/toys/utils/xdg.rb,
lib/toys/utils/xdg.rb

Overview

A class that provides tools for working with the XDG Base Directory Specification.

This class provides utility methods that locate base directories and search paths for application state, configuration, caches, and other data, according to the XDG Base Directory Spec version 0.8.

Example

require "toys/utils/xdg"

xdg = Toys::Utils::XDG.new

# Get config file paths, in order from most to least important
config_files = xdg.lookup_config("my-config.toml")
config_files.each { |path| read_my_config(path) }

Windows operation

The Spec assumes a unix-like environment, and cannot be applied directly to Windows without modification. In general, this class will function on Windows, but with the following caveats:

  • All file paths must use Windows-style absolute paths, beginning with the drive letter.
  • Environment variables that can contain multiple paths (XDG_*_DIRS) use the Windows path delimiter (;) rather than the unix path delimiter (:).
  • Defaults for home directories (XDG_*_HOME) will follow unix conventions, using subdirectories under the user's profile directory rather than the Windows known folder paths.
  • Defaults for search paths (XDG_*_DIRS) will be empty and will not use the Windows known folder paths.

Defined Under Namespace

Classes: Error

Constant Summary collapse

VERSION =

Version of the simple_xdg gem

Returns:

  • (String)
"0.1.2"

Instance Method Summary collapse

Constructor Details

#initialize(env: ::ENV) ⇒ XDG

Create an instance of XDG.

Parameters:

  • env (Hash{String=>String}) (defaults to: ::ENV) —

    the environment variables. Normally, you can omit this argument, as it will default to ::ENV.



57
58
59
60
# File 'lib/toys/utils/xdg.rb', line 57

def initialize(env: ::ENV)
  require "fileutils"
  @env = env
end

Instance Method Details

#cache_home ⇒ String

Returns the absolute path to the single base directory relative to which user-specific non-essential (cached) data should be written.

Corresponds to the value of the $XDG_CACHE_HOME environment variable and its defaults according to the XDG Base Directory Spec.

Returns:

  • (String)


125
126
127
# File 'lib/toys/utils/xdg.rb', line 125

def cache_home
  @cache_home ||= validate_dir_env("XDG_CACHE_HOME") || ::File.join(home_dir, ".cache")
end

#config_dirs ⇒ Array<String>

Returns the set of preference ordered base directories relative to which configuration files should be searched, as an array of absolute paths. The array is ordered from most to least important, and does not include the config home directory.

Corresponds to the value of the $XDG_CONFIG_DIRS environment variable and its defaults according to the XDG Base Directory Spec.

Returns:

  • (Array<String>)


169
170
171
172
# File 'lib/toys/utils/xdg.rb', line 169

def config_dirs
  @config_dirs ||= validate_dirs_env("XDG_CONFIG_DIRS") ||
                   validate_dirs(["/etc/xdg"])
end

#config_home ⇒ String

Returns the absolute path to the single base directory relative to which user-specific configuration files should be written.

Corresponds to the value of the $XDG_CONFIG_HOME environment variable and its defaults according to the XDG Base Directory Spec.

Returns:

  • (String)


99
100
101
# File 'lib/toys/utils/xdg.rb', line 99

def config_home
  @config_home ||= validate_dir_env("XDG_CONFIG_HOME") || ::File.join(home_dir, ".config")
end

#data_dirs ⇒ Array<String>

Returns the set of preference ordered base directories relative to which data files should be searched, as an array of absolute paths. The array is ordered from most to least important, and does not include the data home directory.

Corresponds to the value of the $XDG_DATA_DIRS environment variable and its defaults according to the XDG Base Directory Spec.

Returns:

  • (Array<String>)


153
154
155
156
# File 'lib/toys/utils/xdg.rb', line 153

def data_dirs
  @data_dirs ||= validate_dirs_env("XDG_DATA_DIRS") ||
                 validate_dirs(["/usr/local/share", "/usr/share"])
end

#data_home ⇒ String

Returns the absolute path to the single base directory relative to which user-specific data files should be written.

Corresponds to the value of the $XDG_DATA_HOME environment variable and its defaults according to the XDG Base Directory Spec.

Returns:

  • (String)


86
87
88
# File 'lib/toys/utils/xdg.rb', line 86

def data_home
  @data_home ||= validate_dir_env("XDG_DATA_HOME") || ::File.join(home_dir, ".local", "share")
end

#ensure_cache_subdir(path) ⇒ String

Returns the absolute path to a directory under #cache_home, creating it if it doesn't already exist.

Parameters:

  • path (String) —

    The relative path to the subdir within the base cache directory.

Returns:

  • (String) —

    The absolute path to the subdir.

Raises:

  • (SystemCallError) —

    If a non-directory already exists there. It is unspecified which specific error will be raised; it typically could be Errno::EEXIST or Errno::ENOTDIR.



360
361
362
# File 'lib/toys/utils/xdg.rb', line 360

def ensure_cache_subdir(path)
  ensure_subdir_internal(cache_home, path)
end

#ensure_config_subdir(path) ⇒ String

Returns the absolute path to a directory under #config_home, creating it if it doesn't already exist.

Parameters:

  • path (String) —

    The relative path to the subdir within the base config directory.

Returns:

  • (String) —

    The absolute path to the subdir.

Raises:

  • (SystemCallError) —

    If a non-directory already exists there. It is unspecified which specific error will be raised; it typically could be Errno::EEXIST or Errno::ENOTDIR.



330
331
332
# File 'lib/toys/utils/xdg.rb', line 330

def ensure_config_subdir(path)
  ensure_subdir_internal(config_home, path)
end

#ensure_data_subdir(path) ⇒ String

Returns the absolute path to a directory under #data_home, creating it if it doesn't already exist.

Parameters:

  • path (String) —

    The relative path to the subdir within the base data directory.

Returns:

  • (String) —

    The absolute path to the subdir.

Raises:

  • (SystemCallError) —

    If a non-directory already exists there. It is unspecified which specific error will be raised; it typically could be Errno::EEXIST or Errno::ENOTDIR.



315
316
317
# File 'lib/toys/utils/xdg.rb', line 315

def ensure_data_subdir(path)
  ensure_subdir_internal(data_home, path)
end

#ensure_state_subdir(path) ⇒ String

Returns the absolute path to a directory under #state_home, creating it if it doesn't already exist.

Parameters:

  • path (String) —

    The relative path to the subdir within the base state directory.

Returns:

  • (String) —

    The absolute path to the subdir.

Raises:

  • (SystemCallError) —

    If a non-directory already exists there. It is unspecified which specific error will be raised; it typically could be Errno::EEXIST or Errno::ENOTDIR.



345
346
347
# File 'lib/toys/utils/xdg.rb', line 345

def ensure_state_subdir(path)
  ensure_subdir_internal(state_home, path)
end

#executable_home ⇒ String

Returns the absolute path to the single base directory relative to which user-specific executable files may be written.

Returns the value of $HOME/.local/bin as specified by the XDG Base Directory Spec.

Returns:

  • (String)


138
139
140
# File 'lib/toys/utils/xdg.rb', line 138

def executable_home
  @executable_home ||= ::File.join(home_dir, ".local", "bin")
end

#home_dir ⇒ String

Returns the absolute path to the current user's home directory.

Uses the value of the $HOME environment variable if it is an absolute path, otherwise falls back to the system's notion of the home directory. If no home directory can be determined (for example, when $HOME is unset and the current user has no passwd entry, as can happen in a container run under an arbitrary UID), returns the filesystem root "/".

Returns:

  • (String)


73
74
75
# File 'lib/toys/utils/xdg.rb', line 73

def home_dir
  @home_dir ||= validate_dir_env("HOME") || safe_home_dir
end

#lookup_cache(path, type: :file) ⇒ Array<String>

Searches the cache directory (#cache_home) for an object with the given relative path, and returns an array of zero or one absolute paths to any found object. Because the XDG basedir spec does not provide for a list of fallback directories for cache files (i.e. there is no XDG_CACHE_DIRS variable or list of default paths), this will return a maximum of one result. However, it returns an array for consistency with the #lookup_data and #lookup_config methods.

Parameters:

  • path (String) —

    Relative path of the object to search for

  • type (String, Symbol, Array<String,Symbol>) (defaults to: :file) —

    The type(s) of objects to find. You can specify any of the types defined by File::Stat#ftype, such as file or directory, or the special type any. Types can be specified as strings or the corresponding symbols. If this argument is not provided, the default of file is used.

Returns:

  • (Array<String>)


300
301
302
# File 'lib/toys/utils/xdg.rb', line 300

def lookup_cache(path, type: :file)
  lookup_internal([cache_home], path, type)
end

#lookup_config(path, type: :file) ⇒ Array<String>

Searches the config directories for an object with the given relative path, and returns an array of absolute paths to all objects found in all config directories (i.e. #config_home and #config_dirs), in order from most to least important. Returns the empty array if no suitable objects are found.

If multiple objects are found, the caller should implement its own logic to resolve them. For example, it can select the first (most important) object, or implement logic to combine the contents.

Parameters:

  • path (String) —

    Relative path of the object to search for

  • type (String, Symbol, Array<String,Symbol>) (defaults to: :file) —

    The type(s) of objects to find. You can specify any of the types defined by File::Stat#ftype, such as file or directory, or the special type any. Types can be specified as strings or the corresponding symbols. If this argument is not provided, the default of file is used.

Returns:

  • (Array<String>)


256
257
258
# File 'lib/toys/utils/xdg.rb', line 256

def lookup_config(path, type: :file)
  lookup_internal([config_home] + config_dirs, path, type)
end

#lookup_data(path, type: :file) ⇒ Array<String>

Searches the data directories for an object with the given relative path, and returns an array of absolute paths to all objects found in all data directories (i.e. #data_home and #data_dirs), in order from most to least important. Returns the empty array if no suitable objects are found.

If multiple objects are found, the caller should implement its own logic to resolve them. For example, it can select the first (most important) object, or implement logic to combine the contents.

Parameters:

  • path (String) —

    Relative path of the object to search for

  • type (String, Symbol, Array<String,Symbol>) (defaults to: :file) —

    The type(s) of objects to find. You can specify any of the types defined by File::Stat#ftype, such as file or directory, or the special type any. Types can be specified as strings or the corresponding symbols. If this argument is not provided, the default of file is used.

Returns:

  • (Array<String>)


232
233
234
# File 'lib/toys/utils/xdg.rb', line 232

def lookup_data(path, type: :file)
  lookup_internal([data_home] + data_dirs, path, type)
end

#lookup_state(path, type: :file) ⇒ Array<String>

Searches the state directory (#state_home) for an object with the given relative path, and returns an array of zero or one absolute paths to any found object. Because the XDG basedir spec does not provide for a list of fallback directories for state files (i.e. there is no XDG_STATE_DIRS variable or list of default paths), this will return a maximum of one result. However, it returns an array for consistency with the #lookup_data and #lookup_config methods.

Parameters:

  • path (String) —

    Relative path of the object to search for

  • type (String, Symbol, Array<String,Symbol>) (defaults to: :file) —

    The type(s) of objects to find. You can specify any of the types defined by File::Stat#ftype, such as file or directory, or the special type any. Types can be specified as strings or the corresponding symbols. If this argument is not provided, the default of file is used.

Returns:

  • (Array<String>)


278
279
280
# File 'lib/toys/utils/xdg.rb', line 278

def lookup_state(path, type: :file)
  lookup_internal([state_home], path, type)
end

#runtime_dir ⇒ String?

Returns the absolute path to the single base directory relative to which user-specific runtime files and other file objects should be placed.

Corresponds to the value of the $XDG_RUNTIME_DIR environment variable according to the XDG Base Directory Spec.

Important: Returns nil if the $XDG_RUNTIME_DIR environment variable is unset or invalid. In such a case, it is the caller's responsibility to determine a fallback strategy, as this library cannot by itself implement a compliant fallback without OS help.

Returns:

  • (String, nil)


189
190
191
192
# File 'lib/toys/utils/xdg.rb', line 189

def runtime_dir
  @runtime_dir = validate_dir_env("XDG_RUNTIME_DIR") unless defined? @runtime_dir
  @runtime_dir
end

#runtime_dir! ⇒ String

Returns the absolute path to the single base directory relative to which user-specific runtime files and other file objects should be placed.

Corresponds to the value of the $XDG_RUNTIME_DIR environment variable according to the XDG Base Directory Spec.

Raises Error if the $XDG_RUNTIME_DIR environment variable is unset or invalid. Unlike #runtime_dir, does not return nil.

Returns:

  • (String)


208
209
210
# File 'lib/toys/utils/xdg.rb', line 208

def runtime_dir!
  runtime_dir || raise(::Toys::Utils::XDG::Error, "XDG_RUNTIME_DIR is unset or invalid")
end

#state_home ⇒ String

Returns the absolute path to the single base directory relative to which user-specific state files should be written.

Corresponds to the value of the $XDG_STATE_HOME environment variable and its defaults according to the XDG Base Directory Spec.

Returns:

  • (String)


112
113
114
# File 'lib/toys/utils/xdg.rb', line 112

def state_home
  @state_home ||= validate_dir_env("XDG_STATE_HOME") || ::File.join(home_dir, ".local", "state")
end