use super::pump_lines;
use crate::core::config::output::ArgvStep;
use anyhow::Context as _;
use tracing::info;
pub(crate) fn run_argv_step_streamed(
step: &ArgvStep,
work_dir: &str,
env_vars: &[(String, String)],
label: Option<&str>,
) -> anyhow::Result<()> {
let description = std::iter::once(step.command.as_str())
.chain(step.args.iter().map(String::as_str))
.collect::<Vec<_>>()
.join(" ");
info!("Running (argv, cwd={work_dir}): {description}");
let mut command = std::process::Command::new(&step.command);
command.args(&step.args).current_dir(work_dir);
for (key, value) in env_vars {
command.env(key, value);
}
run_prepared_command(command, label, &description)
}
pub(super) fn run_prepared_command(
mut command: std::process::Command,
label: Option<&str>,
description: &str,
) -> anyhow::Result<()> {
let Some(prefix) = label else {
let status = command
.status()
.with_context(|| format!("failed to spawn: {description}"))?;
if !status.success() {
anyhow::bail!("Command failed: {description}");
}
return Ok(());
};
let prefix = format!("[{prefix}] ");
let mut child = command
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.with_context(|| format!("failed to spawn: {description}"))?;
let stdout = child.stdout.take();
let stderr = child.stderr.take();
let p1 = prefix.clone();
let h_out = stdout.map(|s| std::thread::spawn(move || pump_lines(s, &p1)));
let p2 = prefix.clone();
let h_err = stderr.map(|s| std::thread::spawn(move || pump_lines(s, &p2)));
let status = child
.wait()
.with_context(|| format!("failed to wait on: {description}"))?;
if let Some(h) = h_out {
let _ = h.join();
}
if let Some(h) = h_err {
let _ = h.join();
}
if !status.success() {
anyhow::bail!("Command failed: {description}");
}
Ok(())
}