XDG library path support for OCaml via Eio capabilities
linux macos ocaml xdg
at v1.0.0 17 kB view raw
1(** XDG Base Directory Specification support with Eio capabilities 2 3 This library provides an OCaml implementation of the XDG Base Directory 4 Specification with Eio filesystem integration. The XDG specification defines 5 standard locations for user-specific and system-wide application files, 6 helping to keep user home directories clean and organized. 7 8 The specification is available at: 9 {{:https://specifications.freedesktop.org/basedir-spec/latest/} XDG Base 10 Directory Specification} 11 12 {b Key Concepts:} 13 14 The XDG specification defines several types of directories: 15 - {b User directories}: Store user-specific files (config, data, cache, 16 state, runtime) 17 - {b System directories}: Store system-wide files shared across users 18 - {b Precedence}: User directories take precedence over system directories 19 - {b Application isolation}: Each application gets its own subdirectory 20 21 {b Environment Variable Precedence:} 22 23 This library follows a three-level precedence system: 24 + Application-specific variables (e.g., [MYAPP_CONFIG_DIR]) - highest 25 priority 26 + XDG standard variables (e.g., [XDG_CONFIG_HOME]) 27 + Default paths (e.g., [$HOME/.config]) - lowest priority 28 29 This allows fine-grained control over directory locations without affecting 30 other XDG-compliant applications. 31 32 {b Directory Creation:} 33 34 All directories are automatically created with appropriate permissions 35 (0o755) when accessed, except for runtime directories which require stricter 36 permissions as per the specification. 37 38 @see <https://specifications.freedesktop.org/basedir-spec/latest/> 39 XDG Base Directory Specification *) 40 41type t 42(** The main XDG context type containing all directory paths for an application. 43 44 A value of type [t] represents the complete XDG directory structure for a 45 specific application, including both user-specific and system-wide 46 directories. All paths are resolved at creation time and are absolute paths 47 within the Eio filesystem. *) 48 49(** {1 Exceptions} *) 50 51exception Invalid_xdg_path of string 52(** Exception raised when XDG environment variables contain invalid paths. 53 54 The XDG specification requires all paths in environment variables to be 55 absolute. This exception is raised when a relative path is found. *) 56 57(** {1 Construction} *) 58 59val create : Eio.Fs.dir_ty Eio.Path.t -> string -> t 60(** [create fs app_name] creates an XDG context for the given application. 61 62 This function initializes the complete XDG directory structure for your 63 application, resolving all paths according to the environment variables and 64 creating directories as needed. 65 66 @param fs The Eio filesystem providing filesystem access 67 @param app_name The name of your application (used as subdirectory name) 68 69 {b Path Resolution:} 70 71 For each directory type, the following precedence is used: 72 + Application-specific environment variable (e.g., [MYAPP_CONFIG_DIR]) 73 + XDG standard environment variable (e.g., [XDG_CONFIG_HOME]) 74 + Default path as specified in the XDG specification 75 76 {b Example:} 77 {[ 78 let xdg = Xdge.create env#fs "myapp" in 79 let config = Xdge.config_dir xdg in 80 (* config is now <fs:$HOME/.config/myapp> or the overridden path *) 81 ]} 82 83 All directories are created with permissions 0o755 if they don't exist, 84 except for runtime directories which are created with 0o700 permissions and 85 validated according to the XDG specification. 86 87 @raise Invalid_xdg_path if any environment variable contains a relative path 88*) 89 90(** {1 Accessors} *) 91 92val app_name : t -> string 93(** [app_name t] returns the application name used when creating this XDG 94 context. 95 96 This is the name that was passed to {!create} and is used as the 97 subdirectory name within each XDG base directory. *) 98 99(** {1 Base Directories} *) 100 101val config_dir : t -> Eio.Fs.dir_ty Eio.Path.t 102(** [config_dir t] returns the path to user-specific configuration files. 103 104 {b Purpose:} Store user preferences, settings, and configuration files. 105 Configuration files should be human-readable when possible. 106 107 {b Environment Variables:} 108 - [${APP_NAME}_CONFIG_DIR]: Application-specific override (highest priority) 109 - [XDG_CONFIG_HOME]: XDG standard variable 110 - Default: [$HOME/.config/{app_name}] 111 112 @see <https://specifications.freedesktop.org/basedir-spec/latest/#variables> 113 XDG_CONFIG_HOME specification *) 114 115val data_dir : t -> Eio.Fs.dir_ty Eio.Path.t 116(** [data_dir t] returns the path to user-specific data files. 117 118 {b Purpose:} Store persistent application data that should be preserved 119 across application restarts and system reboots. This data is typically not 120 modified by users directly. 121 122 {b Environment Variables:} 123 - [${APP_NAME}_DATA_DIR]: Application-specific override (highest priority) 124 - [XDG_DATA_HOME]: XDG standard variable 125 - Default: [$HOME/.local/share/{app_name}] 126 127 {b Example Files:} 128 - Application databases 129 - User-generated content (documents, projects) 130 - Downloaded resources 131 - Application plugins or extensions 132 133 @see <https://specifications.freedesktop.org/basedir-spec/latest/#variables> 134 XDG_DATA_HOME specification *) 135 136val cache_dir : t -> Eio.Fs.dir_ty Eio.Path.t 137(** [cache_dir t] returns the path to user-specific cache files. 138 139 {b Purpose:} Store non-essential cached data that can be regenerated if 140 deleted. The application should remain functional if this directory is 141 cleared, though performance may be temporarily impacted. 142 143 {b Environment Variables:} 144 - [${APP_NAME}_CACHE_DIR]: Application-specific override (highest priority) 145 - [XDG_CACHE_HOME]: XDG standard variable 146 - Default: [$HOME/.cache/{app_name}] 147 148 {b Example Files:} 149 - Downloaded thumbnails and previews 150 - Compiled bytecode or object files 151 - Network response caches 152 - Temporary computation results 153 154 Users may clear cache directories to free disk space, so always check for 155 cache validity and be prepared to regenerate data. 156 157 @see <https://specifications.freedesktop.org/basedir-spec/latest/#variables> 158 XDG_CACHE_HOME specification *) 159 160val state_dir : t -> Eio.Fs.dir_ty Eio.Path.t 161(** [state_dir t] returns the path to user-specific state files. 162 163 {b Purpose:} Store persistent state data that should be preserved between 164 application restarts but is not important enough to be user data. This 165 includes application state that can be regenerated but would impact the user 166 experience if lost. 167 168 {b Environment Variables:} 169 - [${APP_NAME}_STATE_DIR]: Application-specific override (highest priority) 170 - [XDG_STATE_HOME]: XDG standard variable 171 - Default: [$HOME/.local/state/{app_name}] 172 173 {b Example Files:} 174 - Application history (recently used files, command history) 175 - Current application state (window positions, open tabs) 176 - Logs and journal files 177 - Undo/redo history 178 179 {b Comparison with other directories:} 180 - Unlike cache: State should persist between reboots 181 - Unlike data: State can be regenerated (though inconvenient) 182 - Unlike config: State changes frequently during normal use 183 184 @see <https://specifications.freedesktop.org/basedir-spec/latest/#variables> 185 XDG_STATE_HOME specification *) 186 187val runtime_dir : t -> Eio.Fs.dir_ty Eio.Path.t option 188(** [runtime_dir t] returns the path to user-specific runtime files. 189 190 {b Purpose:} Store runtime files such as sockets, named pipes, and process 191 IDs. These files are only valid for the duration of the user's login 192 session. 193 194 {b Environment Variables:} 195 - [${APP_NAME}_RUNTIME_DIR]: Application-specific override (highest 196 priority) 197 - [XDG_RUNTIME_DIR]: XDG standard variable 198 - Default: None (returns [None] if not set) 199 200 {b Required Properties (per specification):} 201 - Owned by the user with access mode 0700 202 - Bound to the user login session lifetime 203 - Located on a local filesystem (not networked) 204 - Fully-featured by the OS (supporting proper locking, etc.) 205 206 {b Example Files:} 207 - Unix domain sockets 208 - Named pipes (FIFOs) 209 - Lock files 210 - Small process communication files 211 212 This may return [None] if no suitable runtime directory is available. 213 Applications should handle this gracefully, perhaps by falling back to 214 [/tmp] with appropriate security measures. 215 216 @see <https://specifications.freedesktop.org/basedir-spec/latest/#variables> 217 XDG_RUNTIME_DIR specification *) 218 219(** {1 System Directories} *) 220 221val config_dirs : t -> Eio.Fs.dir_ty Eio.Path.t list 222(** [config_dirs t] returns search paths for system-wide configuration files. 223 224 {b Purpose:} Provide a search path for configuration files that are shared 225 between multiple users. Files in user-specific {!config_dir} take precedence 226 over these system directories. 227 228 {b Environment Variables:} 229 - [${APP_NAME}_CONFIG_DIRS]: Application-specific override (highest 230 priority) 231 - [XDG_CONFIG_DIRS]: XDG standard variable (colon-separated list) 232 - Default: [[/etc/xdg/{app_name}]] 233 234 {b Search Order:} Directories are ordered by preference, with earlier 235 entries taking precedence over later ones. When looking for a configuration 236 file, search {!config_dir} first, then each directory in this list. 237 238 @see <https://specifications.freedesktop.org/basedir-spec/latest/#variables> 239 XDG_CONFIG_DIRS specification *) 240 241val data_dirs : t -> Eio.Fs.dir_ty Eio.Path.t list 242(** [data_dirs t] returns search paths for system-wide data files. 243 244 {b Purpose:} Provide a search path for data files that are shared between 245 multiple users. Files in user-specific {!data_dir} take precedence over 246 these system directories. 247 248 {b Environment Variables:} 249 - [${APP_NAME}_DATA_DIRS]: Application-specific override (highest priority) 250 - [XDG_DATA_DIRS]: XDG standard variable (colon-separated list) 251 - Default: [[/usr/local/share/{app_name}; /usr/share/{app_name}]] 252 253 {b Search Order:} Directories are ordered by preference, with earlier 254 entries taking precedence over later ones. When looking for a data file, 255 search {!data_dir} first, then each directory in this list. 256 257 {b Example Files:} 258 - Application icons and themes 259 - Desktop files 260 - Shared application resources 261 - Documentation files 262 - Default templates 263 264 @see <https://specifications.freedesktop.org/basedir-spec/latest/#variables> 265 XDG_DATA_DIRS specification *) 266 267(** {1 File Search} *) 268 269val find_config_file : t -> string -> Eio.Fs.dir_ty Eio.Path.t option 270(** [find_config_file t filename] searches for a configuration file following 271 XDG precedence. 272 273 This function searches for the given filename in the user configuration 274 directory first, then in system configuration directories in order of 275 preference. Files that are inaccessible (due to permissions, non-existence, 276 etc.) are silently skipped as per the XDG specification. 277 278 @param t The XDG context 279 @param filename The name of the file to search for 280 @return [Some path] if found, [None] if not found in any directory 281 282 {b Search Order:} 1. User config directory ({!config_dir}) 2. System config 283 directories ({!config_dirs}) in preference order *) 284 285val find_data_file : t -> string -> Eio.Fs.dir_ty Eio.Path.t option 286(** [find_data_file t filename] searches for a data file following XDG 287 precedence. 288 289 This function searches for the given filename in the user data directory 290 first, then in system data directories in order of preference. Files that 291 are inaccessible (due to permissions, non-existence, etc.) are silently 292 skipped as per the XDG specification. 293 294 @param t The XDG context 295 @param filename The name of the file to search for 296 @return [Some path] if found, [None] if not found in any directory 297 298 {b Search Order:} 1. User data directory ({!data_dir}) 2. System data 299 directories ({!data_dirs}) in preference order *) 300 301(** {1 Pretty Printing} *) 302 303val pp : ?brief:bool -> ?sources:bool -> Format.formatter -> t -> unit 304(** [pp ?brief ?sources ppf t] pretty prints the XDG directory configuration. 305 306 @param brief If [true], prints a compact one-line summary (default: [false]) 307 @param sources 308 If [true], shows the source of each directory value, indicating whether it 309 came from defaults, environment variables, or command line (default: 310 [false]) 311 @param ppf The formatter to print to 312 @param t The XDG context to print 313 314 {b Output formats:} 315 - Normal: Multi-line detailed view of all directories 316 - Brief: Single line showing app name and key directories 317 - With sources: Adds annotations showing where each path came from *) 318 319(** {1 Cmdliner Integration} *) 320 321module Cmd : sig 322 (** The type of the outer XDG context *) 323 type xdg_t = t 324 (** Cmdliner integration for XDG directory configuration. 325 326 This module provides integration with the Cmdliner library, allowing XDG 327 directories to be configured via command-line arguments while respecting 328 the precedence of environment variables. *) 329 330 type t 331 (** Type of XDG configuration gathered from command-line and environment. 332 333 This contains all XDG directory paths along with their sources, as 334 determined by command-line arguments and environment variables. *) 335 336 type dir = 337 [ `Config (** User configuration files *) 338 | `Cache (** User-specific cached data *) 339 | `Data (** User-specific application data *) 340 | `State (** User-specific state data (logs, history, etc.) *) 341 | `Runtime (** User-specific runtime files (sockets, pipes, etc.) *) ] 342 (** XDG directory types for specifying which directories an application needs. 343 344 These allow applications to declare which XDG directories they use, 345 enabling runtime systems to only provide the requested directories. *) 346 347 val term : 348 string -> 349 Eio.Fs.dir_ty Eio.Path.t -> 350 ?dirs:dir list -> 351 unit -> 352 (xdg_t * t) Cmdliner.Term.t 353 (** [term app_name fs ?dirs ()] creates a Cmdliner term for XDG directory 354 configuration. 355 356 This function generates a Cmdliner term that handles XDG directory 357 configuration through both command-line flags and environment variables, 358 and directly returns the XDG context. Only command-line flags for the 359 requested directories are generated. 360 361 @param app_name 362 The application name (used for environment variable prefixes) 363 @param fs The Eio filesystem to use for path resolution 364 @param dirs 365 List of directories to include flags for (default: all directories) 366 367 {b Generated Command-line Flags:} Only the flags for requested directories 368 are generated: 369 - [--config-dir DIR]: Override configuration directory (if [`Config] in 370 dirs) 371 - [--data-dir DIR]: Override data directory (if [`Data] in dirs) 372 - [--cache-dir DIR]: Override cache directory (if [`Cache] in dirs) 373 - [--state-dir DIR]: Override state directory (if [`State] in dirs) 374 - [--runtime-dir DIR]: Override runtime directory (if [`Runtime] in dirs) 375 376 {b Environment Variable Precedence:} For each directory type, the 377 following precedence applies: 378 + Command-line flag (e.g., [--config-dir]) - if enabled 379 + Application-specific variable (e.g., [MYAPP_CONFIG_DIR]) 380 + XDG standard variable (e.g., [XDG_CONFIG_HOME]) 381 + Default value *) 382 383 val cache_term : string -> string Cmdliner.Term.t 384 (** [cache_term app_name] creates a Cmdliner term that provides just the cache 385 directory path as a string, respecting XDG precedence. 386 387 This is a convenience function for applications that only need cache 388 directory configuration. It returns the resolved cache directory path 389 directly as a string, suitable for use in other Cmdliner terms. 390 391 @param app_name 392 The application name (used for environment variable prefixes) 393 394 {b Generated Command-line Flag:} 395 - [--cache-dir DIR]: Override cache directory 396 397 {b Environment Variable Precedence:} 398 + Command-line flag ([--cache-dir]) 399 + Application-specific variable (e.g., [MYAPP_CACHE_DIR]) 400 + XDG standard variable ([XDG_CACHE_HOME]) 401 + Default value ([$HOME/.cache/{app_name}]) *) 402 403 val env_docs : string -> string 404 (** [env_docs app_name] generates documentation for environment variables. 405 406 Returns a formatted string documenting all environment variables that 407 affect XDG directory configuration for the given application. This is 408 useful for generating man pages or help text. 409 410 @param app_name The application name 411 @return A formatted documentation string 412 413 {b Included Information:} 414 - Configuration precedence rules 415 - Application-specific environment variables 416 - XDG standard environment variables 417 - Default values for each directory type *) 418 419 val pp : Format.formatter -> t -> unit 420 (** [pp ppf config] pretty prints a Cmdliner configuration. 421 422 This function formats the configuration showing each directory path along 423 with its source, which is helpful for debugging configuration issues or 424 displaying the current configuration to users. 425 426 @param ppf The formatter to print to 427 @param config The configuration to print *) 428end