Perform git pulls in parallel (fix #48)

This commit is contained in:
Roey Darwish Dror
2019-05-22 08:55:50 +03:00
parent 48653f555d
commit 2d15814996
5 changed files with 240 additions and 26 deletions

View File

@@ -1,12 +1,16 @@
use crate::error::Error;
use crate::error::{Error, ErrorKind};
use crate::executor::{CommandExt, RunType};
use crate::terminal::print_separator;
use crate::utils::{which, HumanizedPath};
use console::style;
use futures::future::{join_all, Future};
use log::{debug, error};
use std::collections::HashSet;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;
use tokio::runtime::Runtime;
use tokio_process::CommandExt as TokioCommandExt;
#[derive(Debug)]
pub struct Git {
@@ -55,18 +59,63 @@ impl Git {
None
}
pub fn pull<P: AsRef<Path>>(&self, path: P, run_type: RunType) -> Result<(), Error> {
let path = path.as_ref();
print_separator(format!("Pulling {}", HumanizedPath::from(path)));
pub fn multi_pull(&self, repositories: &Repositories, run_type: RunType) -> Result<(), Error> {
if repositories.repositories.is_empty() {
return Ok(());
}
let git = self.git.as_ref().unwrap();
run_type
.execute(git)
.args(&["pull", "--rebase", "--autostash"])
.current_dir(&path)
.check_run()
print_separator("Git repositories");
if let RunType::Dry = run_type {
repositories
.repositories
.iter()
.for_each(|repo| println!("Would pull {}", HumanizedPath::from(std::path::Path::new(&repo))));
return Ok(());
}
let futures: Vec<_> = repositories
.repositories
.iter()
.map(|repo| {
let repo = repo.clone();
let path = format!("{}", HumanizedPath::from(std::path::Path::new(&repo)));
println!("{} {}", style("Pulling").cyan(), path);
Command::new(git)
.args(&["pull", "--rebase", "--autostash"])
.current_dir(&repo)
.output_async()
.then(move |result| match result {
Ok(output) => {
if output.status.success() {
println!("{} {}", style("Pulled").green(), path);
Ok(true) as Result<bool, Error>
} else {
println!("{} pulling {}", style("Failed").red(), path);
if let Ok(text) = std::str::from_utf8(&output.stderr) {
print!("{}", text);
}
Ok(false)
}
}
Err(e) => {
println!("{} pulling {}: {}", style("Failed").red(), path, e);
Ok(false)
}
})
})
.collect();
let mut runtime = Runtime::new().unwrap();
let results: Vec<bool> = runtime.block_on(join_all(futures))?;
if results.into_iter().any(|success| !success) {
Err(ErrorKind::StepFailed.into())
} else {
Ok(())
}
}
}
@@ -83,8 +132,4 @@ impl<'a> Repositories<'a> {
self.repositories.insert(repo);
}
}
pub fn repositories(&self) -> &HashSet<String> {
&self.repositories
}
}