Skip to content

Commit

Permalink
Support state directory (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
mmatous authored May 9, 2022
1 parent 7c6be4a commit c22a15e
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/app_strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ pub trait AppStrategy: Sized {
/// Gets the cache directory for your application.
fn cache_dir(&self) -> PathBuf;

/// Gets the state directory for your application.
/// State directory may not to exist for all platforms.
fn state_dir(&self) -> Option<PathBuf>;

/// Constructs a path inside your application’s configuration directory to which a path of your choice has been appended.
fn in_config_dir<P: AsRef<OsStr>>(&self, path: P) -> PathBuf {
in_dir_method!(self, path, config_dir)
Expand Down
8 changes: 8 additions & 0 deletions src/app_strategy/apple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ use std::path::PathBuf;
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Caches/com.apple.Safari/")
/// ));
/// assert_eq!(
/// app_strategy.state_dir(),
/// None
/// );
/// ```
#[derive(Debug)]
pub struct Apple {
Expand Down Expand Up @@ -58,4 +62,8 @@ impl super::AppStrategy for Apple {
fn cache_dir(&self) -> PathBuf {
self.base_strategy.cache_dir().join(&self.bundle_id)
}

fn state_dir(&self) -> Option<PathBuf> {
None
}
}
8 changes: 8 additions & 0 deletions src/app_strategy/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ use std::path::PathBuf;
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".vim/cache/")
/// ));
/// assert_eq!(
/// app_strategy.state_dir().unwrap().strip_prefix(&home_dir),
/// Ok(Path::new(".vim/state/")
/// ));
/// ```
#[derive(Debug)]
pub struct Unix {
Expand Down Expand Up @@ -56,4 +60,8 @@ impl super::AppStrategy for Unix {
fn cache_dir(&self) -> PathBuf {
self.root_dir.join("cache/")
}

fn state_dir(&self) -> Option<PathBuf> {
Some(self.root_dir.join("state/"))
}
}
8 changes: 8 additions & 0 deletions src/app_strategy/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ use std::path::PathBuf;
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new("AppData/Local/Microsoft/File Explorer/cache"))
/// );
/// assert_eq!(
/// app_strategy.state_dir(),
/// None
/// );
/// ```
#[derive(Debug)]
pub struct Windows {
Expand Down Expand Up @@ -68,4 +72,8 @@ impl super::AppStrategy for Windows {
fn cache_dir(&self) -> PathBuf {
dir_method!(self, cache_dir, "cache/")
}

fn state_dir(&self) -> Option<PathBuf> {
None
}
}
26 changes: 26 additions & 0 deletions src/app_strategy/xdg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use std::path::PathBuf;
/// std::env::remove_var("XDG_CONFIG_HOME");
/// std::env::remove_var("XDG_DATA_HOME");
/// std::env::remove_var("XDG_CACHE_HOME");
/// std::env::remove_var("XDG_STATE_HOME");
///
/// let app_strategy = Xdg::new(AppStrategyArgs {
/// top_level_domain: "hm".to_string(),
Expand All @@ -37,6 +38,10 @@ use std::path::PathBuf;
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".cache/htop/")
/// ));
/// assert_eq!(
/// app_strategy.state_dir().unwrap().strip_prefix(&home_dir),
/// Ok(Path::new(".local/state/htop/")
/// ));
/// ```
///
/// This next example gives the environment variables values:
Expand All @@ -63,10 +68,16 @@ use std::path::PathBuf;
/// } else {
/// "/my_cache_location/"
/// };
/// let state_path = if cfg!(windows) {
/// "C:\\my_state_location\\"
/// } else {
/// "/my_state_location/"
/// };
///
/// std::env::set_var("XDG_CONFIG_HOME", config_path);
/// std::env::set_var("XDG_DATA_HOME", data_path);
/// std::env::set_var("XDG_CACHE_HOME", cache_path);
/// std::env::set_var("XDG_STATE_HOME", state_path);
///
/// let app_strategy = Xdg::new(AppStrategyArgs {
/// top_level_domain: "hm".to_string(),
Expand All @@ -77,6 +88,7 @@ use std::path::PathBuf;
/// assert_eq!(app_strategy.config_dir(), Path::new(&format!("{}/htop/", config_path)));
/// assert_eq!(app_strategy.data_dir(), Path::new(&format!("{}/htop/", data_path)));
/// assert_eq!(app_strategy.cache_dir(), Path::new(&format!("{}/htop/", cache_path)));
/// assert_eq!(app_strategy.state_dir().unwrap(), Path::new(&format!("{}/htop/", state_path)));
/// ```
///
/// The XDG spec requires that when the environment variables’ values are not absolute paths, their values should be ignored. This example exemplifies this behaviour:
Expand All @@ -91,6 +103,7 @@ use std::path::PathBuf;
/// std::env::set_var("XDG_CONFIG_HOME", "relative_path/");
/// std::env::set_var("XDG_DATA_HOME", "./another_one/");
/// std::env::set_var("XDG_CACHE_HOME", "yet_another/");
/// std::env::set_var("XDG_STATE_HOME", "./and_another");
///
/// let app_strategy = Xdg::new(AppStrategyArgs {
/// top_level_domain: "hm".to_string(),
Expand All @@ -113,6 +126,10 @@ use std::path::PathBuf;
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".cache/htop/")
/// ));
/// assert_eq!(
/// app_strategy.state_dir().unwrap().strip_prefix(&home_dir),
/// Ok(Path::new(".local/state/htop/")
/// ));
/// ```
#[derive(Debug)]
pub struct Xdg {
Expand Down Expand Up @@ -141,4 +158,13 @@ impl super::AppStrategy for Xdg {
fn cache_dir(&self) -> PathBuf {
self.base_strategy.cache_dir().join(&self.unixy_name)
}

fn state_dir(&self) -> Option<PathBuf> {
Some(
self.base_strategy
.state_dir()
.unwrap()
.join(&self.unixy_name),
)
}
}
4 changes: 4 additions & 0 deletions src/base_strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ pub trait BaseStrategy: Sized {

/// Gets the user’s cache directory.
fn cache_dir(&self) -> PathBuf;

/// Gets the user’s state directory.
/// State directory may not exist for all platforms.
fn state_dir(&self) -> Option<PathBuf>;
}

macro_rules! create_choose_base_strategy {
Expand Down
8 changes: 8 additions & 0 deletions src/base_strategy/apple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ use std::path::PathBuf;
/// base_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Caches/")
/// ));
/// assert_eq!(
/// base_strategy.state_dir(),
/// None
/// );
/// ```
#[derive(Debug)]
pub struct Apple {
Expand Down Expand Up @@ -50,4 +54,8 @@ impl super::BaseStrategy for Apple {
fn cache_dir(&self) -> PathBuf {
self.library_path.join("Caches/")
}

fn state_dir(&self) -> Option<PathBuf> {
None
}
}
8 changes: 8 additions & 0 deletions src/base_strategy/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ use std::path::PathBuf;
/// base_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new("AppData/Local/"))
/// );
/// assert_eq!(
/// base_strategy.state_dir(),
/// None
/// );
/// ```
#[derive(Debug)]
pub struct Windows {
Expand All @@ -49,4 +53,8 @@ impl super::BaseStrategy for Windows {
fn cache_dir(&self) -> PathBuf {
self.appdata.join("Local/")
}

fn state_dir(&self) -> Option<PathBuf> {
None
}
}
21 changes: 21 additions & 0 deletions src/base_strategy/xdg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use std::path::PathBuf;
/// std::env::remove_var("XDG_CONFIG_HOME");
/// std::env::remove_var("XDG_DATA_HOME");
/// std::env::remove_var("XDG_CACHE_HOME");
/// std::env::remove_var("XDG_STATE_HOME");
///
/// let base_strategy = Xdg::new().unwrap();
///
Expand All @@ -30,6 +31,10 @@ use std::path::PathBuf;
/// base_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".cache/")
/// ));
/// assert_eq!(
/// base_strategy.state_dir().unwrap().strip_prefix(&home_dir),
/// Ok(Path::new(".local/state")
/// ));
/// ```
///
/// And here is another example with the environment variables set to demonstrate that the strategy really does read them:
Expand All @@ -55,16 +60,23 @@ use std::path::PathBuf;
/// } else {
/// "/baz/"
/// };
/// let state_path = if cfg!(windows) {
/// "C:\\foobar\\"
/// } else {
/// "/foobar/"
/// };
///
/// std::env::set_var("XDG_CONFIG_HOME", config_path);
/// std::env::set_var("XDG_DATA_HOME", data_path);
/// std::env::set_var("XDG_CACHE_HOME", cache_path);
/// std::env::set_var("XDG_STATE_HOME", state_path);
///
/// let base_strategy = Xdg::new().unwrap();
///
/// assert_eq!(base_strategy.config_dir(), Path::new(config_path));
/// assert_eq!(base_strategy.data_dir(), Path::new(data_path));
/// assert_eq!(base_strategy.cache_dir(), Path::new(cache_path));
/// assert_eq!(base_strategy.state_dir().unwrap(), Path::new(state_path));
/// ```
///
/// The specification states that:
Expand All @@ -81,6 +93,7 @@ use std::path::PathBuf;
/// std::env::set_var("XDG_CONFIG_HOME", "foo/");
/// std::env::set_var("XDG_DATA_HOME", "bar/");
/// std::env::set_var("XDG_CACHE_HOME", "baz/");
/// std::env::set_var("XDG_STATE_HOME", "foobar/");
///
/// let base_strategy = Xdg::new().unwrap();
///
Expand All @@ -98,6 +111,10 @@ use std::path::PathBuf;
/// base_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".cache/")
/// ));
/// assert_eq!(
/// base_strategy.state_dir().unwrap().strip_prefix(&home_dir),
/// Ok(Path::new(".local/state/")
/// ));
/// ```
#[derive(Debug)]
pub struct Xdg {
Expand Down Expand Up @@ -142,4 +159,8 @@ impl super::BaseStrategy for Xdg {
fn cache_dir(&self) -> PathBuf {
self.env_var_or_default("XDG_CACHE_HOME", ".cache/")
}

fn state_dir(&self) -> Option<PathBuf> {
Some(self.env_var_or_default("XDG_STATE_HOME", ".local/state/"))
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//! let config_dir = strategy.config_dir();
//! let data_dir = strategy.data_dir();
//! let cache_dir = strategy.cache_dir();
//! let state_dir = strategy.state_dir();
//! ```
//!
//! Here is an example where you provide Etcetera with some basic information about your application, and Etcetera will in turn give you a path that includes this information (this is called an ‘app strategy’).
Expand All @@ -33,6 +34,7 @@
//! let config_dir = strategy.config_dir();
//! let data_dir = strategy.data_dir();
//! let cache_dir = strategy.cache_dir();
//! let state_dir = strategy.state_dir();
//! ```
//!
//! 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:
Expand Down

0 comments on commit c22a15e

Please sign in to comment.