use crate::error::{LazyGetError, Result};
use std::fs;
use std::path::{Path, PathBuf};
pub fn fetch<P, F>(cache_dir: P, artifact_id: &str, fetch_fn: F) -> Result<PathBuf>
where
P: AsRef<Path>,
F: FnOnce(&Path) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>>,
{
let cache_dir = cache_dir.as_ref();
let target_dir = cache_dir.join(artifact_id);
if target_dir.exists() {
return Ok(target_dir);
}
fs::create_dir_all(cache_dir).map_err(|e| LazyGetError::CacheCreate {
path: cache_dir.to_path_buf(),
source: e,
})?;
let temp_dir = cache_dir.join(format!(".{}-tmp", artifact_id));
if temp_dir.exists() {
fs::remove_dir_all(&temp_dir)?;
}
fs::create_dir_all(&temp_dir)?;
let fetch_result = fetch_fn(&temp_dir);
match fetch_result {
Ok(()) => {
fs::rename(&temp_dir, &target_dir).map_err(|e| LazyGetError::AtomicRename {
from: temp_dir.clone(),
to: target_dir.clone(),
source: e,
})?;
Ok(target_dir)
}
Err(e) => {
let _ = fs::remove_dir_all(&temp_dir);
Err(LazyGetError::Fetch(e))
}
}
}
pub fn refetch<P, F>(cache_dir: P, artifact_id: &str, fetch_fn: F) -> Result<PathBuf>
where
P: AsRef<Path>,
F: FnOnce(&Path) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>>,
{
let target_dir = cache_dir.as_ref().join(artifact_id);
if target_dir.exists() {
fs::remove_dir_all(&target_dir)?;
}
fetch(cache_dir, artifact_id, fetch_fn)
}