etcetera/lib.rs
1//! This is a Rust library that allows you to determine the locations of configuration, data, cache & other files for your application.
2//! Existing Rust libraries generally do not give you a choice in terms of which standards/conventions they follow.
3//! Etcetera, on the other hand, gives you the choice.
4//!
5//! # Conventions
6//! Etcetera supports the following conventions:
7//! - the [XDG base directory](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html)
8//! - Apple's [Standard Directories](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html)
9//! - Window's [Known Folder Locations](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid)
10//! - the "Unix Single-folder Convention" i.e. everything in `~/.myapp`
11//!
12//! # Strategies
13//! If you want to get started quickly, you can use the following convenience functions that use the default strategies (as determined arbitrarily by yours truly) or the native strategies for each OS.
14//!
15//! ## BaseStrategy
16//! If you just want to get the path to a configuration, data, cache or another directory, you can use the `choose_base_strategy` function.
17//!
18//! ```
19//! use etcetera::{choose_base_strategy, BaseStrategy};
20//!
21//! let strategy = choose_base_strategy().unwrap();
22//!
23//! let config_dir = strategy.config_dir();
24//! let data_dir = strategy.data_dir();
25//! let cache_dir = strategy.cache_dir();
26//! let state_dir = strategy.state_dir();
27//! let runtime_dir = strategy.runtime_dir();
28//! ```
29//!
30//! ## AppStrategy
31//! If you want to get the path to a configuration, data, cache or another directory, and you want to follow the naming conventions for your application, you can use the `choose_app_strategy` function.
32//!
33//! Let’s take an application created by `Acme Corp` with the name `Frobnicator Plus` and the top-level domain of `org` as an example.
34//! - XDG strategy would place these in `~/.config/frobnicator-plus`.
35//! - Unix strategy would place these in `~/.frobnicator-plus`.
36//! - Apple strategy would place these in `~/Library/Preferences/org.acme-corp.Frobnicator-Plus`.
37//! - Windows strategy would place these in `~\AppData\Roaming\Acme Corp\Frobnicator Plus`.
38//!
39//! ```
40//! use etcetera::{choose_app_strategy, AppStrategy, AppStrategyArgs};
41//!
42//! let strategy = choose_app_strategy(AppStrategyArgs {
43//! top_level_domain: "org".to_string(),
44//! author: "Acme Corp".to_string(),
45//! app_name: "Frobnicator Plus".to_string(),
46//! }).unwrap();
47//!
48//! let config_dir = strategy.config_dir();
49//! let data_dir = strategy.data_dir();
50//! let cache_dir = strategy.cache_dir();
51//! let state_dir = strategy.state_dir();
52//! let runtime_dir = strategy.runtime_dir();
53//! ```
54//!
55//! ## Native Strategy
56//!
57//! `choose_base_strategy()` and `choose_app_strategy()` will use the `XDG` strategy on Linux & macOS, and the `Windows` strategy on Windows.
58//! This is used by most CLI tools & some GUI tools on each platform.
59//!
60//! If you're developing a GUI application, you might want to use the "Standard directories" on macOS by using `choose_native_strategy()` instead.
61//! Note that if your application expects the user to modify the configuration files, you should still prefer the `XDG` strategy on macOS.
62//!
63//! ## Custom Conventions
64//!
65//! You aren’t limited to the built-in conventions – you can implement the relevant traits yourself. Please consider contributing these back, as the more preset conventions there are, the better.
66//!
67//! # More Examples
68//! Say you were a hardened Unix veteran, and didn’t want to have any of this XDG nonsense, clutter in the home directory be damned! Instead of using `choose_app_strategy` or `choose_base_strategy`, you can pick a strategy yourself. Here’s an example using the [`Unix`](app_strategy/struct.Unix.html) strategy – see its documentation to see what kind of folder structures it produces:
69//!
70//! ```
71//! use etcetera::{app_strategy, AppStrategy, AppStrategyArgs};
72//!
73//! let strategy = app_strategy::Unix::new(AppStrategyArgs {
74//! top_level_domain: "com".to_string(),
75//! author: "Hardened Unix Veteran Who Likes Short Command Names".to_string(),
76//! app_name: "wry".to_string(),
77//! }).unwrap();
78//!
79//! let config_dir = strategy.config_dir(); // produces ~/.wry/
80//! // et cetera.
81//! ```
82//!
83//! Oftentimes the location of a configuration, data or cache directory is needed solely to create a path that starts inside it. For this purpose, [`AppStrategy`](app_strategy/trait.AppStrategy.html) implements a couple of convenience methods for you:
84//!
85//! ```
86//! use etcetera::{choose_app_strategy, AppStrategy, AppStrategyArgs};
87//!
88//! let strategy = choose_app_strategy(AppStrategyArgs {
89//! top_level_domain: "org".to_string(),
90//! author: "Acme Corp".to_string(),
91//! app_name: "Frobnicator".to_string(),
92//! }).unwrap();
93//!
94//! // Path to configuration directory.
95//! let config_dir = strategy.config_dir();
96//!
97//! // Path to config.toml inside the configuration directory.
98//! let config_file = strategy.in_config_dir("config.toml");
99//!
100//! assert_eq!(config_dir.join("config.toml"), config_file);
101//! ```
102
103#![warn(missing_docs, rust_2018_idioms, missing_debug_implementations)]
104
105pub mod app_strategy;
106pub mod base_strategy;
107
108pub use app_strategy::{AppStrategy, AppStrategyArgs, choose_app_strategy};
109pub use base_strategy::{BaseStrategy, choose_base_strategy};
110
111/// A convenience function that wraps the [`home_dir`](https://doc.rust-lang.org/std/env/fn.home_dir.html) function from the standard library.
112pub fn home_dir() -> Result<std::path::PathBuf, HomeDirError> {
113 std::env::home_dir().ok_or(HomeDirError)
114}
115
116/// This error occurs when the home directory cannot be located.
117#[derive(Debug)]
118pub struct HomeDirError;
119
120impl std::fmt::Display for HomeDirError {
121 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 write!(f, "could not locate home directory")
123 }
124}
125
126impl std::error::Error for HomeDirError {}