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(
WalkDir::new(&*GCLONE_PATH)
.max_depth(3) .max_depth(3)
.into_iter() .into_iter()
.filter_map(|x| x.ok()) .filter_map(|x| x.ok())
.map(|x| x.path().display().to_string()) .map(|x| x.path().display().to_string())
.collect()) .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.
@ -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() {
@ -107,5 +104,4 @@ fn clone_dirty<P: AsRef<Path>>(url: &str, place: P) -> Result<()> {
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(), "error:".bold().red(),
"couldn't read environment variable GCLONE_PATH".bold(), "couldn't read environment variable GCLONE_PATH".bold(),
e), e
Error::IoError(e) => ),
write!(fmt, "{} {} {}", Error::IoError(e) => write!(
fmt,
"{} {} {}",
"error:".bold().red(), "error:".bold().red(),
"couldn't read or write cache:".bold(), "couldn't read or write cache:".bold(),
e), e
Error::GitUrlParseError => ),
write!(fmt, "{} {}", Error::GitUrlParseError => write!(
fmt,
"{} {}",
"error:".bold().red(), "error:".bold().red(),
"couldn't guess server, owner and repo from url".bold()), "couldn't guess server, owner and repo from url".bold()
Error::GitCloneError(Some(e)) => ),
write!(fmt, "{} {} {}", Error::GitCloneError(Some(e)) => write!(
fmt,
"{} {} {}",
"error:".bold().red(), "error:".bold().red(),
"couldn't clone git repository:".bold(), "couldn't clone git repository:".bold(),
e), e
Error::GitCloneError(None) => ),
write!(fmt, "{} {}", Error::GitCloneError(None) => write!(
fmt,
"{} {}",
"error:".bold().red(), "error:".bold().red(),
"couldn't clone git repository".bold()), "couldn't clone git repository".bold()
Error::PathAlreadyExists => ),
write!(fmt, "{} {}", Error::PathAlreadyExists => write!(
fmt,
"{} {}",
"error:".bold().red(), "error:".bold().red(),
"the path corresponding to the repository already exists".bold()), "the path corresponding to the repository already exists".bold()
Error::WrongArgument => ),
write!(fmt, "{} {}", Error::WrongArgument => write!(
fmt,
"{} {}",
"error:".bold().red(), "error:".bold().red(),
"this program expects exactly one argument".bold()), "this program expects exactly one argument".bold()
Error::ParseIntError(e) => ),
write!(fmt, "{} {} {}", Error::ParseIntError(e) => write!(
fmt,
"{} {} {}",
"error:".bold().red(), "error:".bold().red(),
"couldn't parse integer:".bold(), "couldn't parse integer:".bold(),
e), e
Error::OutsideRange => ),
write!(fmt, "{} {}", Error::OutsideRange => write!(
fmt,
"{} {}",
"error:".bold().red(), "error:".bold().red(),
"integer is outside the range".bold()), "integer is outside the range".bold()
Error::NoSuchDirectory => ),
write!(fmt, "{} {}", Error::NoSuchDirectory => write!(
fmt,
"{} {}",
"error:".bold().red(), "error:".bold().red(),
"no such directory was found".bold()), "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(); let cache = Cache::generate();
cache.write()?; cache.write()?;
return main_with_cache(request, false); 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(())
} }