Skip to content

Commit

Permalink
Enhance Readme & Docs + couple of bug fixes (#6)
Browse files Browse the repository at this point in the history
* app_strategy/apple: remove spaces from bundle_id

* app_strategy: add in_state_dir/in_runtime_dir

* Remove thiserror dependency

* Add crate keywords

* Enhance Readme & Docs
  • Loading branch information
utkarshgupta137 authored Apr 21, 2023
1 parent a811a68 commit 5ed9bc0
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 106 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
[package]
categories = ["config"]
description = "An unopinionated library for obtaining configuration, data and cache directories"
description = "An unopinionated library for obtaining configuration, data, cache, & other directories"
documentation = "https://docs.rs/etcetera"
edition = "2018"
homepage = "https://github.com/lunacookies/etcetera"
keywords = ["xdg", "dirs", "directories", "directory", "basedir", "app_dirs", "cli_dirs", "config", "path", "folder"]
license = "MIT OR Apache-2.0"
name = "etcetera"
readme = "README.md"
Expand All @@ -13,4 +14,3 @@ version = "0.5.0"
[dependencies]
cfg-if = "1.0.0"
home = "0.5.4"
thiserror = "1.0.22"
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,36 @@
[![crates.io version](https://img.shields.io/crates/v/etcetera?style=for-the-badge)](https://crates.io/crates/etcetera)
[![crates.io revdeps](https://img.shields.io/crates/d/etcetera?style=for-the-badge)](https://crates.io/crates/etcetera/reverse_dependencies)
[![documentation](https://img.shields.io/docsrs/etcetera?style=for-the-badge)](https://docs.rs/etcetera)
![license](https://img.shields.io/crates/l/etcetera?style=for-the-badge)

# Etcetera

This is a Rust library that aims to allow you to determine the locations of configuration, cache and data files for your application. Existing Rust libraries generally do not give you a choice in terms of which standards/conventions (Etcetera calls these ‘strategies’) they follow. Etcetera, on the other hand, gives you the choice.
This is a Rust library that allows you to determine the locations of configuration, data, cache & other files for your application. Existing Rust libraries generally do not give you a choice in terms of which standards/conventions (Etcetera calls these ‘strategies’) they follow. Etcetera, on the other hand, gives you the choice.

Etcetera supports the following strategies:
- the [XDG base directory](https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html)
- the [Known Folder Locations](https://msdn.microsoft.com/en-us/library/windows/desktop/dd378457.aspx)
- the [Standard Directories](https://developer.apple.com/library/content/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html)
- the "Unix Single-folder Strategy" i.e. everything in `~/.myapp`

Etcetera has 2 modes of operation: `BaseStrategy` & `AppStrategy`:
- With `BaseStrategy`, you just get the location of the respective directory. For eg. for `config_dir()`:
- XDG: `~/.config`
- Apple: `~/Library/Preferences`
- Windows: `~\AppData\Roaming`
- With `AppStrategy`, you provide additional information to get the location of your app directory.
For eg. if you provide the following details: `{ top_level_domain: "org", author: "Acme Corp", app_name: "Frobnicator Plus" }`, you'll get:
- XDG: `~/.config/frobnicator-plus`
- Unix: `~/.frobnicator-plus`
- Apple: `~/Library/Preferences/org.acmecorp.FrobnicatorPlus`
- Windows: `~\AppData\Roaming\Acme Corp\Frobnicator Plus`

Note: the location of the home (~) is determined by the [`home`](https://docs.rs/home/0.5.4/home/fn.home_dir.html) crate.

Etcetera also provides convenience functions for selecting the appropriate strategy on each platform:
- `base_strategy::choose_base_strategy` & `app_strategy::choose_app_strategy`: Uses `Windows` on Windows & `XDG` everywhere else.
This is used by most CLI tools & some GUI tools on each platform.
- `base_strategy::choose_native_strategy` & `app_strategy::choose_native_strategy`: Uses `Windows` on Windows, `Apple` on macOS/iOS, & `XDG` everywhere else.
This is used by most GUI applications on each platform.

See the documentation for more.
See the documentation for examples.
30 changes: 22 additions & 8 deletions src/app_strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ impl AppStrategyArgs {
/// use etcetera::app_strategy::AppStrategyArgs;
///
/// let strategy_args = AppStrategyArgs {
/// top_level_domain: "com".to_string(),
/// author: "Apple".to_string(),
/// app_name: "Safari".to_string(),
/// top_level_domain: "org".to_string(),
/// author: "Acme Corp".to_string(),
/// app_name: "Frobnicator Plus".to_string(),
/// };
///
/// assert_eq!(strategy_args.bundle_id(), "com.apple.Safari".to_string());
/// assert_eq!(strategy_args.bundle_id().replace(' ', ""), "org.acmecorp.FrobnicatorPlus".to_string());
/// ```
pub fn bundle_id(&self) -> String {
format!(
Expand All @@ -45,11 +45,11 @@ impl AppStrategyArgs {
///
/// let strategy_args = AppStrategyArgs {
/// top_level_domain: "org".to_string(),
/// author: "Mozilla".to_string(),
/// app_name: "Firefox Developer Edition".to_string(),
/// author: "Acme Corp".to_string(),
/// app_name: "Frobnicator Plus".to_string(),
/// };
///
/// assert_eq!(strategy_args.unixy_name(), "firefox-developer-edition".to_string());
/// assert_eq!(strategy_args.unixy_name(), "frobnicator-plus".to_string());
/// ```
pub fn unixy_name(&self) -> String {
self.app_name.to_lowercase().replace(' ', "-")
Expand All @@ -60,9 +60,13 @@ macro_rules! in_dir_method {
($self: ident, $path_extra: expr, $dir_method_name: ident) => {{
let mut path = $self.$dir_method_name();
path.push(Path::new(&$path_extra));

path
}};
(opt: $self: ident, $path_extra: expr, $dir_method_name: ident) => {{
let mut path = $self.$dir_method_name()?;
path.push(Path::new(&$path_extra));
Some(path)
}};
}

/// Allows applications to retrieve the paths of configuration, data and cache directories specifically for them.
Expand Down Expand Up @@ -104,6 +108,16 @@ pub trait AppStrategy: Sized {
fn in_cache_dir<P: AsRef<OsStr>>(&self, path: P) -> PathBuf {
in_dir_method!(self, path, cache_dir)
}

/// Constructs a path inside your application’s state directory to which a path of your choice has been appended.
fn in_state_dir<P: AsRef<OsStr>>(&self, path: P) -> Option<PathBuf> {
in_dir_method!(opt: self, path, state_dir)
}

/// Constructs a path inside your application’s runtime directory to which a path of your choice has been appended.
fn in_runtime_dir<P: AsRef<OsStr>>(&self, path: P) -> Option<PathBuf> {
in_dir_method!(opt: self, path, runtime_dir)
}
}

macro_rules! create_strategies {
Expand Down
20 changes: 10 additions & 10 deletions src/app_strategy/apple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,25 @@ use std::path::PathBuf;
/// use std::path::Path;
///
/// let app_strategy = Apple::new(AppStrategyArgs {
/// top_level_domain: "com".to_string(),
/// author: "Apple".to_string(),
/// app_name: "Safari".to_string(),
/// top_level_domain: "org".to_string(),
/// author: "Acme Corp".to_string(),
/// app_name: "Frobnicator Plus".to_string(),
/// }).unwrap();
///
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// app_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Preferences/com.apple.Safari/")
/// ));
/// Ok(Path::new("Library/Preferences/org.acmecorp.FrobnicatorPlus/"))
/// );
/// assert_eq!(
/// app_strategy.data_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Application Support/com.apple.Safari/")
/// ));
/// Ok(Path::new("Library/Application Support/org.acmecorp.FrobnicatorPlus/"))
/// );
/// assert_eq!(
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Caches/com.apple.Safari/")
/// ));
/// Ok(Path::new("Library/Caches/org.acmecorp.FrobnicatorPlus/"))
/// );
/// assert_eq!(
/// app_strategy.state_dir(),
/// None
Expand All @@ -51,7 +51,7 @@ impl super::AppStrategy for Apple {
fn new(args: super::AppStrategyArgs) -> Result<Self, Self::CreationError> {
Ok(Self {
base_strategy: base_strategy::Apple::new()?,
bundle_id: args.bundle_id(),
bundle_id: args.bundle_id().replace(' ', ""),
})
}

Expand Down
26 changes: 13 additions & 13 deletions src/app_strategy/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,36 @@ use std::path::PathBuf;
///
/// let app_strategy = Unix::new(AppStrategyArgs {
/// top_level_domain: "org".to_string(),
/// author: "Bram Moolenar".to_string(),
/// app_name: "Vim".to_string(),
/// author: "Acme Corp".to_string(),
/// app_name: "Frobnicator Plus".to_string(),
/// }).unwrap();
///
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// app_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".vim/")
/// ));
/// Ok(Path::new(".frobnicator-plus/"))
/// );
/// assert_eq!(
/// app_strategy.data_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".vim/data/")
/// ));
/// Ok(Path::new(".frobnicator-plus/data/"))
/// );
/// assert_eq!(
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".vim/cache/")
/// ));
/// Ok(Path::new(".frobnicator-plus/cache/"))
/// );
/// assert_eq!(
/// app_strategy.state_dir().unwrap().strip_prefix(&home_dir),
/// Ok(Path::new(".vim/state/")
/// ));
/// Ok(Path::new(".frobnicator-plus/state/"))
/// );
/// assert_eq!(
/// app_strategy.runtime_dir().unwrap().strip_prefix(&home_dir),
/// Ok(Path::new(".vim/runtime/")
/// ));
/// Ok(Path::new(".frobnicator-plus/runtime/"))
/// );
/// ```
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Unix {
// This is `.vim` in the above example.
// This is `.frobnicator-plus` in the above example.
root_dir: PathBuf,
}

Expand Down
12 changes: 6 additions & 6 deletions src/app_strategy/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,24 @@ use std::path::PathBuf;
/// use std::path::Path;
///
/// let app_strategy = Windows::new(AppStrategyArgs {
/// top_level_domain: "com".to_string(),
/// author: "Microsoft".to_string(),
/// app_name: "File Explorer".to_string(),
/// top_level_domain: "org".to_string(),
/// author: "Acme Corp".to_string(),
/// app_name: "Frobnicator Plus".to_string(),
/// }).unwrap();
///
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// app_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new("AppData/Roaming/Microsoft/File Explorer/config"))
/// Ok(Path::new("AppData/Roaming/Acme Corp/Frobnicator Plus/config"))
/// );
/// assert_eq!(
/// app_strategy.data_dir().strip_prefix(&home_dir),
/// Ok(Path::new("AppData/Roaming/Microsoft/File Explorer/data"))
/// Ok(Path::new("AppData/Roaming/Acme Corp/Frobnicator Plus/data"))
/// );
/// assert_eq!(
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new("AppData/Local/Microsoft/File Explorer/cache"))
/// Ok(Path::new("AppData/Local/Acme Corp/Frobnicator Plus/cache"))
/// );
/// assert_eq!(
/// app_strategy.state_dir(),
Expand Down
75 changes: 45 additions & 30 deletions src/app_strategy/xdg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,29 @@ use std::path::PathBuf;
/// std::env::remove_var("XDG_RUNTIME_DIR");
///
/// let app_strategy = Xdg::new(AppStrategyArgs {
/// top_level_domain: "hm".to_string(),
/// author: "hisham".to_string(),
/// app_name: "htop".to_string(),
/// top_level_domain: "org".to_string(),
/// author: "Acme Corp".to_string(),
/// app_name: "Frobnicator Plus".to_string(),
/// }).unwrap();
///
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// app_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".config/htop/")
/// ));
/// Ok(Path::new(".config/frobnicator-plus/"))
/// );
/// assert_eq!(
/// app_strategy.data_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".local/share/htop/")
/// ));
/// Ok(Path::new(".local/share/frobnicator-plus/"))
/// );
/// assert_eq!(
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".cache/htop/")
/// ));
/// Ok(Path::new(".cache/frobnicator-plus/"))
/// );
/// assert_eq!(
/// app_strategy.state_dir().unwrap().strip_prefix(&home_dir),
/// Ok(Path::new(".local/state/htop/")
/// ));
/// Ok(Path::new(".local/state/frobnicator-plus/"))
/// );
/// assert_eq!(
/// app_strategy.runtime_dir(),
/// None
Expand Down Expand Up @@ -91,16 +91,31 @@ use std::path::PathBuf;
/// std::env::set_var("XDG_RUNTIME_DIR", runtime_path);
///
/// let app_strategy = Xdg::new(AppStrategyArgs {
/// top_level_domain: "hm".to_string(),
/// author: "hisham".to_string(),
/// app_name: "htop".to_string(),
/// top_level_domain: "org".to_string(),
/// author: "Acme Corp".to_string(),
/// app_name: "Frobnicator Plus".to_string(),
/// }).unwrap();
///
/// 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)));
/// assert_eq!(app_strategy.runtime_dir().unwrap(), Path::new(&format!("{}/htop/", runtime_path)));
/// assert_eq!(
/// app_strategy.config_dir(),
/// Path::new(&format!("{}/frobnicator-plus/", config_path))
/// );
/// assert_eq!(
/// app_strategy.data_dir(),
/// Path::new(&format!("{}/frobnicator-plus/", data_path))
/// );
/// assert_eq!(
/// app_strategy.cache_dir(),
/// Path::new(&format!("{}/frobnicator-plus/", cache_path))
/// );
/// assert_eq!(
/// app_strategy.state_dir().unwrap(),
/// Path::new(&format!("{}/frobnicator-plus/", state_path))
/// );
/// assert_eq!(
/// app_strategy.runtime_dir().unwrap(),
/// Path::new(&format!("{}/frobnicator-plus/", runtime_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 @@ -119,30 +134,30 @@ use std::path::PathBuf;
/// std::env::set_var("XDG_RUNTIME_DIR", "relative_path/");
///
/// let app_strategy = Xdg::new(AppStrategyArgs {
/// top_level_domain: "hm".to_string(),
/// author: "hisham".to_string(),
/// app_name: "htop".to_string(),
/// top_level_domain: "org".to_string(),
/// author: "Acme Corp".to_string(),
/// app_name: "Frobnicator Plus".to_string(),
/// }).unwrap();
///
/// let home_dir = etcetera::home_dir().unwrap();
///
/// // We still get the default values.
/// assert_eq!(
/// app_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".config/htop/")
/// ));
/// Ok(Path::new(".config/frobnicator-plus/"))
/// );
/// assert_eq!(
/// app_strategy.data_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".local/share/htop/")
/// ));
/// Ok(Path::new(".local/share/frobnicator-plus/"))
/// );
/// assert_eq!(
/// app_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".cache/htop/")
/// ));
/// Ok(Path::new(".cache/frobnicator-plus/"))
/// );
/// assert_eq!(
/// app_strategy.state_dir().unwrap().strip_prefix(&home_dir),
/// Ok(Path::new(".local/state/htop/")
/// ));
/// Ok(Path::new(".local/state/frobnicator-plus/"))
/// );
/// assert_eq!(
/// app_strategy.runtime_dir(),
/// None
Expand Down
12 changes: 6 additions & 6 deletions src/base_strategy/apple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ use std::path::PathBuf;
///
/// assert_eq!(
/// base_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Preferences/")
/// ));
/// Ok(Path::new("Library/Preferences/"))
/// );
/// assert_eq!(
/// base_strategy.data_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Application Support/")
/// ));
/// Ok(Path::new("Library/Application Support/"))
/// );
/// assert_eq!(
/// base_strategy.cache_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Caches/")
/// ));
/// Ok(Path::new("Library/Caches/"))
/// );
/// assert_eq!(
/// base_strategy.state_dir(),
/// None
Expand Down
Loading

0 comments on commit 5ed9bc0

Please sign in to comment.