1use anyhow::bail;
2use std::{
3 collections::BTreeMap,
4 process::{Command, Stdio},
5};
6pub fn exec(
7 command: &[String],
8 values: &BTreeMap<String, String>,
9 force: bool,
10) -> anyhow::Result<i32> {
11 let Some(program) = command.first() else {
12 bail!("a child command is required after --")
13 };
14 let mut child = Command::new(program);
15 child
16 .args(&command[1..])
17 .stdin(Stdio::inherit())
18 .stdout(Stdio::inherit())
19 .stderr(Stdio::inherit());
20 if force {
21 child.envs(values);
22 } else {
23 for (name, value) in values {
24 if std::env::var_os(name).is_none() {
25 child.env(name, value);
26 }
27 }
28 }
29 let status = child.status()?;
30 Ok(status.code().unwrap_or(128 + status.signal().unwrap_or(0)))
31}
32trait SignalCode {
33 fn signal(&self) -> Option<i32>;
34}
35impl SignalCode for std::process::ExitStatus {
36 fn signal(&self) -> Option<i32> {
37 #[cfg(unix)]
38 {
39 std::os::unix::process::ExitStatusExt::signal(self)
40 }
41 #[cfg(not(unix))]
42 {
43 None
44 }
45 }
46}