use std::{env, fmt, result}; use std::process::exit; use std::error::Error; use std::path::PathBuf; 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) => { impl From<$from> for $type { fn from(e: $from) -> $type { $variant(e) } } } } #[derive(Debug)] pub enum MError { NoGclonePath(env::VarError), IoError(io::Error), } impl_from_error!(MError, MError::NoGclonePath, env::VarError); impl_from_error!(MError, MError::IoError, io::Error); impl fmt::Display for MError { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { MError::NoGclonePath(e) => write!(fmt, "{} {} {}", "error:".bold().red(), "couldn't read environment variable GCLONE_PATH".bold(), e), MError::IoError(e) => write!(fmt, "{} {} {}", "error:".bold().red(), "couldn't read or write cache:".bold(), e), } } } impl Error for MError {} pub type Result = result::Result; pub fn git_dir() -> Result { Ok(env::var("GCLONE_PATH")?) } 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()?); path.push(".cdgcache"); let file = match File::open(&path) { Ok(f) => f, Err(_) => return Ok(Cache(vec![])), }; let file = BufReader::new(file); let mut values = vec![]; for line in file.lines() { if let Ok(l) = line { values.push(l); } } Ok(Cache(values)) } pub fn write(&self) -> Result<()> { let mut path = PathBuf::from(git_dir()?); path.push(".cdgcache"); let mut file = File::create(path)?; for line in &self.0 { writeln!(file, "{}", line)?; } 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); } }