diff --git a/src/app_strategy.rs b/src/app_strategy.rs index 0f3a206..c21e6fc 100644 --- a/src/app_strategy.rs +++ b/src/app_strategy.rs @@ -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; + /// Constructs a path inside your application’s configuration directory to which a path of your choice has been appended. fn in_config_dir>(&self, path: P) -> PathBuf { in_dir_method!(self, path, config_dir) diff --git a/src/app_strategy/apple.rs b/src/app_strategy/apple.rs index e3929bb..c01ad69 100644 --- a/src/app_strategy/apple.rs +++ b/src/app_strategy/apple.rs @@ -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 { @@ -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 { + None + } } diff --git a/src/app_strategy/unix.rs b/src/app_strategy/unix.rs index eef25e3..663e0c5 100644 --- a/src/app_strategy/unix.rs +++ b/src/app_strategy/unix.rs @@ -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 { @@ -56,4 +60,8 @@ impl super::AppStrategy for Unix { fn cache_dir(&self) -> PathBuf { self.root_dir.join("cache/") } + + fn state_dir(&self) -> Option { + Some(self.root_dir.join("state/")) + } } diff --git a/src/app_strategy/windows.rs b/src/app_strategy/windows.rs index 7be8b14..eaacacd 100644 --- a/src/app_strategy/windows.rs +++ b/src/app_strategy/windows.rs @@ -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 { @@ -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 { + None + } } diff --git a/src/app_strategy/xdg.rs b/src/app_strategy/xdg.rs index 6318622..4d3d19e 100644 --- a/src/app_strategy/xdg.rs +++ b/src/app_strategy/xdg.rs @@ -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(), @@ -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: @@ -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(), @@ -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: @@ -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(), @@ -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 { @@ -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 { + Some( + self.base_strategy + .state_dir() + .unwrap() + .join(&self.unixy_name), + ) + } } diff --git a/src/base_strategy.rs b/src/base_strategy.rs index 63a7156..dc0c743 100644 --- a/src/base_strategy.rs +++ b/src/base_strategy.rs @@ -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; } macro_rules! create_choose_base_strategy { diff --git a/src/base_strategy/apple.rs b/src/base_strategy/apple.rs index ab6dd93..b7446a5 100644 --- a/src/base_strategy/apple.rs +++ b/src/base_strategy/apple.rs @@ -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 { @@ -50,4 +54,8 @@ impl super::BaseStrategy for Apple { fn cache_dir(&self) -> PathBuf { self.library_path.join("Caches/") } + + fn state_dir(&self) -> Option { + None + } } diff --git a/src/base_strategy/windows.rs b/src/base_strategy/windows.rs index 214778b..aed1f5b 100644 --- a/src/base_strategy/windows.rs +++ b/src/base_strategy/windows.rs @@ -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 { @@ -49,4 +53,8 @@ impl super::BaseStrategy for Windows { fn cache_dir(&self) -> PathBuf { self.appdata.join("Local/") } + + fn state_dir(&self) -> Option { + None + } } diff --git a/src/base_strategy/xdg.rs b/src/base_strategy/xdg.rs index ad85596..785a561 100644 --- a/src/base_strategy/xdg.rs +++ b/src/base_strategy/xdg.rs @@ -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(); /// @@ -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: @@ -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: @@ -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(); /// @@ -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 { @@ -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 { + Some(self.env_var_or_default("XDG_STATE_HOME", ".local/state/")) + } } diff --git a/src/lib.rs b/src/lib.rs index 789aa41..fc3866a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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’). @@ -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: