diff options
-rw-r--r-- | CHANGELOG.md | 8 | ||||
-rw-r--r-- | Cargo.lock | 40 | ||||
-rw-r--r-- | src/driver.rs | 35 | ||||
-rw-r--r-- | src/lib.rs | 44 | ||||
-rw-r--r-- | src/main.rs | 6 | ||||
-rw-r--r-- | src/util.rs | 67 |
6 files changed, 136 insertions, 64 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d8e817..3d5090b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] <!-- The latest version contains all changes. --> +### Added + +- Include standard directory feature + +### Changed + +- Directory walking to skip hidden directories + ### Removed - File header comments @@ -72,9 +72,9 @@ dependencies = [ [[package]] name = "bstr" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf" +checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" dependencies = [ "lazy_static", "memchr", @@ -99,12 +99,6 @@ dependencies = [ [[package]] name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" @@ -137,7 +131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -219,7 +213,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi", ] @@ -277,9 +271,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "idna" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +checksum = "de910d521f7cc3135c4de8db1cb910e0b5ed1dc6f57c381cd07e8e661ce10094" dependencies = [ "matches", "unicode-bidi", @@ -315,9 +309,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.82" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" +checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c" [[package]] name = "libgit2-sys" @@ -335,9 +329,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df40b13fe7ea1be9b9dffa365a51273816c345fc1811478b57ed7d964fbfc4ce" +checksum = "e0186af0d8f171ae6b9c4c90ec51898bad5d08a2d5e470903a50d9ad8959cbee" dependencies = [ "cc", "libc", @@ -361,11 +355,11 @@ dependencies = [ [[package]] name = "log" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf3805d4480bb5b86070dcfeb9e2cb2ebc148adb753c5cca5f884d1d65a42b2" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", ] [[package]] @@ -613,9 +607,9 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8208a331e1cb318dd5bd76951d2b8fc48ca38a69f5f4e4af1b6a9f8c6236915" +checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd" dependencies = [ "once_cell", ] @@ -646,9 +640,9 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13e63ab62dbe32aeee58d1c5408d35c36c392bba5d9d3142287219721afe606" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" dependencies = [ "tinyvec", ] diff --git a/src/driver.rs b/src/driver.rs index 51cfbcc..f2d0869 100644 --- a/src/driver.rs +++ b/src/driver.rs @@ -1,13 +1,16 @@ -use crate::util; -use eyre::Result; -use log::debug; use std::cmp::Ordering; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; + +use eyre::Result; +use log::debug; + +use crate::util; #[derive(Debug)] pub struct Config { pub enable_unpushed_check: bool, + pub include_non_repos: bool, pub no_color: bool, pub recursive: bool, pub skip_sort: bool, @@ -51,27 +54,41 @@ impl Results { fn execute_in_directory(&mut self, config: &Config, dir: &Path) -> Result<()> { // FIXME: find ways to add concurrent programming (tokio, async, etc.) to this section. let path_entries = fs::read_dir(dir)?; - let mut repos = Vec::new(); + let mut repos: Vec<PathBuf> = Vec::new(); + let mut non_repos: Vec<PathBuf> = Vec::new(); for entry in path_entries { let subpath = &entry?.path(); - if subpath.is_dir() { + + // Ensure that the directory is not hidden. + if subpath.is_dir() + && !util::get_short_name_for_directory(subpath, dir).starts_with(".") + { if git2::Repository::open(subpath).is_ok() { repos.push(subpath.to_owned()); - } else if config.recursive { - debug!("Recursive execution into directory: {:#?}", &subpath); - self.execute_in_directory(&config, &subpath)?; + } else { + if config.include_non_repos { + non_repos.push(subpath.to_owned()); + } + if config.recursive { + debug!("Recursive execution into directory: {:#?}", &subpath); + self.execute_in_directory(&config, &subpath)?; + } } } } debug!("Git repositories found: {:#?}", repos); + if config.include_non_repos { + debug!("Standard directories found: {:#?}", non_repos); + } if !repos.is_empty() { if !&config.skip_sort { repos.sort(); } if let Some(table_wrapper) = util::create_table_from_paths( repos, + non_repos, &dir, &config.enable_unpushed_check, &config.no_color, @@ -3,15 +3,17 @@ #[macro_use] extern crate prettytable; -mod driver; -mod util; +use std::path::Path; use eyre::Result; -use std::path::Path; + +mod driver; +mod util; /// This function is the primary, backend driver for `gfold`. /// /// - `enable_unpushed_check`: enable checking for unpushed commits (experimental) +/// - `include_non_repos`: include standard directories in the result /// - `no_color`: disables color, bolding, etc. /// - `path`: the target path to find and parse Git repositories /// - `recursive`: recursively searches directories for Git repositories @@ -21,12 +23,14 @@ use std::path::Path; pub fn run( path: &Path, enable_unpushed_check: bool, + include_non_repos: bool, no_color: bool, recursive: bool, skip_sort: bool, ) -> Result<()> { let config = driver::Config { enable_unpushed_check, + include_non_repos, no_color, recursive, skip_sort, @@ -44,27 +48,43 @@ mod tests { #[test] fn current_directory() { let current_dir = env::current_dir().expect("failed to get CWD"); - assert_ne!(run(¤t_dir, false, false, false, false).is_err(), true); + assert_ne!( + run(¤t_dir, false, false, false, false, false).is_err(), + true + ); } #[test] fn parent_directory() { let mut current_dir = env::current_dir().expect("failed to get CWD"); current_dir.pop(); - assert_ne!(run(¤t_dir, false, false, false, false).is_err(), true); + assert_ne!( + run(¤t_dir, false, false, false, false, false).is_err(), + true + ); } #[test] fn parent_directory_all_options() { let mut current_dir = env::current_dir().expect("failed to get CWD"); current_dir.pop(); - for skip_sort in vec![true, false] { - for recursive in vec![true, false] { - for no_color in vec![true, false] { - assert_ne!( - run(¤t_dir, false, no_color, recursive, skip_sort).is_err(), - true - ); + for include_non_repos in vec![true, false] { + for no_color in vec![true, false] { + for recursive in vec![true, false] { + for skip_sort in vec![true, false] { + assert_ne!( + run( + ¤t_dir, + false, + include_non_repos, + no_color, + recursive, + skip_sort + ) + .is_err(), + true + ); + } } } } diff --git a/src/main.rs b/src/main.rs index 4d223d6..c19e86b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ -use eyre::Result; use std::env; use std::path::PathBuf; + +use eyre::Result; use structopt::StructOpt; #[derive(StructOpt, Debug)] @@ -20,6 +21,8 @@ struct Opt { help = "Toggle to enable checking for unpushed commits (experimental)" )] enable_unpushed_check: bool, + #[structopt(short, long, help = "Include standard directories in the result")] + include_non_repos: bool, #[structopt(long = "nc", help = "Disable color output")] no_color: bool, #[structopt(parse(from_os_str), help = "Target a different directory")] @@ -47,6 +50,7 @@ fn main() -> Result<()> { gfold::run( &path, opt.enable_unpushed_check, + opt.include_non_repos, opt.no_color, opt.recursive, opt.skip_sort, diff --git a/src/util.rs b/src/util.rs index c887d64..7d05190 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,9 @@ -use crate::driver; -use log::debug; use std::path::{Path, PathBuf}; +use log::{debug, warn}; + +use crate::driver; + #[derive(Debug)] enum Condition { Bare, @@ -13,6 +15,7 @@ enum Condition { pub fn create_table_from_paths( repos: Vec<PathBuf>, + non_repos: Vec<PathBuf>, path: &Path, enable_unpushed_check: &bool, no_color: &bool, @@ -52,13 +55,6 @@ pub fn create_table_from_paths( let branch = head.shorthand().unwrap_or("none"); debug!("[+] branch: {:#?}", branch); - let name = Path::new(&repo) - .strip_prefix(path) - .ok()? - .to_str() - .unwrap_or("none"); - debug!("[+] name: {:#?}", name); - // FIXME: test using the "is_bare()" method for a repository object. let mut opts = git2::StatusOptions::new(); let condition = match repo_obj.statuses(Some(&mut opts)) { @@ -79,33 +75,54 @@ pub fn create_table_from_paths( Err(_) => Condition::Error, }; + // This match block's formatting is aimed at readability (frequent usage of "{}"). match condition { Condition::Bare if *no_color => { - table.add_row(row![Fl->name, Fl->"bare", Fl->branch, Fl->url]) + table.add_row(row![Fl->get_short_name_for_directory(&repo, path), Fl->"bare", Fl->branch, Fl->url]) + } + Condition::Bare => { + table.add_row(row![Flb->get_short_name_for_directory(&repo, path), Frl->"bare", Fl->branch, Fl->url]) } - Condition::Bare => table.add_row(row![Flb->name, Frl->"bare", Fl->branch, Fl->url]), Condition::Clean if *no_color => { - table.add_row(row![Fl->name, Fl->"clean", Fl->branch, Fl->url]) + table.add_row(row![Fl->get_short_name_for_directory(&repo, path), Fl->"clean", Fl->branch, Fl->url]) + } + Condition::Clean => { + table.add_row(row![Flb->get_short_name_for_directory(&repo, path), Fgl->"clean", Fl->branch, Fl->url]) } - Condition::Clean => table.add_row(row![Flb->name, Fgl->"clean", Fl->branch, Fl->url]), Condition::Unclean if *no_color => { - table.add_row(row![Fl->name, Fl->"unclean", Fl->branch, Fl->url]) + table.add_row(row![Fl->get_short_name_for_directory(&repo, path), Fl->"unclean", Fl->branch, Fl->url]) } Condition::Unclean => { - table.add_row(row![Flb->name, Fyl->"unclean", Fl->branch, Fl->url]) + table.add_row(row![Flb->get_short_name_for_directory(&repo, path), Fyl->"unclean", Fl->branch, Fl->url]) } Condition::Unpushed if *no_color => { - table.add_row(row![Fl->name, Fl->"unpushed", Fl->branch, Fl->url]) + table.add_row(row![Fl->get_short_name_for_directory(&repo, path), Fl->"unpushed", Fl->branch, Fl->url]) } Condition::Unpushed => { - table.add_row(row![Flb->name, Fcl->"unpushed", Fl->branch, Fl->url]) + table.add_row(row![Flb->get_short_name_for_directory(&repo, path), Fcl->"unpushed", Fl->branch, Fl->url]) + } + _ if *no_color => { + table.add_row(row![Fl->get_short_name_for_directory(&repo, path), Fl->"error", Fl->branch, Fl->url]) + } + _ => { + table.add_row(row![Flb->get_short_name_for_directory(&repo, path), Frl->"error", Fl->branch, Fl->url]) } - _ if *no_color => table.add_row(row![Fl->name, Fl->"error", Fl->branch, Fl->url]), - _ => table.add_row(row![Flb->name, Frl->"error", Fl->branch, Fl->url]), }; debug!("[+] condition: {:#?}", condition); } + for non_repo in non_repos { + if *no_color { + table.add_row( + row![Fl->get_short_name_for_directory(&non_repo, path), Fl->"dir", Fl->"-", Fl->"-"], + ); + } else { + table.add_row( + row![Flb->get_short_name_for_directory(&non_repo, path), Fcl->"dir", Fl->"-", Fl->"-"], + ); + } + } + debug!("Generated {:#?} rows for table object", table.len()); match table.is_empty() { true => None, @@ -116,6 +133,18 @@ pub fn create_table_from_paths( } } +pub fn get_short_name_for_directory(child: &PathBuf, parent: &Path) -> String { + let temp_dir = child.clone(); + let path = match Path::new(&temp_dir).strip_prefix(parent) { + Ok(o) => o, + Err(e) => { + warn!("Encountered error: {:#?}", e); + return "none".to_string(); + } + }; + path.to_str().unwrap_or("none").to_owned() +} + // FIXME: this function may not currently work because "clean", non-main branches can be considered "unpushed". fn is_unpushed(repo: &git2::Repository, head: &git2::Reference) -> bool { let local = match head.peel_to_commit() { |