diff --git a/Cargo.lock b/Cargo.lock index cc4e1f3..7604f86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,7 @@ name = "gclone" version = "0.1.0" dependencies = [ "colored 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -18,6 +19,57 @@ name = "lazy_static" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "same-file" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "walkdir" +version = "2.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] "checksum colored 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e9a455e156a4271e12fd0246238c380b1e223e3736663c7a18ed8b6362028a9" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" +"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 5c0e352..d7c04fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,11 +6,12 @@ edition = "2018" [dependencies] colored = "1.7.0" +walkdir = "2.2.7" [[bin]] name = "gclone" path = "src/gclone.rs" [[bin]] -name = "cdg" -path = "src/cdg.rs" +name = "pgd" +path = "src/pgd.rs" diff --git a/src/cdg.rs b/src/cdg.rs deleted file mode 100644 index 4a7984c..0000000 --- a/src/cdg.rs +++ /dev/null @@ -1,5 +0,0 @@ -use gclone::Cache; - -fn main() { - let cache = Cache::read(); -} diff --git a/src/gclone.rs b/src/gclone.rs index ad867f6..f4f4eda 100644 --- a/src/gclone.rs +++ b/src/gclone.rs @@ -6,7 +6,7 @@ use std::path::PathBuf; use colored::*; -use gclone::{git_dir, Cache}; +use gclone::{git_dir, Cache, Result}; macro_rules! unwrap { ($e: expr) => { @@ -55,9 +55,9 @@ fn help() { } -fn main() { +fn main() -> Result<()> { - let git_dir = git_dir(); + let git_dir = git_dir()?; // Parse args let url = match env::args().nth(1) { @@ -72,7 +72,7 @@ fn main() { }; if url == "-h" || url == "--help" { - return help(); + return Ok(help()); } let (server, owner, repo) = match parse_url(&url) { @@ -137,7 +137,7 @@ fn main() { eprintln!("{} {}", "info:".bold(), "done!"); // Append to cache - let mut cache = Cache::read(); + let mut cache = Cache::read()?; cache.append(path.display().to_string()); match cache.write() { @@ -150,4 +150,6 @@ fn main() { }, } + Ok(()) + } diff --git a/src/lib.rs b/src/lib.rs index a551146..083768e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ use std::fs::File; use std::io::{self, Write, BufRead, BufReader}; use colored::*; +use walkdir::WalkDir; macro_rules! impl_from_error { ($type: ty, $variant: path, $from: ty) => { @@ -43,11 +44,9 @@ impl fmt::Display for MError { } } -impl Error for MError { +impl Error for MError {} -} - -type Result = result::Result; +pub type Result = result::Result; pub fn git_dir() -> Result { Ok(env::var("GCLONE_PATH")?) @@ -56,6 +55,16 @@ pub fn git_dir() -> Result { pub struct Cache(Vec); impl Cache { + + pub fn new() -> Result { + Ok(Cache(WalkDir::new(git_dir()?) + .max_depth(3) + .into_iter() + .filter_map(|x| x.ok()) + .map(|x| x.path().display().to_string()) + .collect())) + } + pub fn read() -> Result { let mut path = PathBuf::from(git_dir()?); @@ -91,6 +100,18 @@ impl Cache { Ok(()) } + pub fn find(&self, dirname: &str) -> Vec { + let dirname = &format!("/{}", dirname); + let mut matches = vec![]; + for line in &self.0 { + if line.ends_with(dirname) { + matches.push(line.clone()); + } + } + + matches + } + pub fn append(&mut self, value: String) { self.0.push(value); } diff --git a/src/pgd.rs b/src/pgd.rs new file mode 100644 index 0000000..632e88a --- /dev/null +++ b/src/pgd.rs @@ -0,0 +1,125 @@ +use std::env; +use std::error::Error; +use std::process::exit; +use std::io::{stdout, stdin, Write}; +use std::num::Wrapping; +use colored::*; +use gclone::Cache; + +fn flush_stdout() { + stdout().flush().ok(); +} + +fn main() { + let request = match env::args().nth(1) { + Some(arg) => arg, + None => { + eprintln!("{} {}", + "error:".bold().red(), + "cdg expects an argument".bold()); + + exit(1); + }, + }; + + main_with_cache(&request, true); +} + +fn main_with_cache(request: &str, regen: bool) { + + let cache = Cache::read(); + + let matches = cache.find(&request); + + match matches.len() { + 0 => { + + if regen { + eprintln!("{} {}", + "warning:".bold().yellow(), + "directory not found, regenerating cache...".bold()); + + let cache = Cache::new(); + + match cache.write() { + Ok(_) => (), + Err(e) => { + eprintln!("{} {} {}", + "warning:".bold().yellow(), + "couldn't write cache:".bold(), + e.description()); + }, + } + + return main_with_cache(request, false); + + } else { + eprintln!("{} {}", + "error:".bold().red(), + "no such directory".bold()); + + exit(1); + } + }, + + 1 => { + println!("{}", matches[0]); + }, + + len => { + + eprintln!("{}", "info: multiple entries found, please select one".bold()); + + for (i, j) in matches.iter().enumerate() { + eprintln!("{} {}", + &format!("[{}]", i + 1).bold().blue(), + &format!("{}", j).yellow()); + } + + eprint!("{}", "Enter your choice: ".bold()); + flush_stdout(); + + let mut string = String::new(); + match stdin().read_line(&mut string) { + Ok(_) => (), + Err(e) => { + eprintln!("{} {} {}", + "error:".bold().red(), + "couldn't read line:".bold(), + e.description()); + + exit(1); + }, + }; + + // Pop the trailing \n of the string + string.pop(); + + // Use wrapping to move 0 to std::usize::MAX which is ok. + let value = (Wrapping(match string.parse::() { + Ok(v) => v, + Err(e) => { + eprintln!("{} {} {}", + "error:".bold().red(), + "couldn't parse integer:".bold(), + e.description()); + + exit(1); + } + }) - Wrapping(1)).0; + + if value >= len { + eprintln!("{} {}", + "error:".bold().red(), + "integer wasn't in the right range".bold()); + + exit(1); + } + + println!("{}", matches[value]); + }, + } + + +} +