use crate::{Afterburner, AfterburnerError, EnvAccess, ScriptInvocation};
use anyhow::{Context, Result};
use std::collections::BTreeMap;
use std::io::Write;
use super::args::Cli;
use super::manifold::build_manifold;
pub fn build_invocation(cli: &Cli, script_label: &str, user_args: &[String]) -> ScriptInvocation {
let mut argv = Vec::with_capacity(2 + user_args.len());
argv.push("burn".to_string());
argv.push(script_label.to_string());
argv.extend(user_args.iter().cloned());
ScriptInvocation {
argv,
env: collect_env(cli),
cwd: cli_cwd(),
}
}
pub fn cli_cwd() -> String {
std::env::current_dir()
.map(|p| p.to_string_lossy().into_owned())
.unwrap_or_else(|_| "/".to_string())
}
fn collect_env(cli: &Cli) -> BTreeMap<String, String> {
let manifold = build_manifold(cli);
let mut env: BTreeMap<String, String> = match &manifold.env {
EnvAccess::None => BTreeMap::new(),
EnvAccess::AllowList(keys) => keys
.iter()
.filter_map(|k| std::env::var(k).ok().map(|v| (k.clone(), v)))
.collect(),
EnvAccess::Full => std::env::vars().collect(),
};
for path in &cli.env_file {
if let Ok(text) = std::fs::read_to_string(path) {
for line in text.lines() {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let Some(eq) = line.find('=') else {
continue;
};
let key = line[..eq].trim();
if key.is_empty() {
continue;
}
let mut val = line[eq + 1..].trim();
if val.len() >= 2
&& ((val.starts_with('"') && val.ends_with('"'))
|| (val.starts_with('\'') && val.ends_with('\'')))
{
val = &val[1..val.len() - 1];
}
env.insert(key.to_string(), val.to_string());
}
}
}
env
}
pub fn execute(
ab: &Afterburner,
source: &str,
script_label: &str,
user_args: &[String],
cli: &Cli,
) -> Result<()> {
let invocation = build_invocation(cli, script_label, user_args);
let outcome = ab
.run_script_with(source, &invocation, ab.default_limits())
.map_err(|e: AfterburnerError| anyhow::anyhow!("{e}"))?;
std::io::stdout()
.write_all(&outcome.stdout)
.context("write script stdout")?;
std::io::stderr()
.write_all(&outcome.stderr)
.context("write script stderr")?;
if outcome.exit_code != 0 {
std::process::exit(outcome.exit_code);
}
Ok(())
}