Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add home_dir function & re-exports #9

Merged
merged 2 commits into from
Apr 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/app_strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ pub trait AppStrategy: Sized {
/// The constructor requires access to some basic information about your application.
fn new(args: AppStrategyArgs) -> Result<Self, Self::CreationError>;

/// Gets the home directory of the current user.
fn home_dir(&self) -> &Path;

/// Gets the configuration directory for your application.
fn config_dir(&self) -> PathBuf;

Expand Down
10 changes: 9 additions & 1 deletion src/app_strategy/apple.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::base_strategy;
use crate::base_strategy::BaseStrategy;
use std::path::PathBuf;
use std::path::{Path, PathBuf};

/// This is the strategy created by Apple for use on macOS and iOS devices. It is always used by GUI apps on macOS, and is sometimes used by command-line applications there too. iOS only has GUIs, so all iOS applications follow this strategy. The specification is available [here](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW1).
///
Expand All @@ -19,6 +19,10 @@ use std::path::PathBuf;
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// app_strategy.home_dir(),
/// &home_dir
/// );
/// assert_eq!(
/// app_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Preferences/org.acmecorp.FrobnicatorPlus/"))
/// );
Expand Down Expand Up @@ -55,6 +59,10 @@ impl super::AppStrategy for Apple {
})
}

fn home_dir(&self) -> &Path {
self.base_strategy.home_dir()
}

fn config_dir(&self) -> PathBuf {
self.base_strategy.config_dir().join(&self.bundle_id)
}
Expand Down
29 changes: 19 additions & 10 deletions src/app_strategy/unix.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};

/// This strategy has no standard or official specification. It has arisen over time through hundreds of Unixy tools. Vim and Cargo are notable examples whose configuration/data/cache directory layouts are similar to those created by this strategy.
///
Expand All @@ -17,6 +17,10 @@ use std::path::PathBuf;
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// app_strategy.home_dir(),
/// &home_dir
/// );
/// assert_eq!(
/// app_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".frobnicator-plus/"))
/// );
Expand All @@ -40,36 +44,41 @@ use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Unix {
// This is `.frobnicator-plus` in the above example.
root_dir: PathBuf,
home_dir: PathBuf,
unixy_name: String,
}

impl super::AppStrategy for Unix {
type CreationError = crate::HomeDirError;

fn new(args: super::AppStrategyArgs) -> Result<Self, Self::CreationError> {
let mut root_dir = crate::home_dir()?;
root_dir.push(format!(".{}", args.unixy_name()));
Ok(Self {
home_dir: crate::home_dir()?,
unixy_name: format!(".{}", args.unixy_name()),
})
}

Ok(Self { root_dir })
fn home_dir(&self) -> &Path {
&self.home_dir
}

fn config_dir(&self) -> PathBuf {
self.root_dir.clone()
self.home_dir.join(&self.unixy_name)
}

fn data_dir(&self) -> PathBuf {
self.root_dir.join("data/")
self.home_dir.join(&self.unixy_name).join("data/")
}

fn cache_dir(&self) -> PathBuf {
self.root_dir.join("cache/")
self.home_dir.join(&self.unixy_name).join("cache/")
}

fn state_dir(&self) -> Option<PathBuf> {
Some(self.root_dir.join("state/"))
Some(self.home_dir.join(&self.unixy_name).join("state/"))
}

fn runtime_dir(&self) -> Option<PathBuf> {
Some(self.root_dir.join("runtime/"))
Some(self.home_dir.join(&self.unixy_name).join("runtime/"))
}
}
10 changes: 9 additions & 1 deletion src/app_strategy/windows.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::base_strategy;
use crate::base_strategy::BaseStrategy;
use std::path::PathBuf;
use std::path::{Path, PathBuf};

/// This strategy follows Windows’ conventions. It seems that all Windows GUI apps, and some command-line ones follow this pattern. The specification is available [here](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
///
Expand All @@ -19,6 +19,10 @@ use std::path::PathBuf;
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// app_strategy.home_dir(),
/// &home_dir
/// );
/// assert_eq!(
/// app_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new("AppData/Roaming/Acme Corp/Frobnicator Plus/config"))
/// );
Expand Down Expand Up @@ -65,6 +69,10 @@ impl super::AppStrategy for Windows {
})
}

fn home_dir(&self) -> &Path {
self.base_strategy.home_dir()
}

fn config_dir(&self) -> PathBuf {
dir_method!(self, config_dir, "config/")
}
Expand Down
10 changes: 9 additions & 1 deletion src/app_strategy/xdg.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::base_strategy;
use crate::base_strategy::BaseStrategy;
use std::path::PathBuf;
use std::path::{Path, PathBuf};

/// This strategy implements the [XDG Base Directories Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html). It is the most common on Linux, but is increasingly being adopted elsewhere.
///
Expand Down Expand Up @@ -28,6 +28,10 @@ use std::path::PathBuf;
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// app_strategy.home_dir(),
/// &home_dir
/// );
/// assert_eq!(
/// app_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".config/frobnicator-plus/"))
/// );
Expand Down Expand Up @@ -179,6 +183,10 @@ impl super::AppStrategy for Xdg {
})
}

fn home_dir(&self) -> &Path {
self.base_strategy.home_dir()
}

fn config_dir(&self) -> PathBuf {
self.base_strategy.config_dir().join(&self.unixy_name)
}
Expand Down
5 changes: 4 additions & 1 deletion src/base_strategy.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! These strategies simply provide the user’s configuration, data, and cache directories, without knowing about the application specifically.

use std::path::PathBuf;
use std::path::{Path, PathBuf};

