wordchipper_disk_cache/
path_resolver.rs1use directories_next::ProjectDirs;
6use std::env;
7use std::path::{Path, PathBuf};
8
9pub struct PathResolver {
11 pub qualifier: &'static str,
13
14 pub organization: &'static str,
16
17 pub application: &'static str,
19
20 pub cache_env_vars: &'static [&'static str],
22
23 pub data_env_vars: &'static [&'static str],
25}
26
27impl PathResolver {
28 pub fn project_dirs(&self) -> Option<ProjectDirs> {
30 ProjectDirs::from(self.organization, self.application, self.qualifier)
31 }
32
33 pub fn resolve_cache_dir<P: AsRef<Path>>(
49 &self,
50 path: Option<P>,
51 ) -> Option<PathBuf> {
52 if let Some(path) = path.as_ref() {
53 return Some(path.as_ref().to_path_buf());
54 }
55
56 for env_var in self.cache_env_vars {
57 if let Ok(path) = env::var(env_var) {
58 return Some(PathBuf::from(path));
59 }
60 }
61
62 if let Some(pds) = self.project_dirs() {
63 return Some(pds.cache_dir().to_path_buf());
64 }
65
66 None
67 }
68
69 pub fn resolve_data_dir<P: AsRef<Path>>(
85 &self,
86 path: Option<P>,
87 ) -> Option<PathBuf> {
88 if let Some(path) = path.as_ref() {
89 return Some(path.as_ref().to_path_buf());
90 }
91
92 for env_var in self.data_env_vars {
93 if let Ok(path) = env::var(env_var) {
94 return Some(PathBuf::from(path));
95 }
96 }
97
98 if let Some(pds) = self.project_dirs() {
99 return Some(pds.data_dir().to_path_buf());
100 }
101
102 None
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109 use serial_test::serial;
110
111 const CACHE_ENV1: &str = "_APP_PATH_CACHE_ENV1";
112 const CACHE_ENV2: &str = "_APP_PATH_CACHE_ENV2";
113 const DATA_ENV1: &str = "_APP_PATH_DATA_ENV1";
114 const DATA_ENV2: &str = "_APP_PATH_DATA_ENV2";
115
116 const TEST_CONFIG: PathResolver = PathResolver {
117 qualifier: "io",
118 organization: "crates",
119 application: "example",
120 cache_env_vars: &[CACHE_ENV1, CACHE_ENV2],
121 data_env_vars: &[DATA_ENV1, DATA_ENV2],
122 };
123
124 #[test]
125 #[serial]
126 fn test_resolve_dirs() {
127 let pds = TEST_CONFIG
128 .project_dirs()
129 .expect("failed to get project dirs");
130
131 let no_path: Option<PathBuf> = None;
132
133 let user_cache_dir = PathBuf::from("/tmp/app_cache/cache");
134 let user_data_dir = PathBuf::from("/tmp/app_cache/data");
135
136 let env_cache_dir1 = PathBuf::from("/tmp/app_cache/env_cache.1");
137 let env_cache_dir2 = PathBuf::from("/tmp/app_cache/env_cache.2");
138 let env_data_dir1 = PathBuf::from("/tmp/app_cache/env_data.1");
139 let env_data_dir2 = PathBuf::from("/tmp/app_cache/env_data.2");
140
141 unsafe {
143 for v in TEST_CONFIG.cache_env_vars {
144 env::remove_var(v);
145 }
146 for v in TEST_CONFIG.data_env_vars {
147 env::remove_var(v);
148 }
149 }
150
151 assert_eq!(
153 TEST_CONFIG.resolve_cache_dir(Some(user_cache_dir.clone())),
154 Some(user_cache_dir.clone()),
155 );
156 assert_eq!(
157 TEST_CONFIG.resolve_data_dir(Some(user_data_dir.clone())),
158 Some(user_data_dir.clone()),
159 );
160
161 assert_eq!(
163 TEST_CONFIG.resolve_cache_dir(no_path.clone()),
164 Some(pds.cache_dir().to_path_buf())
165 );
166 assert_eq!(
167 TEST_CONFIG.resolve_data_dir(no_path.clone()),
168 Some(pds.data_dir().to_path_buf())
169 );
170
171 unsafe {
173 env::set_var(CACHE_ENV2, env_cache_dir2.to_str().unwrap());
174 env::set_var(DATA_ENV2, env_data_dir2.to_str().unwrap());
175 }
176
177 assert_eq!(
179 TEST_CONFIG.resolve_cache_dir(Some(user_cache_dir.clone())),
180 Some(user_cache_dir.clone()),
181 );
182 assert_eq!(
183 TEST_CONFIG.resolve_data_dir(Some(user_data_dir.clone())),
184 Some(user_data_dir.clone()),
185 );
186
187 assert_eq!(
189 TEST_CONFIG.resolve_cache_dir(no_path.clone()),
190 Some(env_cache_dir2.clone())
191 );
192 assert_eq!(
193 TEST_CONFIG.resolve_data_dir(no_path.clone()),
194 Some(env_data_dir2.clone())
195 );
196
197 unsafe {
199 env::set_var(CACHE_ENV1, env_cache_dir1.to_str().unwrap());
200 env::set_var(DATA_ENV1, env_data_dir1.to_str().unwrap());
201 }
202
203 assert_eq!(
205 TEST_CONFIG.resolve_cache_dir(Some(user_cache_dir.clone())),
206 Some(user_cache_dir.clone()),
207 );
208 assert_eq!(
209 TEST_CONFIG.resolve_data_dir(Some(user_data_dir.clone())),
210 Some(user_data_dir.clone()),
211 );
212
213 assert_eq!(
215 TEST_CONFIG.resolve_cache_dir(no_path.clone()),
216 Some(env_cache_dir1.clone())
217 );
218 assert_eq!(
219 TEST_CONFIG.resolve_data_dir(no_path.clone()),
220 Some(env_data_dir1.clone())
221 );
222 }
223}