diff --git a/Cargo.toml b/Cargo.toml index 1d9906e..fabd6d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,10 @@ cargo-features = ["codegen-backend"] name = "git-heatmap" version = "0.1.0" edition = "2021" +authors = ["Wynd "] +description = "A simple and customizable heatmap for git repos" +readme = "README.md" +repository = "https://git.pixelatedw.xyz/wynd/git-heatmap" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 93ea42e..71ebf94 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,11 @@ $ git-heatmap -r "/path/to/repo" -b "main" -r "/other/repo" -b "test" # or to comply with the same number of branch lists per repo lists rule from above $ git-heatmap -r "/path/to/repo" -b "main" -r "other/repo" -b "" +# alternatively you can simply pass a root directory and let the program search for all git projects +# do be warned that doing so means you're losing the customization aspect of choosing +# which branches should be checked per repo, in this case all branches will be checked. +$ git-heatmap --root-dir "/path" + # by default merges are counted so using --no-merges ensures they won't be counted $ git-heatmap --no-merges diff --git a/src/cli.rs b/src/cli.rs index 394b5fb..5a85db7 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -6,8 +6,11 @@ use clap::{arg, Parser, ValueHint}; use crate::heatmap::{ColorLogic, HeatmapColors}; #[derive(Clone, Debug, Parser, PartialEq, Eq)] -#[command(version, about, long_about = None)] +#[command(version, about, author, long_about = None)] pub struct CliArgs { + #[arg(long("root-dir"), value_hint = ValueHint::DirPath)] + pub root_dir: Option, + #[arg(short, long, num_args(0..))] pub authors: Option>, @@ -39,4 +42,4 @@ pub struct CliArgs { fn get_since_date() -> String { let date = Local::now() - Duration::days(365); date.format("%Y-%m-%d").to_string() -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 25fb3f5..9b217d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,12 @@ #![feature(let_chains)] #![allow(dead_code)] -use std::{cmp::Reverse, collections::HashSet, path::PathBuf, sync::OnceLock}; +use std::{ + cmp::Reverse, + collections::HashSet, + path::{self, PathBuf}, + sync::OnceLock, +}; use anyhow::{anyhow, Context, Result}; use chrono::{DateTime, Duration, Local, NaiveDate, TimeZone}; @@ -84,6 +89,12 @@ fn main() -> Result<()> { .unwrap_or_else(|| get_default_until(since)); let until = NaiveDate::parse_from_str(&until, "%Y-%m-%d").unwrap(); + // let mut repo_dirs: Vec = vec![]; + // if let Some(root_dir) = &args.root_dir { + // find_git_repos(root_dir, &mut repo_dirs, &args); + // } + // + // dbg!(repo_dirs); let commits = get_commits(args, since).with_context(|| "Could not fetch commit list")?; let heatmap = Heatmap::new(since, until, commits.0, commits.1); @@ -147,24 +158,57 @@ fn get_color_map() -> Vec { .to_vec() } +fn find_git_repos(scan_path: &path::Path, repos: &mut Vec, _args: &CliArgs) { + let Ok(dirs) = scan_path.read_dir() + else { + return; + }; + + let dirs: Vec<_> = dirs + .filter_map(|f| f.ok()) + .filter(|f| f.file_type().is_ok_and(|t| t.is_dir())) + .collect_vec(); + + let dirs = dirs.iter().map(|f| f.path()); + + for dir in dirs { + let filename = dir.file_name().unwrap_or_default().to_string_lossy(); + match filename.as_ref() { + ".git" => repos.push(dir), + _ => find_git_repos(&dir, repos, _args), + } + } +} + fn get_commits(args: CliArgs, start_date: NaiveDate) -> Result<(usize, Vec)> { let mut commits: HashSet = HashSet::new(); - let repos = match args.repos { - Some(r) => r, - None => vec![PathBuf::from(".")], + let (repos, branches) = match &args.root_dir { + Some(root) => { + let mut repos: Vec = vec![]; + find_git_repos(root, &mut repos, &args); + let branches = vec!["".to_string(); repos.len()]; + (repos, branches) + } + None => { + let repos = match args.repos { + Some(r) => r, + None => vec![PathBuf::from(".")], + }; + + let branches = args.branches.unwrap_or_else(|| vec!["@".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() + )); + } + (repos, branches) + } }; - let branches = args.branches.unwrap_or_else(|| vec!["@".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 current_time = Local::now().time(); let start_date = start_date.and_time(current_time); let start_date = Local.from_local_datetime(&start_date).unwrap();