use crate::config::gate_args::GateArgs;
use crate::config::job_list_builder::JobListBuilder;
use crate::config::job_source::JobSource;
use crate::config::pre_build_resolver::PreBuildResolver;
use crate::execution::executor::Executor;
use crate::execution::job_outcome::JobOutcome;
use crate::execution::job_runner::JobRunner;
use crate::execution::outcome_line::OutcomeLine;
use crate::execution::run_summary::RunSummary;
use crate::ports::port_range_allocator::PortRangeAllocator;
use std::process::ExitCode;
use std::time::Duration;
pub struct GateRunner;
impl GateRunner {
pub async fn run(args: GateArgs) -> ExitCode {
let effective_args = match PreBuildResolver::resolve(&args)
.await
.map_err(|error| format!("PRE-BUILD FAILED: {error}"))
.and_then(JobSource::apply)
{
Ok(effective_args) => effective_args,
Err(error) => {
eprintln!("SLOTGATE — {error}");
return ExitCode::FAILURE;
}
};
let jobs = JobListBuilder::build(&effective_args);
Self::print_plan(&effective_args, jobs.len());
let outcomes = Self::executor_for(&effective_args)
.run_all(jobs, Self::print_outcome_as_it_completes)
.await;
let summary = RunSummary::from_outcomes(&outcomes);
println!();
println!("{}", summary.render());
summary.exit_code()
}
fn executor_for(args: &GateArgs) -> Executor {
let port_allocator = PortRangeAllocator::new(args.port_range_base, args.port_range_size);
let job_runner = JobRunner::new(
args.port_env_base.clone(),
args.port_env_count.clone(),
Duration::from_secs(args.timeout_secs),
args.log_dir.clone(),
);
Executor::new(args.max_parallel, port_allocator, job_runner)
}
fn print_plan(args: &GateArgs, job_count: usize) {
println!(
"SLOTGATE — {} jobs, max_parallel={}, ports {}-{} per slot",
job_count,
args.max_parallel,
args.port_range_base,
args.port_range_base as u32 + args.port_range_size as u32 - 1,
);
println!();
}
fn print_outcome_as_it_completes(outcome: &JobOutcome) {
println!("{}", OutcomeLine::render(outcome));
}
}