use std::collections::BTreeSet;
use std::time::Instant;
use crate::errors::{ErrorCode, ErrorInfo, aggregate_exit};
use crate::exec::{self, RUN_HEADERS, RunSummary};
use crate::output::Emitter;
use crate::state;
use crate::workspace::{Repo, Workspace};
pub async fn run(
ws: &Workspace,
targets: Vec<Repo>,
cmd: Option<String>,
with_deps: bool,
jobs: usize,
max_bytes: usize,
human: bool,
) -> i32 {
let started = Instant::now();
let target_names: BTreeSet<String> = targets.iter().map(|r| r.name.clone()).collect();
let waves: Vec<Vec<String>> = if with_deps {
let mut upstreams: BTreeSet<String> = BTreeSet::new();
for name in &target_names {
upstreams.extend(crate::graph::transitive_upstreams(ws, name));
}
upstreams.retain(|u| !target_names.contains(u));
let mut set = target_names.clone();
set.extend(state::filter_stale(ws, &upstreams, max_bytes).await);
crate::graph::topo_waves(ws, &set)
} else {
vec![target_names.iter().cloned().collect()]
};
let mut emitter = Emitter::new(human, RUN_HEADERS);
let command_for = |repo: &Repo| -> Result<String, ErrorInfo> {
if let Some(c) = &cmd {
if target_names.contains(&repo.name) {
return Ok(c.clone());
}
}
repo.default_cmd.clone().ok_or_else(|| {
ErrorInfo::new(
ErrorCode::NoDefaultCmd,
format!("repo {:?} has no default_cmd", repo.name),
)
})
};
let (passed, failed) =
exec::execute_waves(ws, waves, command_for, jobs, max_bytes, true, &mut emitter).await;
let summary = RunSummary::new(passed, failed, started.elapsed().as_millis() as u64);
emitter.emit_summary(&summary, summary.human());
emitter.finish();
aggregate_exit(failed > 0, false)
}