From 9ba9533ba179744fc3f2ba2c81b73a6c8bf8ac98 Mon Sep 17 00:00:00 2001 From: o2sh Date: Wed, 30 Jun 2021 21:27:25 +0200 Subject: [PATCH 1/4] use mailmap bindings --- src/onefetch/info.rs | 2 +- src/onefetch/repo.rs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/onefetch/info.rs b/src/onefetch/info.rs index 6865dadb8..e00e4fbe6 100644 --- a/src/onefetch/info.rs +++ b/src/onefetch/info.rs @@ -221,7 +221,7 @@ impl Info { let number_of_branches = internal_repo.get_number_of_branches()?; let creation_date = internal_repo.get_creation_date(config.iso_time)?; let number_of_commits = internal_repo.get_number_of_commits(); - let authors = internal_repo.get_authors(config.number_of_authors, config.show_email); + let authors = internal_repo.get_authors(config.number_of_authors, config.show_email)?; let last_change = internal_repo.get_date_of_last_commit(config.iso_time); let (repo_size, file_count) = internal_repo.get_repo_size(); let workdir = internal_repo.get_work_dir()?; diff --git a/src/onefetch/repo.rs b/src/onefetch/repo.rs index 11ab4321e..7f794e678 100644 --- a/src/onefetch/repo.rs +++ b/src/onefetch/repo.rs @@ -67,12 +67,13 @@ impl<'a> Repo<'a> { &self, n: usize, show_email: bool, - ) -> Vec<(String, Option, usize, usize)> { + ) -> Result, usize, usize)>> { let mut authors = std::collections::HashMap::new(); let mut author_name_by_email = std::collections::HashMap::new(); let mut total_nbr_of_commits = 0; + let mailmap = self.repo.mailmap()?; for commit in &self.logs { - let author = commit.author(); + let author = commit.author_with_mailmap(&mailmap)?; let author_name = String::from_utf8_lossy(author.name_bytes()).into_owned(); let author_email = String::from_utf8_lossy(author.email_bytes()).into_owned(); @@ -100,7 +101,7 @@ impl<'a> Repo<'a> { }) .collect(); - authors + Ok(authors) } pub fn get_date_of_last_commit(&self, iso_time: bool) -> String { From 98f57566ce05b91294dea51af72102a1bd37f114 Mon Sep 17 00:00:00 2001 From: o2sh Date: Wed, 30 Jun 2021 23:07:17 +0200 Subject: [PATCH 2/4] merge authors by signature ~ username + email --- src/onefetch/repo.rs | 69 +++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/src/onefetch/repo.rs b/src/onefetch/repo.rs index 7f794e678..8c78a5168 100644 --- a/src/onefetch/repo.rs +++ b/src/onefetch/repo.rs @@ -4,6 +4,7 @@ use git2::{ StatusShow, }; use regex::Regex; +use std::collections::HashMap; use std::path::Path; pub struct Repo<'a> { @@ -11,6 +12,20 @@ pub struct Repo<'a> { logs: Vec>, } +#[derive(Hash, PartialEq, Eq)] +pub struct Sig { + name: String, + email: String, +} + +impl From> for Sig { + fn from(sig: Signature) -> Self { + let name = String::from_utf8_lossy(sig.name_bytes()).into_owned(); + let email = String::from_utf8_lossy(sig.email_bytes()).into_owned(); + Self { name, email } + } +} + impl<'a> Repo<'a> { pub fn new( repo: &'a Repository, @@ -65,43 +80,43 @@ impl<'a> Repo<'a> { pub fn get_authors( &self, - n: usize, + number_of_author: usize, show_email: bool, ) -> Result, usize, usize)>> { - let mut authors = std::collections::HashMap::new(); - let mut author_name_by_email = std::collections::HashMap::new(); + let mut author_to_number_of_commits: HashMap = HashMap::new(); let mut total_nbr_of_commits = 0; let mailmap = self.repo.mailmap()?; for commit in &self.logs { let author = commit.author_with_mailmap(&mailmap)?; - let author_name = String::from_utf8_lossy(author.name_bytes()).into_owned(); - let author_email = String::from_utf8_lossy(author.email_bytes()).into_owned(); - - let author_nbr_of_commits = authors.entry(author_email.to_string()).or_insert(0); - author_name_by_email.entry(author_email.to_string()).or_insert(author_name); + let author_nbr_of_commits = + author_to_number_of_commits.entry(Sig::from(author)).or_insert(0); *author_nbr_of_commits += 1; total_nbr_of_commits += 1; } - let mut authors: Vec<(String, usize)> = authors.into_iter().collect(); - authors.sort_by(|(_, a_count), (_, b_count)| b_count.cmp(a_count)); - - authors.truncate(n); - - let authors: Vec<(String, Option, usize, usize)> = authors - .into_iter() - .map(|(author_email, author_nbr_of_commits)| { - ( - author_name_by_email.get(&author_email).unwrap().trim_matches('\'').to_string(), - show_email.then(|| author_email), - author_nbr_of_commits, - (author_nbr_of_commits as f32 * 100. / total_nbr_of_commits as f32).round() - as usize, - ) - }) - .collect(); - - Ok(authors) + let mut authors_sorted_by_number_of_commits: Vec<(Sig, usize)> = + author_to_number_of_commits.into_iter().collect(); + + authors_sorted_by_number_of_commits + .sort_by(|(_, a_count), (_, b_count)| b_count.cmp(a_count)); + + authors_sorted_by_number_of_commits.truncate(number_of_author); + + let result: Vec<(String, Option, usize, usize)> = + authors_sorted_by_number_of_commits + .into_iter() + .map(|(author, author_nbr_of_commits)| { + ( + author.name.clone(), + show_email.then(|| author.email), + author_nbr_of_commits, + (author_nbr_of_commits as f32 * 100. / total_nbr_of_commits as f32).round() + as usize, + ) + }) + .collect(); + + Ok(result) } pub fn get_date_of_last_commit(&self, iso_time: bool) -> String { From e031a88ce7718330174b8a691a5921d4917ac5eb Mon Sep 17 00:00:00 2001 From: o2sh Date: Thu, 1 Jul 2021 00:38:50 +0200 Subject: [PATCH 3/4] fallback to commit.author() if commit.author_with_mailmap() fails --- src/onefetch/repo.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/onefetch/repo.rs b/src/onefetch/repo.rs index 8c78a5168..a15c4df62 100644 --- a/src/onefetch/repo.rs +++ b/src/onefetch/repo.rs @@ -87,7 +87,10 @@ impl<'a> Repo<'a> { let mut total_nbr_of_commits = 0; let mailmap = self.repo.mailmap()?; for commit in &self.logs { - let author = commit.author_with_mailmap(&mailmap)?; + let author = match commit.author_with_mailmap(&mailmap) { + Ok(val) => val, + Err(_) => commit.author(), + }; let author_nbr_of_commits = author_to_number_of_commits.entry(Sig::from(author)).or_insert(0); *author_nbr_of_commits += 1; From 9b1aa1691607212c187ebe88b65e8e931bd0c211 Mon Sep 17 00:00:00 2001 From: o2sh Date: Sat, 3 Jul 2021 02:54:13 +0200 Subject: [PATCH 4/4] fix json/yaml serializer --- src/info/mod.rs | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/src/info/mod.rs b/src/info/mod.rs index 7f34cc253..481b50286 100644 --- a/src/info/mod.rs +++ b/src/info/mod.rs @@ -431,31 +431,17 @@ impl Serialize for Info { where S: serde::Serializer, { - let mut state = serializer.serialize_struct("Info", 20)?; - - // Only collect the version number - let git_version = if !self.git_version.is_empty() { - self.git_version.split(' ').collect::>()[2] - } else { - "" - }; - - state.serialize_field("gitVersion", &git_version)?; - state.serialize_field("gitUsername", &self.git_username)?; + let mut state = serializer.serialize_struct("Info", 15)?; + let langs: Vec = self.languages.iter().map(|(l, _)| format!("{}", l)).collect(); + let auths: Vec = self.authors.iter().map(|(l, _, _, _)| format!("{}", l)).collect(); state.serialize_field("repoName", &self.repo_name)?; state.serialize_field("numberOfTags", &self.number_of_tags)?; state.serialize_field("numberOfBranches", &self.number_of_branches)?; state.serialize_field("headRefs", &self.head_refs)?; - state.serialize_field("pendingChanges", &self.pending_changes)?; state.serialize_field("version", &self.version)?; state.serialize_field("creationDate", &self.creation_date)?; - state.serialize_field("languages", &self.languages)?; - - let dependencies_split: Vec = - self.dependencies.split(' ').map(|s| s.to_string()).collect(); - - state.serialize_field("dependencies", &dependencies_split[0])?; - state.serialize_field("authors", &self.authors)?; + state.serialize_field("languages", &langs)?; + state.serialize_field("authors", &auths)?; state.serialize_field("lastChange", &self.last_change)?; state.serialize_field("repoUrl", &self.repo_url)?; state.serialize_field("numberOfCommits", &self.number_of_commits)?; @@ -463,7 +449,7 @@ impl Serialize for Info { state.serialize_field("repoSize", &self.repo_size)?; state.serialize_field("filesCount", &self.file_count)?; state.serialize_field("license", &self.license)?; - state.serialize_field("dominantLanguage", &self.dominant_language)?; + state.end() } }