Skip to content

Commit 69d4870

Browse files
committed
Add a way to change the stragey by a function call
1 parent 3544073 commit 69d4870

File tree

2 files changed

+151
-9
lines changed

2 files changed

+151
-9
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ serde_yaml = { version = "0.9", optional = true }
1717
thiserror = "2.0"
1818
basic-toml = { version = "0.1.10", optional = true }
1919
toml = { version = "0.9", optional = true }
20+
lazy_static = "1.5"
2021

2122
[features]
2223
default = ["toml_conf"]

src/lib.rs

Lines changed: 150 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,19 @@
9292
//! [`basic_toml` crate]: https://docs.rs/basic_toml
9393
9494
mod utils;
95+
use etcetera::app_strategy;
9596
use utils::*;
9697

97-
use etcetera::{AppStrategy, AppStrategyArgs, app_strategy::choose_app_strategy};
98+
use etcetera::{
99+
AppStrategy, AppStrategyArgs, app_strategy::choose_app_strategy,
100+
app_strategy::choose_native_strategy,
101+
};
102+
use lazy_static::lazy_static;
98103
use serde::{Serialize, de::DeserializeOwned};
99104
use std::fs::{self, File, OpenOptions, Permissions};
100105
use std::io::{ErrorKind::NotFound, Write};
101106
use std::path::{Path, PathBuf};
107+
use std::sync::Mutex;
102108
use thiserror::Error;
103109

104110
#[cfg(feature = "toml_conf")]
@@ -153,6 +159,10 @@ const EXTENSION: &str = "yml";
153159
#[cfg(feature = "ron_conf")]
154160
const EXTENSION: &str = "ron";
155161

