This commit is contained in:
Thomas Forgione 2019-02-21 15:21:27 +01:00
parent a56db54b72
commit 101e6a14a6
No known key found for this signature in database
GPG Key ID: 203DAEA747F48F41
5 changed files with 111 additions and 97 deletions

View File

@ -1,13 +1,16 @@
//! This module contains the cache manager. //! This module contains the cache manager.
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, Write};
use std::num::Wrapping; use std::num::Wrapping;
use std::path::PathBuf; use std::path::PathBuf;
use std::fs::File;
use std::io::{stdin, stdout, Write, BufRead, BufReader};
use walkdir::WalkDir;
use colored::*; use colored::*;
use crate::{Error, Result};
use walkdir::WalkDir;
use crate::git::GCLONE_PATH; use crate::git::GCLONE_PATH;
use crate::{Error, Result};
/// Flushes the stdout. /// Flushes the stdout.
fn flush_stdout() { fn flush_stdout() {
@ -22,20 +25,20 @@ fn flush_stdout() {
pub struct Cache(Vec<String>); pub struct Cache(Vec<String>);
impl Cache { impl Cache {
/// Generates the cache by traversing the files in the git directory. /// Generates the cache by traversing the files in the git directory.
pub fn generate() -> Cache { pub fn generate() -> Cache {
Cache(WalkDir::new(&*GCLONE_PATH) Cache(
.max_depth(3) WalkDir::new(&*GCLONE_PATH)
.into_iter() .max_depth(3)
.filter_map(|x| x.ok()) .into_iter()
.map(|x| x.path().display().to_string()) .filter_map(|x| x.ok())
.collect()) .map(|x| x.path().display().to_string())
.collect(),
)
} }
/// Reads the cache file. /// Reads the cache file.
pub fn read() -> Result<Cache> { pub fn read() -> Result<Cache> {
let mut path = PathBuf::from(&*GCLONE_PATH); let mut path = PathBuf::from(&*GCLONE_PATH);
path.push(".cdgcache"); path.push(".cdgcache");
@ -89,21 +92,23 @@ impl Cache {
/// Searches a directory, if multiple where found, prompt user for answer. /// Searches a directory, if multiple where found, prompt user for answer.
pub fn find_interactive(&self, dirname: &str) -> Result<String> { pub fn find_interactive(&self, dirname: &str) -> Result<String> {
let matches = self.find(dirname); let matches = self.find(dirname);
match matches.len() { match matches.len() {
0 => Err(Error::NoSuchDirectory), 0 => Err(Error::NoSuchDirectory),
1 => Ok(matches[0].clone()), 1 => Ok(matches[0].clone()),
len => { len => {
eprintln!(
eprintln!("{}", "info: multiple entries found, please select one".bold()); "{}",
"info: multiple entries found, please select one".bold()
);
for (i, j) in matches.iter().enumerate() { for (i, j) in matches.iter().enumerate() {
eprintln!("{} {}", eprintln!(
"{} {}",
&format!("[{}]", i + 1).bold().blue(), &format!("[{}]", i + 1).bold().blue(),
&format!("{}", j).yellow()); &format!("{}", j).yellow()
);
} }
eprint!("{}", "Enter your choice: ".bold()); eprint!("{}", "Enter your choice: ".bold());
@ -123,9 +128,8 @@ impl Cache {
} }
Ok(matches[value].clone()) Ok(matches[value].clone())
}, }
} }
} }
/// Appends a value to the cache. /// Appends a value to the cache.
@ -133,4 +137,3 @@ impl Cache {
self.0.push(value); self.0.push(value);
} }
} }

View File

@ -1,17 +1,14 @@
use std::process::exit;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::exit;
use colored::*; use colored::*;
use gclone::git::{clone, parse_url, GCLONE_PATH};
use gclone::{first_arg, Cache, Result}; use gclone::{first_arg, Cache, Result};
use gclone::git::{GCLONE_PATH, parse_url, clone};
fn help() { fn help() {}
}
fn main_result() -> Result<()> { fn main_result() -> Result<()> {
// Parse args // Parse args
let url = first_arg()?; let url = first_arg()?;
@ -38,7 +35,6 @@ fn main_result() -> Result<()> {
cache.write()?; cache.write()?;
Ok(()) Ok(())
} }
fn main() { fn main() {

View File

@ -3,7 +3,7 @@
use std::env; use std::env;
use std::fs::{create_dir_all, remove_dir_all}; use std::fs::{create_dir_all, remove_dir_all};
use std::path::Path; use std::path::Path;
use std::process::{Command, Stdio, exit}; use std::process::{exit, Command, Stdio};
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -29,7 +29,7 @@ macro_rules! unwrap {
Some(e) => e, Some(e) => e,
None => return Err(Error::GitUrlParseError), None => return Err(Error::GitUrlParseError),
} }
} };
} }
/// Transforms a git url to a (server, owner, repository) tuple. /// Transforms a git url to a (server, owner, repository) tuple.
@ -52,7 +52,7 @@ fn parse_http_url(input: &str) -> Result<(String, String, String)> {
let repo = String::from(split[split.len() - 1]); let repo = String::from(split[split.len() - 1]);
let owner = String::from(split[split.len() - 2]); let owner = String::from(split[split.len() - 2]);
let server = split[2 .. split.len() - 2].join("/"); let server = split[2..split.len() - 2].join("/");
Ok((server, owner, repo)) Ok((server, owner, repo))
} }
@ -75,20 +75,17 @@ fn parse_ssh_url(input: &str) -> Result<(String, String, String)> {
/// ///
/// If an error happens, it deletes the directory created. /// If an error happens, it deletes the directory created.
pub fn clone<P: AsRef<Path>>(url: &str, place: P) -> Result<()> { pub fn clone<P: AsRef<Path>>(url: &str, place: P) -> Result<()> {
match clone_dirty(url, &place) { match clone_dirty(url, &place) {
Ok(o) => Ok(o), Ok(o) => Ok(o),
Err(e) => { Err(e) => {
remove_dir_all(&place).ok(); remove_dir_all(&place).ok();
Err(e) Err(e)
}, }
} }
} }
/// Clones a git repository in the right place. /// Clones a git repository in the right place.
fn clone_dirty<P: AsRef<Path>>(url: &str, place: P) -> Result<()> { fn clone_dirty<P: AsRef<Path>>(url: &str, place: P) -> Result<()> {
let place = place.as_ref(); let place = place.as_ref();
if place.exists() { if place.exists() {
@ -104,8 +101,7 @@ fn clone_dirty<P: AsRef<Path>>(url: &str, place: P) -> Result<()> {
match command { match command {
Err(e) => Err(Error::GitCloneError(Some(e))), Err(e) => Err(Error::GitCloneError(Some(e))),
Ok(o) if ! o.success() => Err(Error::GitCloneError(None)), Ok(o) if !o.success() => Err(Error::GitCloneError(None)),
Ok(_) => Ok(()), Ok(_) => Ok(()),
} }
} }

View File

@ -12,8 +12,8 @@
#![warn(missing_docs)] #![warn(missing_docs)]
use std::{env, fmt, num, error, result};
use std::io; use std::io;
use std::{env, error, fmt, num, result};
use colored::*; use colored::*;
@ -29,7 +29,7 @@ macro_rules! impl_from_error {
$variant(e) $variant(e)
} }
} }
} };
} }
#[derive(Debug)] #[derive(Debug)]
@ -70,51 +70,70 @@ impl_from_error!(Error, Error::ParseIntError, num::ParseIntError);
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Error::NoGclonePath(e) => Error::NoGclonePath(e) => write!(
write!(fmt, "{} {} {}", fmt,
"error:".bold().red(), "{} {} {}",
"couldn't read environment variable GCLONE_PATH".bold(), "error:".bold().red(),
e), "couldn't read environment variable GCLONE_PATH".bold(),
Error::IoError(e) => e
write!(fmt, "{} {} {}", ),
"error:".bold().red(), Error::IoError(e) => write!(
"couldn't read or write cache:".bold(), fmt,
e), "{} {} {}",
Error::GitUrlParseError => "error:".bold().red(),
write!(fmt, "{} {}", "couldn't read or write cache:".bold(),
"error:".bold().red(), e
"couldn't guess server, owner and repo from url".bold()), ),
Error::GitCloneError(Some(e)) => Error::GitUrlParseError => write!(
write!(fmt, "{} {} {}", fmt,
"error:".bold().red(), "{} {}",
"couldn't clone git repository:".bold(), "error:".bold().red(),
e), "couldn't guess server, owner and repo from url".bold()
Error::GitCloneError(None) => ),
write!(fmt, "{} {}", Error::GitCloneError(Some(e)) => write!(
"error:".bold().red(), fmt,
"couldn't clone git repository".bold()), "{} {} {}",
Error::PathAlreadyExists => "error:".bold().red(),
write!(fmt, "{} {}", "couldn't clone git repository:".bold(),
"error:".bold().red(), e
"the path corresponding to the repository already exists".bold()), ),
Error::WrongArgument => Error::GitCloneError(None) => write!(
write!(fmt, "{} {}", fmt,
"error:".bold().red(), "{} {}",
"this program expects exactly one argument".bold()), "error:".bold().red(),
Error::ParseIntError(e) => "couldn't clone git repository".bold()
write!(fmt, "{} {} {}", ),
"error:".bold().red(), Error::PathAlreadyExists => write!(
"couldn't parse integer:".bold(), fmt,
e), "{} {}",
Error::OutsideRange => "error:".bold().red(),
write!(fmt, "{} {}", "the path corresponding to the repository already exists".bold()
"error:".bold().red(), ),
"integer is outside the range".bold()), Error::WrongArgument => write!(
Error::NoSuchDirectory => fmt,
write!(fmt, "{} {}", "{} {}",
"error:".bold().red(), "error:".bold().red(),
"no such directory was found".bold()), "this program expects exactly one argument".bold()
),
Error::ParseIntError(e) => write!(
fmt,
"{} {} {}",
"error:".bold().red(),
"couldn't parse integer:".bold(),
e
),
Error::OutsideRange => write!(
fmt,
"{} {}",
"error:".bold().red(),
"integer is outside the range".bold()
),
Error::NoSuchDirectory => write!(
fmt,
"{} {}",
"error:".bold().red(),
"no such directory was found".bold()
),
} }
} }
} }

