diff --git a/config.example.toml b/config.example.toml index a75ef178..7a38a2d9 100644 --- a/config.example.toml +++ b/config.example.toml @@ -59,3 +59,6 @@ #yay_arguments = "--nodevel" #trizen_arguments = "--devel" #enable_tlmgr = true + +#[git] +#max_concurrency = 5 diff --git a/src/config.rs b/src/config.rs index ad8d5a07..58927213 100644 --- a/src/config.rs +++ b/src/config.rs @@ -50,6 +50,11 @@ pub enum Step { Tmux, } +#[derive(Deserialize, Default, Debug)] +pub struct Git { + max_concurrency: Option, +} + #[derive(Deserialize, Default, Debug)] pub struct Brew { greedy_cask: Option, @@ -93,6 +98,7 @@ pub struct ConfigFile { composer: Option, brew: Option, linux: Option, + git: Option, } impl ConfigFile { @@ -440,6 +446,11 @@ impl Config { .and_then(|linux| linux.dnf_arguments.as_deref()) } + /// Concurrency limit for git + pub fn git_concurrency_limit(&self) -> Option { + self.config_file.git.as_ref().and_then(|git| git.max_concurrency) + } + /// Extra yay arguments #[allow(dead_code)] pub fn enable_tlmgr_linux(&self) -> bool { diff --git a/src/steps/git.rs b/src/steps/git.rs index 93ae78a7..d30848c2 100644 --- a/src/steps/git.rs +++ b/src/steps/git.rs @@ -1,19 +1,22 @@ +use std::collections::HashSet; +use std::io; +use std::path::{Path, PathBuf}; +use std::process::{Command, Output}; + +use anyhow::Result; +use console::style; +use futures::stream::{iter, FuturesUnordered}; +use futures::StreamExt; +use glob::{glob_with, MatchOptions}; +use log::{debug, error}; +use tokio::process::Command as AsyncCommand; +use tokio::runtime; + use crate::error::SkipStep; use crate::execution_context::ExecutionContext; use crate::executor::{CommandExt, RunType}; use crate::terminal::print_separator; use crate::utils::{which, PathExt}; -use anyhow::Result; -use console::style; -use futures::future::try_join_all; -use glob::{glob_with, MatchOptions}; -use log::{debug, error}; -use std::collections::HashSet; -use std::io; -use std::path::{Path, PathBuf}; -use std::process::{Command, Output}; -use tokio::process::Command as AsyncCommand; -use tokio::runtime; #[cfg(windows)] static PATH_PREFIX: &str = "\\\\?\\"; @@ -189,7 +192,7 @@ impl Git { return Ok(()); } - let futures: Vec<_> = repositories + let futures_iterator = repositories .repositories .iter() .filter(|repo| match has_remotes(git, repo) { @@ -203,13 +206,19 @@ impl Git { } _ => true, // repo has remotes or command to check for remotes has failed. proceed to pull anyway. }) - .map(|repo| pull_repository(repo.clone(), &git, ctx)) - .collect(); + .map(|repo| pull_repository(repo.clone(), &git, ctx)); + + let stream_of_futures = if let Some(limit) = ctx.config().git_concurrency_limit() { + iter(futures_iterator).buffer_unordered(limit).boxed() + } else { + futures_iterator.collect::>().boxed() + }; let mut basic_rt = runtime::Runtime::new()?; - basic_rt.block_on(async { try_join_all(futures).await })?; + let results = basic_rt.block_on(async { stream_of_futures.collect::>>().await }); - Ok(()) + let error = results.into_iter().find(|r| r.is_err()); + error.unwrap_or(Ok(())) } }