use super::*;
pub(crate) fn head_commit_sha(repo: &git2::Repository) -> Option<String> {
repo.head().ok()?.target().map(|oid| oid.to_string())
}
pub(crate) fn blob_sha_at_head(repo: &git2::Repository, path: &str) -> Option<String> {
let head_ref = repo.head().ok()?;
let commit = head_ref.peel_to_commit().ok()?;
let tree = commit.tree().ok()?;
let entry = tree.get_path(Path::new(path)).ok()?;
Some(entry.id().to_string())
}
pub(crate) fn blob_sha_at_commit(
repo: &git2::Repository,
path: &str,
commit_sha: &str,
) -> Option<String> {
let oid = git2::Oid::from_str(commit_sha).ok()?;
let commit = repo.find_commit(oid).ok()?;
let tree = commit.tree().ok()?;
let entry = tree.get_path(Path::new(path)).ok()?;
Some(entry.id().to_string())
}
#[allow(dead_code)]
pub(super) fn count_recent_commits(repo: &git2::Repository, path: &str, limit: usize) -> u32 {
let head_oid = match repo.head().ok().and_then(|h| h.target()) {
Some(oid) => oid,
None => return 0,
};
let mut revwalk = match repo.revwalk() {
Ok(rw) => rw,
Err(_) => return 0,
};
if revwalk.push(head_oid).is_err() {
return 0;
}
revwalk.set_sorting(git2::Sort::TOPOLOGICAL).ok();
let mut count: u32 = 0;
let mut total_iterations: usize = 0;
for oid_result in revwalk {
total_iterations += 1;
if total_iterations > limit {
break;
}
let oid = match oid_result {
Ok(o) => o,
Err(_) => continue,
};
if commit_touches_file(repo, oid, path) {
count += 1;
}
}
count
}
pub(crate) fn commits_to_factor(commits: u32) -> f32 {
match commits {
0 => 0.0,
1 => 0.15,
2 => 0.30,
3 => 0.50,
4 => 0.70,
_ => 1.0,
}
}
pub(crate) fn commit_touches_file(
repo: &git2::Repository,
commit_oid: git2::Oid,
path: &str,
) -> bool {
let commit = match repo.find_commit(commit_oid) {
Ok(c) => c,
Err(_) => return false,
};
let tree = match commit.tree() {
Ok(t) => t,
Err(_) => return false,
};
let file_entry = tree.get_path(Path::new(path)).ok();
if commit.parent_count() == 0 {
return file_entry.is_some();
}
let parent = match commit.parent(0) {
Ok(p) => p,
Err(_) => return file_entry.is_some(),
};
let parent_tree = match parent.tree() {
Ok(t) => t,
Err(_) => return file_entry.is_some(),
};
let parent_entry = parent_tree.get_path(Path::new(path)).ok();
match (file_entry, parent_entry) {
(Some(cur), Some(par)) => cur.id() != par.id(),
(Some(_), None) => true, (None, Some(_)) => true, (None, None) => false,
}
}
pub(crate) fn staleness_changed(old: &Record, new: &Record) -> bool {
let value_delta = (old.staleness.value - new.staleness.value).abs();
if value_delta > 0.01 {
return true;
}
if old.staleness.tier != new.staleness.tier {
return true;
}
if old.staleness.signals.len() != new.staleness.signals.len() {
return true;
}
if old.staleness.last_record_sha != new.staleness.last_record_sha {
return true;
}
false
}
pub(crate) fn is_reparse_signal(signal: &StalenessSignal) -> bool {
matches!(
signal,
StalenessSignal::EntryPointsChanged(_)
| StalenessSignal::ImportsChanged(_)
| StalenessSignal::TodosChanged
| StalenessSignal::UnsafeCountChanged(_)
| StalenessSignal::UnwrapCountChanged(_)
)
}