From cbbe8c44b029c6c9a36d281a352e84c26257c970 Mon Sep 17 00:00:00 2001 From: Wynd Date: Sat, 17 Aug 2024 01:48:06 +0300 Subject: [PATCH] Added support for multiple repos each with their own number of branches --- src/cli.rs | 6 +-- src/heatmap.rs | 5 +- src/main.rs | 134 ++++++++++++++++++++++++++++--------------------- 3 files changed, 84 insertions(+), 61 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 1e39ea7..17b2204 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -8,9 +8,6 @@ use crate::heatmap::HeatmapColors; #[derive(Clone, Debug, Parser, PartialEq, Eq)] #[command(version, about, long_about = None)] pub struct CliArgs { - #[arg(default_value=".", value_hint = ValueHint::DirPath)] - pub input: PathBuf, - #[arg(short, long)] pub author: String, @@ -20,6 +17,9 @@ pub struct CliArgs { #[arg(long("color"), value_enum, default_value_t = HeatmapColors::Green)] pub color_scheme: HeatmapColors, + #[arg(short, long, num_args(0..), value_hint = ValueHint::DirPath)] + pub repos: Option>, + #[arg(short, long, num_args(0..))] pub branches: Option>, diff --git a/src/heatmap.rs b/src/heatmap.rs index 6f57fb1..f2bac05 100644 --- a/src/heatmap.rs +++ b/src/heatmap.rs @@ -12,10 +12,11 @@ pub struct Heatmap { commits: Vec, months: Vec<(usize, String)>, highest_count: i32, + repos: usize, } impl Heatmap { - pub fn new(since: NaiveDate, until: NaiveDate, commits: Vec) -> Self { + pub fn new(since: NaiveDate, until: NaiveDate, repos: usize, commits: Vec) -> Self { let mut heatmap = Self { data: [vec![], vec![], vec![], vec![], vec![], vec![], vec![]], since, @@ -23,6 +24,7 @@ impl Heatmap { commits, months: vec![], highest_count: 0, + repos, }; let mut grouped_commits = BTreeMap::new(); @@ -97,6 +99,7 @@ impl Display for Heatmap { let commits = self.commits.len().to_string(); write!(f, "{} - {}\n", start_date, end_date).unwrap(); + write!(f, "{} repos\n", self.repos).unwrap(); write!(f, "{} commits\n\n", commits).unwrap(); write!(f, "{}\n", self.months_row()).unwrap(); diff --git a/src/main.rs b/src/main.rs index ab22ce7..dce765c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,14 +2,14 @@ #![feature(let_chains)] #![allow(dead_code)] -use std::{cmp::Reverse, collections::HashSet, sync::OnceLock}; +use std::{cmp::Reverse, collections::HashSet, path::PathBuf, sync::OnceLock}; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use chrono::{DateTime, Duration, Local, NaiveDate, TimeZone}; use clap::Parser; use gix::{bstr::ByteSlice, ObjectId, Repository}; use heatmap::HeatmapColors; -use itertools::Itertools; +use itertools::{enumerate, Itertools}; use rgb::Rgb; use crate::{cli::CliArgs, heatmap::Heatmap}; @@ -53,6 +53,8 @@ fn main() -> Result<()> { let args = CliArgs::parse(); + // dbg!(&args); + CHAR.set(args.char).unwrap(); let color_map = match args.color_scheme { HeatmapColors::Green => GREEN_COLOR_MAP, @@ -64,8 +66,6 @@ fn main() -> Result<()> { .collect::>(); COLOR_MAP.set(color_map).unwrap(); - let repo = gix::open(&args.input).unwrap(); - let since = NaiveDate::parse_from_str(&args.since, "%Y-%m-%d").unwrap(); let until = args @@ -74,9 +74,9 @@ fn main() -> Result<()> { .unwrap_or_else(|| get_default_until(since)); let until = NaiveDate::parse_from_str(&until, "%Y-%m-%d").unwrap(); - let commits = get_commits(repo, args, since).with_context(|| "Could not fetch commit list")?; + let commits = get_commits(args, since).with_context(|| "Could not fetch commit list")?; - let heatmap = Heatmap::new(since, until, commits); + let heatmap = Heatmap::new(since, until, commits.0, commits.1); println!("{heatmap}"); @@ -122,65 +122,85 @@ fn get_color_map() -> Vec { .to_vec() } -fn get_commits(repo: Repository, args: CliArgs, start_date: NaiveDate) -> Result> { +fn get_commits(args: CliArgs, start_date: NaiveDate) -> Result<(usize, Vec)> { let mut commits: HashSet = HashSet::new(); - let branches = match args.branches { - Some(b) => b, - None => repo - .branch_names() - .into_iter() - .map(|b| b.to_string()) - .collect_vec(), + let repos = match args.repos { + Some(r) => r, + None => vec![PathBuf::from(".")], }; - for branch in branches { - let branch_commits = repo - .rev_parse(&*branch)? - .single() - .unwrap() - .ancestors() - .all()?; + let branches = args.branches.unwrap_or_else(|| vec!["@".to_string()]); - branch_commits - .filter_map(|c| c.ok()) - .filter_map(|c| c.object().ok()) - .filter_map(|c| { - let title = c - .message() - .ok()? - .title - .trim_ascii() - .to_str() - .ok()? - .to_string(); + if repos.len() > 1 && repos.len() != branches.len() { + return Err(anyhow!( + "Number of repos ({}) needs to match the number of branch lists ({})!", + repos.len(), + branches.len() + )); + } - let author = c.author().ok()?.name.to_string(); - if author != args.author { - return None; - } + for (i, repo) in repos.iter().enumerate() { + let repo = gix::open(repo).unwrap(); - let current_time = Local::now().time(); - let start_date = start_date.and_time(current_time); - let start_date = Local.from_local_datetime(&start_date).unwrap(); + let branch_names = &*branches[i]; + let mut branches = vec![]; + if branch_names.is_empty() { + branches.extend(repo.branch_names().iter()); + } + else { + let branch_names = branch_names.split(' '); + branches.extend(branch_names); + } - let time = c.time().ok()?; - let time = - DateTime::from_timestamp_millis(time.seconds * 1000)?.with_timezone(&Local); - if time <= start_date + Duration::days(1) { - return None; - } + for branch in branches { + let branch_commits = repo + .rev_parse(branch)? + .single() + .unwrap() + .ancestors() + .all()?; - Some(Commit { - id: c.id, - title, - author, - time, + branch_commits + .filter_map(|c| c.ok()) + .filter_map(|c| c.object().ok()) + .filter_map(|c| { + let title = c + .message() + .ok()? + .title + .trim_ascii() + .to_str() + .ok()? + .to_string(); + + let author = c.author().ok()?.name.to_string(); + if author != args.author { + return None; + } + + let current_time = Local::now().time(); + let start_date = start_date.and_time(current_time); + let start_date = Local.from_local_datetime(&start_date).unwrap(); + + let time = c.time().ok()?; + let time = + DateTime::from_timestamp_millis(time.seconds * 1000)?.with_timezone(&Local); + if time <= start_date + Duration::days(1) { + return None; + } + + Some(Commit { + id: c.id, + title, + author, + time, + }) }) - }) - .for_each(|c| { - commits.insert(c); - }); + .for_each(|c| { + commits.insert(c); + }); + } } let commits = commits @@ -188,5 +208,5 @@ fn get_commits(repo: Repository, args: CliArgs, start_date: NaiveDate) -> Result .sorted_by_cached_key(|a| Reverse(a.time)) .collect_vec(); - Ok(commits) + Ok((repos.len(), commits)) }