/// Provides configuration, data, and cache directories of the current user.
pub trait BaseStrategy: Sized {
Expand All @@ -10,6 +10,9 @@ pub trait BaseStrategy: Sized {
/// Base strategies are constructed without knowledge of the application.
fn new() -> Result<Self, Self::CreationError>;

/// Gets the home directory of the current user.
fn home_dir(&self) -> &Path;

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

Expand Down
23 changes: 15 additions & 8 deletions src/base_strategy/apple.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};

/// This is the strategy created by Apple for use on macOS and iOS devices. It is always used by GUI apps on macOS, and is sometimes used by command-line applications there too. iOS only has GUIs, so all iOS applications follow this strategy. The specification is available [here](https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html#//apple_ref/doc/uid/TP40010672-CH2-SW1).
///
Expand All @@ -12,6 +12,10 @@ use std::path::PathBuf;
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// base_strategy.home_dir(),
/// &home_dir
/// );
/// assert_eq!(
/// base_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new("Library/Preferences/"))
/// );
Expand All @@ -34,29 +38,32 @@ use std::path::PathBuf;
/// ```
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Apple {
library_path: PathBuf,
home_dir: PathBuf,
}

impl super::BaseStrategy for Apple {
type CreationError = crate::HomeDirError;

fn new() -> Result<Self, Self::CreationError> {
let mut library_path = crate::home_dir()?;
library_path.push("Library/");
Ok(Self {
home_dir: crate::home_dir()?,
})
}

Ok(Self { library_path })
fn home_dir(&self) -> &Path {
&self.home_dir
}

fn config_dir(&self) -> PathBuf {
self.library_path.join("Preferences/")
self.home_dir.join("Library/Preferences/")
}

fn data_dir(&self) -> PathBuf {
self.library_path.join("Application Support/")
self.home_dir.join("Library/Application Support/")
}

fn cache_dir(&self) -> PathBuf {
self.library_path.join("Caches/")
self.home_dir.join("Library/Caches/")
}

fn state_dir(&self) -> Option<PathBuf> {
Expand Down
20 changes: 14 additions & 6 deletions src/base_strategy/windows.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::path::PathBuf;
use std::path::{Path, PathBuf};

/// This strategy follows Windows’ conventions. It seems that all Windows GUI apps, and some command-line ones follow this pattern. The specification is available [here](https://docs.microsoft.com/en-us/windows/win32/shell/knownfolderid).
///
Expand All @@ -12,6 +12,10 @@ use std::path::PathBuf;
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// base_strategy.home_dir(),
/// &home_dir
/// );
/// assert_eq!(
/// base_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new("AppData/Roaming/"))
/// );
Expand All @@ -34,28 +38,32 @@ use std::path::PathBuf;
/// ```
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Windows {
appdata: PathBuf,
home_dir: PathBuf,
}

impl super::BaseStrategy for Windows {
type CreationError = crate::HomeDirError;

fn new() -> Result<Self, Self::CreationError> {
Ok(Self {
appdata: crate::home_dir()?.join("AppData/"),
home_dir: crate::home_dir()?,
})
}

fn home_dir(&self) -> &Path {
&self.home_dir
}

fn config_dir(&self) -> PathBuf {
self.appdata.join("Roaming/")
self.home_dir.join("AppData/Roaming/")
}

fn data_dir(&self) -> PathBuf {
self.appdata.join("Roaming/")
self.home_dir.join("AppData/Roaming/")
}

fn cache_dir(&self) -> PathBuf {
self.appdata.join("Local/")
self.home_dir.join("AppData/Local/")
}

fn state_dir(&self) -> Option<PathBuf> {
Expand Down
16 changes: 16 additions & 0 deletions src/base_strategy/xdg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ use std::path::PathBuf;
/// let home_dir = etcetera::home_dir().unwrap();
///
/// assert_eq!(
/// base_strategy.home_dir(),
/// &home_dir
/// );
/// assert_eq!(
/// base_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".config/"))
/// );
Expand Down Expand Up @@ -86,6 +90,10 @@ use std::path::PathBuf;
/// let base_strategy = Xdg::new().unwrap();
///
/// assert_eq!(
/// base_strategy.home_dir(),
/// etcetera::home_dir().unwrap()
/// );
/// assert_eq!(
/// base_strategy.config_dir(),
/// Path::new(config_path)
/// );
Expand Down Expand Up @@ -127,6 +135,10 @@ use std::path::PathBuf;
///
/// // We still get the default values.
/// assert_eq!(
/// base_strategy.home_dir(),
/// &home_dir
/// );
/// assert_eq!(
/// base_strategy.config_dir().strip_prefix(&home_dir),
/// Ok(Path::new(".config/"))
/// );
Expand Down Expand Up @@ -180,6 +192,10 @@ impl super::BaseStrategy for Xdg {
})
}

fn home_dir(&self) -> &Path {
&self.home_dir
}

fn config_dir(&self) -> PathBuf {
self.env_var_or_default("XDG_CONFIG_HOME", ".config/")
}
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@
pub mod app_strategy;
pub mod base_strategy;

pub use app_strategy::{choose_app_strategy, AppStrategy, AppStrategyArgs};
pub use base_strategy::{choose_base_strategy, BaseStrategy};

/// A convenience function that wraps the [`home_dir`](https://docs.rs/home/0.5.4/home/fn.home_dir.html) function from the [home](https://docs.rs/home) crate.
pub fn home_dir() -> Result<std::path::PathBuf, HomeDirError> {
home::home_dir().ok_or(HomeDirError)
Expand Down