use super::executor::Executor; use super::terminal::Terminal; use super::utils::{which, Check}; use failure::Error; use std::collections::HashSet; use std::io; use std::path::{Path, PathBuf}; use std::process::Command; pub struct Git { git: Option, } pub struct Repositories<'a> { git: &'a Git, repositories: HashSet, } impl Git { pub fn new() -> Self { Self { git: which("git") } } pub fn get_repo_root>(&self, path: P) -> Option { match path.as_ref().canonicalize() { Ok(mut path) => { debug_assert!(path.exists()); if path.is_file() { debug!("{} is a file. Checking {}", path.display(), path.parent()?.display()); path = path.parent()?.to_path_buf(); } debug!("Checking if {} is a git repository", path.display()); if let Some(git) = &self.git { let output = Command::new(&git) .args(&["rev-parse", "--show-toplevel"]) .current_dir(path) .output(); if let Ok(output) = output { if !output.status.success() { return None; } return Some(String::from_utf8_lossy(&output.stdout).trim().to_string()); } } } Err(e) => match e.kind() { io::ErrorKind::NotFound => debug!("{} does not exists", path.as_ref().display()), _ => error!("Error looking for {}: {}", path.as_ref().display(), e), }, } None } pub fn pull>(&self, path: P, terminal: &mut Terminal, dry_run: bool) -> Option<(String, bool)> { let path = path.as_ref(); terminal.print_separator(format!("Pulling {}", path.display())); let git = self.git.as_ref().unwrap(); let success = || -> Result<(), Error> { Executor::new(git, dry_run) .args(&["pull", "--rebase", "--autostash"]) .current_dir(&path) .spawn()? .wait()? .check()?; Executor::new(git, dry_run) .args(&["submodule", "update", "--init", "--recursive"]) .current_dir(&path) .spawn()? .wait()? .check()?; Ok(()) }().is_ok(); Some((format!("git: {}", path.display()), success)) } } impl<'a> Repositories<'a> { pub fn new(git: &'a Git) -> Self { Self { git, repositories: HashSet::new(), } } pub fn insert>(&mut self, path: P) { if let Some(repo) = self.git.get_repo_root(path) { self.repositories.insert(repo); } } pub fn repositories(&self) -> &HashSet { &self.repositories } }