diff --git a/src/cache.rs b/src/cache.rs index 081dea2..fb55349 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -16,6 +16,8 @@ use walkdir::{DirEntry, WalkDir}; use crate::error::TealdeerError::{self, CacheError, UpdateError}; use crate::types::{OsType, PathSource}; +static CACHE_DIR_ENV_VAR: &str = "TEALDEER_CACHE_DIR"; + #[derive(Debug)] pub struct Cache { url: String, @@ -59,19 +61,32 @@ impl Cache { /// Return the path to the cache directory. pub fn get_cache_dir() -> Result<(PathBuf, PathSource), TealdeerError> { - // Allow overriding the cache directory by setting the - // $TEALDEER_CACHE_DIR env variable. - if let Ok(value) = env::var("TEALDEER_CACHE_DIR") { + // Allow overriding the cache directory by setting the env variable. + if let Ok(value) = env::var(CACHE_DIR_ENV_VAR) { let path = PathBuf::from(value); - - if path.exists() && path.is_dir() { - return Ok((path, PathSource::EnvVar)); + let (path_exists, path_is_dir) = path + .metadata() + .map_or((false, false), |md| (true, md.is_dir())); + if path_exists && !path_is_dir { + return Err(CacheError(format!( + "Path specified by ${} is not a directory.", + CACHE_DIR_ENV_VAR + ))); } - return Err(CacheError( - "Path specified by $TEALDEER_CACHE_DIR \ - does not exist or is not a directory." - .into(), - )); + if !path_exists { + // Try to create the complete directory path. + fs::create_dir_all(&path).map_err(|_| { + CacheError(format!( + "Directory path specified by ${} cannot be created.", + CACHE_DIR_ENV_VAR + )) + })?; + eprintln!( + "Successfully created cache directory path `{}`.", + path.to_str().unwrap() + ); + } + return Ok((path, PathSource::EnvVar)); }; // Otherwise, fall back to user cache directory. diff --git a/tests/lib.rs b/tests/lib.rs index 769901a..686fcaf 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -10,6 +10,9 @@ use predicates::boolean::PredicateBooleanExt; use predicates::prelude::predicate::str::{contains, is_empty, similar}; use tempfile::{Builder, TempDir}; +// TODO: Should be 'cache::CACHE_DIR_ENV_VAR'. This requires to have a library crate for the logic. +static CACHE_DIR_ENV_VAR: &str = "TEALDEER_CACHE_DIR"; + struct TestEnv { pub cache_dir: TempDir, pub custom_pages_dir: TempDir, @@ -106,10 +109,7 @@ impl TestEnv { } let run = build.run().unwrap(); let mut cmd = run.command(); - cmd.env( - "TEALDEER_CACHE_DIR", - self.cache_dir.path().to_str().unwrap(), - ); + cmd.env(CACHE_DIR_ENV_VAR, self.cache_dir.path().to_str().unwrap()); cmd.env( "TEALDEER_CONFIG_DIR", self.config_dir.path().to_str().unwrap(), @@ -218,6 +218,50 @@ fn test_quiet_old_cache() { .stderr(contains("The cache hasn't been updated for more than ").not()); } +#[test] +fn test_create_cache_directory_path() { + let testenv = TestEnv::new(); + let cache_dir = testenv.cache_dir.path(); + let internal_cache_dir = cache_dir.join("internal"); + + let mut command = testenv.command(); + command.env(CACHE_DIR_ENV_VAR, internal_cache_dir.to_str().unwrap()); + + assert!(!internal_cache_dir.exists()); + + command + .arg("-u") + .assert() + .success() + .stderr(contains(format!( + "Successfully created cache directory path `{}`.", + internal_cache_dir.to_str().unwrap() + ))) + .stderr(contains("Successfully updated cache.")); + + assert!(internal_cache_dir.is_dir()); +} + +#[test] +fn test_cache_location_not_a_directory() { + let testenv = TestEnv::new(); + let cache_dir = testenv.cache_dir.path(); + let internal_file = cache_dir.join("internal"); + File::create(&internal_file).unwrap(); + + let mut command = testenv.command(); + command.env(CACHE_DIR_ENV_VAR, internal_file.to_str().unwrap()); + + command + .arg("-u") + .assert() + .failure() + .stderr(contains(format!( + "Path specified by ${} is not a directory.", + CACHE_DIR_ENV_VAR + ))); +} + #[test] fn test_setup_seed_config() { let testenv = TestEnv::new();