use std::env; use std::io::{Error, ErrorKind, Result}; use std::path::PathBuf; pub struct Configuration { // Default Base Directories, default to XDG dirs but can be pub output_directory: PathBuf, } impl Configuration { pub fn new() -> Result { let output_directory = Configuration::directory("PAGE_OUTPUT_DIRECTORY", "XDG_CACHE_HOME", ".cache", "page")?; Ok(Configuration { output_directory }) } fn directory( user_override: &str, default_value: &str, home_fallback: &str, path: &str, ) -> Result { match env::var(user_override) { Ok(directory) => Ok(PathBuf::from(directory).join(path)), Err(_) => match env::var(default_value) { Ok(directory) => Ok(PathBuf::from(directory).join(path)), Err(_) => match env::var("HOME") { Ok(directory) => Ok(PathBuf::from(directory).join(home_fallback).join(path)), Err(_) => Err(Error::new( ErrorKind::NotFound, format!( "Could not find required directory, {user_override} or {default_value} should be set and readable" ), )), }, }, } } } #[cfg(test)] mod tests { use super::*; use std::env; use test_utilities::*; #[test] fn test_sets_correct_configuration_directories() { let default_configuration = Configuration::new().unwrap(); let test_dir = setup_test_dir(); // SAFETY: Run only in single-threaded mode unsafe { env::set_var("PAGE_OUTPUT_DIRECTORY", test_dir.join("output")); } let override_configuration = Configuration::new().unwrap(); // Ensure our overrides were applied assert_eq!( override_configuration.output_directory, test_dir.join("output/page") ); // Ensure all the defaults are different from defaults assert_ne!( default_configuration.output_directory, override_configuration.output_directory ); cleanup_test_dir(&test_dir); } }