use std::collections::{HashMap, HashSet};
use crate::git::BlameInfo;
pub struct AuthorSummary {
pub name: String,
pub email: String,
pub owned_files: usize,
pub lines: usize,
pub languages: Vec<String>,
pub last_active: i64,
}
struct AuthorAccum {
name: String,
lines: usize,
languages: HashSet<String>,
last_active: i64,
owned_files: usize,
}
pub fn compute_authors(file_blames: &[(&str, &[BlameInfo])]) -> Vec<AuthorSummary> {
let mut accum: HashMap<String, AuthorAccum> = HashMap::new();
for (language, blames) in file_blames {
let primary_email = blames.first().map(|b| b.email.as_str()).unwrap_or("");
for blame in *blames {
let entry = accum
.entry(blame.email.clone())
.or_insert_with(|| AuthorAccum {
name: blame.author.clone(),
lines: 0,
languages: HashSet::new(),
last_active: 0,
owned_files: 0,
});
entry.lines += blame.lines;
entry.languages.insert(language.to_string());
if blame.last_commit_time > entry.last_active {
entry.last_active = blame.last_commit_time;
}
if blame.email.as_str() == primary_email {
entry.owned_files += 1;
}
}
}
let mut result: Vec<AuthorSummary> = accum
.into_iter()
.map(|(email, a)| {
let mut langs: Vec<String> = a.languages.into_iter().collect();
langs.sort();
AuthorSummary {
name: a.name,
email,
owned_files: a.owned_files,
lines: a.lines,
languages: langs,
last_active: a.last_active,
}
})
.collect();
result.sort_by(|a, b| b.lines.cmp(&a.lines));
result
}
#[cfg(test)]
#[path = "analyzer_test.rs"]
mod tests;