use std::collections::HashMap;
use std::path::Path;
pub fn compute_staleness_batch(
root: &Path,
file_paths: &[impl AsRef<str>],
) -> HashMap<String, f64> {
let mut result: HashMap<String, f64> = HashMap::new();
let Some(repo) = open_repo(root) else {
for p in file_paths {
result.insert(p.as_ref().to_string(), 0.0);
}
return result;
};
let mut seen = std::collections::HashSet::new();
let unique_paths: Vec<&str> = file_paths
.iter()
.map(|p| p.as_ref())
.filter(|p| seen.insert(*p))
.collect();
for rel_path in unique_paths {
let staleness = compute_staleness_for_file(&repo, rel_path);
result.insert(rel_path.to_string(), staleness);
}
result
}
fn compute_staleness_for_file(repo: &gix::Repository, rel_path: &str) -> f64 {
let Ok(head_id) = repo.head_id() else {
return 0.0;
};
let Ok(walk) = head_id
.ancestors()
.sorting(gix::revision::walk::Sorting::ByCommitTime(
gix::traverse::commit::simple::CommitTimeOrder::NewestFirst,
))
.all()
else {
return 0.0;
};
let mut commits_before_last_touch = 0usize;
let mut found = false;
for info in walk {
let Ok(info) = info else { continue };
let Ok(commit) = info.object() else { continue };
let Ok(tree) = commit.tree() else { continue };
let parent_tree = info
.parent_ids()
.next()
.and_then(|pid| pid.object().ok())
.and_then(|obj| obj.into_commit().tree().ok());
let changes = match repo.diff_tree_to_tree(parent_tree.as_ref(), Some(&tree), None) {
Ok(c) => c,
Err(_) => continue,
};
let touches = changes.iter().any(|change| {
use gix::object::tree::diff::ChangeDetached;
let loc = match change {
ChangeDetached::Addition { location, .. }
| ChangeDetached::Deletion { location, .. }
| ChangeDetached::Modification { location, .. } => location.as_slice(),
ChangeDetached::Rewrite {
source_location, ..
} => source_location.as_slice(),
};
loc == rel_path.as_bytes()
});
if touches {
found = true;
break;
}
commits_before_last_touch += 1;
}
if !found {
return 0.0;
}
(commits_before_last_touch as f64 / 50.0).min(1.0)
}
fn open_repo(path: &Path) -> Option<gix::Repository> {
gix::discover(path).ok()
}