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