project_dirs/
lib.rs

1mod proj_dirs;
2mod project_triplet;
3
4/// Utility functions and traits for project directories
5pub mod dir_utils;
6
7/// Ways of retrieving project directories
8pub mod strategy;
9
10pub use proj_dirs::{FullProjectDirs, MissingError, ProjectDirs};
11
12/// Definition of the project essentials. Allows to retrive project directories
13pub struct Project {
14    /// NOTE: You should rather use qualifier_value
15    _orig_qualifier: String,
16    /// NOTE: You should rather use organization_name
17    _orig_organization: String,
18    /// NOTE: You should rather use application_name
19    _orig_application: String,
20
21    qualifier_value: String,
22    organization_name: String,
23    application_name: String,
24}
25
26/// Purpose of directory existence. Ex. Bin, Config, Cache etc.
27#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, PartialOrd, Ord)]
28#[cfg_attr(feature = "strum", derive(strum::Display, strum::EnumString))]
29#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
30#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
31#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
32pub enum Directory {
33    /// Binaries directory. This is where the project executable(s) is/are located
34    Bin,
35    /// Non-essential data, usually used to speed up the application
36    Cache,
37    /// You can store there conf.d dir and other config files
38    Config,
39    /// Essential files for application like db files, cross-session data etc.
40    Data,
41    /// C/C++ headers files. Should include files like lib.h, lib.hpp or lib.inc
42    Include,
43    /// Shared library files. Should include files like lib.a, lib.so, lib.dylib or lib.dll
44    Lib,
45    /// Application logs. Usually subdir of the state
46    Log,
47    /// Root directory of the project. Has meaning only for the some strategies
48    ProjectRoot,
49    /// Runtime files are similar to the cache, but don't persist between session/reboot
50    Runtime,
51    /// Non-essential data files that should persist between sessions. E.g. logs, history
52    State,
53}
54
55/// Project directories gathered by scope: user, system and local (pwd)
56#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
57#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
58pub struct Scoped {
59    pub user: ProjectDirs,
60    pub system: ProjectDirs,
61    pub local: ProjectDirs,
62}
63
64impl Project {
65    pub fn new(qualifier: &str, organization: &str, application: &str) -> Self {
66        Self {
67            _orig_qualifier: qualifier.to_string(),
68            _orig_organization: organization.to_string(),
69            _orig_application: application.to_string(),
70            qualifier_value: project_triplet::qualifier_cleanup(qualifier),
71            organization_name: project_triplet::name_cleanup(organization),
72            application_name: project_triplet::name_cleanup(application),
73        }
74    }
75
76    /// Get application name for UNIX-like systems (excluding mac)
77    pub fn application_name_unix(&self) -> String {
78        project_triplet::unix_name_cleanup(&self._orig_application)
79    }
80
81    /// Get application name for Windows systems
82    pub fn application_name_windows(&self) -> String {
83        project_triplet::windows_name_cleanup(&self._orig_application)
84    }
85
86    /// Get application name for macOS
87    pub fn application_name_macos(&self) -> String {
88        project_triplet::unix_name_cleanup(&self._orig_application)
89    }
90
91    /// Get organization name for Windows
92    pub fn organization_name_windows(&self) -> String {
93        project_triplet::windows_name_cleanup(&self._orig_organization)
94    }
95
96    /// Get organization_name calculated for the current system
97    pub fn organization_name(&self) -> &str {
98        &self.organization_name
99    }
100
101    /// Get application_name calculated for the current system
102    pub fn application_name(&self) -> &str {
103        &self.application_name
104    }
105
106    /// Get qualifier calculated for the current system
107    pub fn qualifier(&self) -> &str {
108        &self.qualifier_value
109    }
110
111    #[cfg(all(target_family = "unix", not(target_os = "macos")))]
112    fn unix_project_dirs(&self) -> Scoped {
113        use crate::strategy::fhs::Fhs;
114        use crate::strategy::unix::Unix;
115        use crate::strategy::xdg::{Xdg, XdgEnv};
116
117        Scoped {
118            user: self
119                .xdg_with_env(XdgEnv::new_system())
120                .map(|x| x.into())
121                .unwrap_or(ProjectDirs::empty()),
122            system: self.fhs().into(),
123            local: self
124                .unix_pwd()
125                .map(Into::into)
126                .unwrap_or(ProjectDirs::empty()),
127        }
128    }
129
130    #[cfg(target_os = "windows")]
131    fn windows_project_dirs(&self) -> Scoped {
132        use crate::strategy::unix::Unix;
133
134        use crate::strategy::windows::{Windows, WindowsEnv};
135        let windows_env = WindowsEnv::new_system();
136        Scoped {
137            user: self.windows_user_with_env(windows_env.clone()),
138            system: self.windows_system_with_env(windows_env),
139            local: self
140                .unix_pwd()
141                .map(Into::into)
142                .unwrap_or(ProjectDirs::empty()),
143        }
144    }
145
146    pub fn project_dirs(&self) -> Scoped {
147        #[cfg(all(target_family = "unix", not(target_os = "macos")))]
148        {
149            self.unix_project_dirs()
150        }
151        #[cfg(all(target_family = "unix", target_os = "macos"))]
152        {
153            todo!()
154        }
155        #[cfg(target_family = "windows")]
156        {
157            self.windows_project_dirs()
158        }
159    }
160}