View File

@ -1,5 +1,7 @@
use std::process::exit; use std::process::exit;
use colored::*; use colored::*;
use gclone::{first_arg, Cache, Error, Result}; use gclone::{first_arg, Cache, Error, Result};
fn main() { fn main() {
@ -15,26 +17,26 @@ fn main_result() -> Result<()> {
} }
fn main_with_cache(request: &str, regen: bool) -> Result<()> { fn main_with_cache(request: &str, regen: bool) -> Result<()> {
let (cache, just_generated) = match Cache::read() { let (cache, just_generated) = match Cache::read() {
Ok(c) => (c, false), Ok(c) => (c, false),
Err(_) => { Err(_) => {
let cache = Cache::generate(); let cache = Cache::generate();
cache.write()?; cache.write()?;
(cache, true) (cache, true)
}, }
}; };
let only_match = match cache.find_interactive(&request) { let only_match = match cache.find_interactive(&request) {
Err(Error::NoSuchDirectory) if regen && !just_generated => {
Err(Error::NoSuchDirectory) if regen && ! just_generated => { eprintln!(
eprintln!("{} {}", "{} {}",
"warning:".bold().yellow(), "warning:".bold().yellow(),
"directory not found, regenerating cache...".bold()); "directory not found, regenerating cache...".bold()
let cache = Cache::generate(); );
cache.write()?; let cache = Cache::generate();
return main_with_cache(request, false); cache.write()?;
}, return main_with_cache(request, false);
}
Err(e) => return Err(e), Err(e) => return Err(e),
Ok(x) => x, Ok(x) => x,
@ -43,6 +45,4 @@ fn main_with_cache(request: &str, regen: bool) -> Result<()> {
println!("{}", only_match); println!("{}", only_match);
Ok(()) Ok(())
} }