use crate::tripwire::hasher;
use std::path::Path;
pub fn hash_inputs(patterns: &[String], base_dir: &Path) -> Result<Option<String>, String> {
if patterns.is_empty() {
return Ok(None);
}
let mut matched_files: Vec<String> = Vec::new();
for pattern in patterns {
let files = expand_glob(pattern, base_dir)?;
matched_files.extend(files);
}
if matched_files.is_empty() {
return Ok(None);
}
matched_files.sort();
matched_files.dedup();
let mut components: Vec<String> = Vec::new();
for file_path in &matched_files {
let path = Path::new(file_path);
let hash = hasher::hash_file(path)?;
components.push(format!("{file_path}\0{hash}"));
}
let refs: Vec<&str> = components.iter().map(|s| s.as_str()).collect();
Ok(Some(hasher::composite_hash(&refs)))
}
pub fn hash_outputs(artifacts: &[String]) -> Result<Option<String>, String> {
if artifacts.is_empty() {
return Ok(None);
}
let mut components: Vec<String> = Vec::new();
for artifact in artifacts {
let path = Path::new(artifact);
if path.exists() {
let hash = if path.is_dir() {
hasher::hash_directory(path)?
} else {
hasher::hash_file(path)?
};
components.push(format!("{artifact}\0{hash}"));
}
}
if components.is_empty() {
return Ok(None);
}
let refs: Vec<&str> = components.iter().map(|s| s.as_str()).collect();
Ok(Some(hasher::composite_hash(&refs)))
}
pub fn should_skip_cached(
cache: bool,
current_hash: Option<&str>,
stored_hash: Option<&str>,
) -> bool {
if !cache {
return false;
}
match (current_hash, stored_hash) {
(Some(cur), Some(stored)) => cur == stored,
_ => false,
}
}
fn expand_glob(pattern: &str, base_dir: &Path) -> Result<Vec<String>, String> {
let full_pattern = if Path::new(pattern).is_absolute() {
pattern.to_string()
} else {
format!("{}/{pattern}", base_dir.display())
};
let paths =
glob::glob(&full_pattern).map_err(|e| format!("invalid glob pattern '{pattern}': {e}"))?;
let mut result = Vec::new();
for entry in paths {
match entry {
Ok(path) if path.is_file() => {
result.push(path.to_string_lossy().to_string());
}
Ok(_) => {} Err(e) => {
return Err(format!("glob error for '{pattern}': {e}"));
}
}
}
Ok(result)
}