162+
lazy_static! {
163+
static ref STRATEGY: Mutex<ConfigStrategy> = Mutex::new(ConfigStrategy::App);
164+
}
165+
156166
/// The errors the confy crate can encounter.
157167
#[derive(Debug, Error)]
158168
pub enum ConfyError {
@@ -202,6 +212,84 @@ pub enum ConfyError {
202212
SetPermissionsFileError(#[source] std::io::Error),
203213
}
204214

215+
/// Determine what strategy `confy` should use
216+
pub enum ConfigStrategy {
217+
App,
218+
Native,
219+
}
220+
221+
/// Change the strategy to use
222+
///
223+
/// default is the AppStrategy
224+
pub fn change_config_strategy(changer: ConfigStrategy) {
225+
*STRATEGY
226+
.lock()
227+
.expect("Error getting lock on Config Stragey") = changer;
228+
}
229+
230+
enum InternalStrategy {
231+
App(app_strategy::Xdg),
232+
NativeMac(app_strategy::Apple),
233+
NativeUnix(app_strategy::Unix),
234+
NativeWindows(app_strategy::Windows),
235+
}
236+
237+
// we only every access the config dir function
238+
impl AppStrategy for InternalStrategy {
239+
fn home_dir(&self) -> &Path {
240+
unimplemented!()
241+
}
242+
243+
fn config_dir(&self) -> PathBuf {
244+
match self {
245+
InternalStrategy::App(xdg) => xdg.config_dir(),
246+
InternalStrategy::NativeMac(mac) => mac.config_dir(),
247+
InternalStrategy::NativeUnix(unix) => unix.config_dir(),
248+
InternalStrategy::NativeWindows(windows) => windows.config_dir(),
249+
}
250+
}
251+
252+
fn data_dir(&self) -> PathBuf {
253+
unimplemented!()
254+
}
255+
256+
fn cache_dir(&self) -> PathBuf {
257+
unimplemented!()
258+
}
259+
260+
fn state_dir(&self) -> Option<PathBuf> {
261+
unimplemented!()
262+
}
263+
264+
fn runtime_dir(&self) -> Option<PathBuf> {
265+
unimplemented!()
266+
}
267+
}
268+
269+
impl From<app_strategy::Xdg> for InternalStrategy {
270+
fn from(value: app_strategy::Xdg) -> Self {
271+
InternalStrategy::App(value)
272+
}
273+
}
274+
275+
impl From<app_strategy::Apple> for InternalStrategy {
276+
fn from(value: app_strategy::Apple) -> Self {
277+
InternalStrategy::NativeMac(value)
278+
}
279+
}
280+
281+
impl From<app_strategy::Unix> for InternalStrategy {
282+
fn from(value: app_strategy::Unix) -> Self {
283+
InternalStrategy::NativeUnix(value)
284+
}
285+
}
286+
287+
impl From<app_strategy::Windows> for InternalStrategy {
288+
fn from(value: app_strategy::Windows) -> Self {
289+
InternalStrategy::NativeWindows(value)
290+
}
291+
}
292+
205293
/// Load an application configuration from disk
206294
///
207295
/// A new configuration file is created with default values if none
@@ -469,14 +557,29 @@ pub fn get_configuration_file_path<'a>(
469557
config_name: impl Into<Option<&'a str>>,
470558
) -> Result<PathBuf, ConfyError> {
471559
let config_name = config_name.into().unwrap_or("default-config");
472-
let project = choose_app_strategy(AppStrategyArgs {
473-
top_level_domain: "rs".to_string(),
474-
author: "".to_string(),
475-
app_name: app_name.to_string(),
476-
})
477-
.map_err(|e| {
478-
ConfyError::BadConfigDirectory(format!("could not determine home directory path: {e}"))
479-
})?;
560+
let project: InternalStrategy = match *STRATEGY
561+
.lock()
562+
.expect("Error getting lock on config strategy")
563+
{
564+
ConfigStrategy::App => choose_app_strategy(AppStrategyArgs {
565+
top_level_domain: "rs".to_string(),
566+
author: "".to_string(),
567+
app_name: app_name.to_string(),
568+
})
569+
.map_err(|e| {
570+
ConfyError::BadConfigDirectory(format!("could not determine home directory path: {e}"))
571+
})?
572+
.into(),
573+
ConfigStrategy::Native => choose_native_strategy(AppStrategyArgs {
574+
top_level_domain: "rs".to_string(),
575+
author: "".to_string(),
576+
app_name: app_name.to_string(),
577+
})
578+
.map_err(|e| {
579+
ConfyError::BadConfigDirectory(format!("could not determine home directory path: {e}"))
580+
})?
581+
.into(),
582+
};
480583

481584
let config_dir_str = get_configuration_directory_str(&project)?;
482585

@@ -572,6 +675,44 @@ mod tests {
572675
})
573676
}
574677

678+
#[test]
679+
fn test_store_path_native() {
680+
// change the strategy first then the app will always use it
681+
change_config_strategy(ConfigStrategy::Native);
682+
683+
with_config_path(|path| {
684+
let config: ExampleConfig = ExampleConfig {
685+
name: "Test".to_string(),
686+
count: 42,
687+
};
688+
689+
let file_path = get_configuration_file_path("example-app", "example-config").unwrap();
690+
691+
if cfg!(target_os = "macos") {
692+
assert_eq!(
693+
file_path,
694+
Path::new("/Users/rth/Library/Preferences/rs.example-app/example-config.toml"),
695+
);
696+
} else if cfg!(target_os = "linux") {
697+
assert_eq!(
698+
file_path,
699+
Path::new(".config/example-app/example-config.toml")
700+
);
701+
} else {
702+
//windows
703+
assert_eq!(
704+
file_path,
705+
Path::new("AppData/Roaming/example-app/example-config/config"),
706+
);
707+
}
708+
709+
// Make sure it is still the same config file
710+
store_path(path, &config).expect("store_path failed");
711+
let loaded = load_path(path).expect("load_path failed");
712+
assert_eq!(config, loaded);
713+
})
714+
}
715+
575716
/// [`store_path_perms`] stores [`ExampleConfig`], with only read permission for owner (UNIX).
576717
#[test]
577718
#[cfg(unix)]

0 commit comments

Comments
 (0)