Skip to main content

dotstore/
lib.rs

1//! Library to create dot directories in common system places.
2//!
3//! It's essentially a wrapper around the [`dirs`] crate that allows you to create dot directories
4//! (e.g. /home/user/.project-name) in common places (e.g. Home dir, Config dir etc.) to store program data and configs.
5//!
6//! You can also create them in custom locations
7//!
8//! # Examples
9//!
10//! ```rust,no_run
11//! use dotstore;
12//!
13//! fn main() -> std::io::Result<()> {
14//!     // Create a new directory called `/home/user/.barracuda`
15//!     // The `.` is automatically appended
16//!     let project_dir = dotstore::home_store("barracuda")?;
17//!
18//!     // Create a new directory called `/home/user/.config/.editor`
19//!     let editor_dir = dotstore::config_store("editor")?;
20//!
21//!     // Create a new directory called `/home/user/workspace/middle-earth/.eregion`
22//!     let custom_dir = dotstore::custom_store("/home/user/workspace/middle-earth", "eregion")?;
23//!
24//!     Ok(())
25//! }
26//! ```
27
28use dirs;
29use std::{
30    fs, io,
31    path::{Path, PathBuf},
32};
33
34#[derive(Debug, PartialEq, Eq)]
35enum StoreType {
36    Home,
37    Config,
38    ConfigLocal,
39    Executable,
40    Audio,
41    Cache,
42    Data,
43    DataLocal,
44    Desktop,
45    Download,
46    Document,
47    Font,
48    Picture,
49    Preference,
50    Public,
51    Runtime,
52    State,
53    Template,
54    Video,
55}
56
57impl StoreType {
58    pub fn path(&self) -> fn() -> Option<PathBuf> {
59        match *self {
60            Self::Home => dirs::home_dir,
61            Self::Config => dirs::config_dir,
62            Self::ConfigLocal => dirs::config_local_dir,
63            Self::Executable => dirs::executable_dir,
64            Self::Audio => dirs::audio_dir,
65            Self::Cache => dirs::cache_dir,
66            Self::Data => dirs::data_dir,
67            Self::DataLocal => dirs::data_local_dir,
68            Self::Desktop => dirs::desktop_dir,
69            Self::Download => dirs::download_dir,
70            Self::Document => dirs::document_dir,
71            Self::Font => dirs::font_dir,
72            Self::Picture => dirs::picture_dir,
73            Self::Preference => dirs::preference_dir,
74            Self::Public => dirs::public_dir,
75            Self::Runtime => dirs::runtime_dir,
76            Self::State => dirs::state_dir,
77            Self::Template => dirs::template_dir,
78            Self::Video => dirs::video_dir,
79        }
80    }
81}
82
83fn create_dir(path: &PathBuf) -> io::Result<()> {
84    if !path.exists() {
85        fs::create_dir_all(&path)?;
86    }
87
88    Ok(())
89}
90
91fn create_store(store: StoreType, path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
92    let dir_fn = store.path();
93    if let Some(root) = dir_fn() {
94        let store_dir = root.join(format!(".{}", path.as_ref().display()));
95        create_dir(&store_dir)?;
96
97        Ok(Some(store_dir))
98    } else {
99        Ok(None)
100    }
101}
102
103/// Creates a new dot directory in the systems Audio path (See [`dirs::audio_dir`])
104pub fn audio_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
105    create_store(StoreType::Audio, path)
106}
107
108/// Creates a new dot directory in the systems Cache path (See [`dirs::cache_dir`])
109pub fn cache_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
110    create_store(StoreType::Cache, path)
111}
112
113/// Creates a new dot directory in the systems Config path (See [`dirs::config_dir`])
114pub fn config_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
115    create_store(StoreType::Config, path)
116}
117
118/// Creates a new dot directory in the systems local Config path (See [`dirs::config_local_dir`])
119pub fn local_config_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
120    create_store(StoreType::ConfigLocal, path)
121}
122
123/// Creates a new dot directory in the systems Data path (See [`dirs::data_dir`])
124pub fn data_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
125    create_store(StoreType::Data, path)
126}
127
128/// Creates a new dot directory in the systems local Data path (See [`dirs::data_local_dir`])
129pub fn local_data_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
130    create_store(StoreType::DataLocal, path)
131}
132
133/// Creates a new dot directory in the systems Desktop path (See [`dirs::desktop_dir`])
134pub fn desktop_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
135    create_store(StoreType::Desktop, path)
136}
137
138/// Creates a new dot directory in the systems Document path (See [`dirs::document_dir`])
139pub fn document_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
140    create_store(StoreType::Document, path)
141}
142
143/// Creates a new dot directory in the systems Download path (See [`dirs::download_dir`])
144pub fn download_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
145    create_store(StoreType::Download, path)
146}
147
148/// Creates a new dot directory in the systems Executable path (See [`dirs::executable_dir`])
149pub fn executable_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
150    create_store(StoreType::Executable, path)
151}
152
153/// Creates a new dot directory in the systems Font path (See [`dirs::font_dir`])
154pub fn font_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
155    create_store(StoreType::Font, path)
156}
157
158/// Creates a new dot directory in the systems Home path (See [`dirs::home_dir`])
159pub fn home_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
160    create_store(StoreType::Home, path)
161}
162
163/// Creates a new dot directory in the systems Picture path (See [`dirs::picture_dir`])
164pub fn picture_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
165    create_store(StoreType::Picture, path)
166}
167
168/// Creates a new dot directory in the systems Preference path (See [`dirs::picture_dir`])
169pub fn preference_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
170    create_store(StoreType::Preference, path)
171}
172
173/// Creates a new dot directory in the systems Public path (See [`dirs::public_dir`])
174pub fn public_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
175    create_store(StoreType::Public, path)
176}
177
178/// Creates a new dot directory in the systems Runtime path (See [`dirs::runtime_dir`])
179pub fn runtime_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
180    create_store(StoreType::Runtime, path)
181}
182
183/// Creates a new dot directory in the systems State path (See [`dirs::runtime_dir`])
184pub fn state_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
185    create_store(StoreType::State, path)
186}
187
188/// Creates a new dot directory in the systems Template path (See [`dirs::template_dir`])
189pub fn template_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
190    create_store(StoreType::Template, path)
191}
192
193/// Creates a new dot directory in the systems Video path (See [`dirs::video_dir`])
194pub fn video_store(path: impl AsRef<Path>) -> io::Result<Option<PathBuf>> {
195    create_store(StoreType::Video, path)
196}
197
198/// Create a new dot directory in a custom location of your choosing.
199///
200/// # Argments
201///
202/// * `root_path`: The root directory to create the target
203/// * `target`: The name of the dot directory or path to create
204///
205/// # Examples
206///
207/// ```rust,no_run
208/// use dotstore;
209///
210/// fn main() -> std::io::Result<()> {
211///     // Create a new dot directory in a specified location
212///     // Will create `/home/user/project/config/.app`
213///     let path = dotstore::custom_store("/home/user/project/config", "app")?;
214///
215///     // Will create `/home/user/project/.settings/user/local`
216///     let another_path = dotstore::custom_store("/home/user/project", "settings/user/local")?;
217/// }
218/// ```
219pub fn custom_store(
220    root_path: impl AsRef<Path>,
221    target: impl AsRef<Path>,
222) -> io::Result<Option<PathBuf>> {
223    let root = PathBuf::from(root_path.as_ref());
224    let store_dir = root.join(format!(".{}", target.as_ref().display()));
225    create_dir(&store_dir)?;
226
227    Ok(Some(store_dir))
228}