greentic_dev/
passthrough.rs

1use anyhow::{Context, Result, anyhow, bail};
2use std::env;
3use std::ffi::OsString;
4use std::path::{Path, PathBuf};
5use std::process::{Command, ExitStatus, Stdio};
6
7/// Resolve a binary by name using env override, optional workspace target, then PATH.
8pub fn resolve_binary(name: &str) -> Result<PathBuf> {
9    let env_key = format!("GREENTIC_DEV_BIN_{}", name.replace('-', "_").to_uppercase());
10    if let Ok(path) = env::var(&env_key) {
11        let pb = PathBuf::from(path);
12        if pb.exists() {
13            return Ok(pb);
14        }
15        bail!("{env_key} points to non-existent binary: {}", pb.display());
16    }
17
18    if let Ok(path) = which::which(name) {
19        return Ok(path);
20    }
21
22    // Optional workspace target resolution (debug and release) as a fallback.
23    if let Ok(cwd) = env::current_dir() {
24        for dir in ["target/debug", "target/release"] {
25            let candidate = cwd.join(dir).join(name);
26            if candidate.exists() {
27                return Ok(candidate);
28            }
29        }
30    }
31
32    which::which(name).with_context(|| {
33        format!("failed to find `{name}` in PATH; set {env_key} or install {name}")
34    })
35}
36
37pub fn run_passthrough(bin: &Path, args: &[OsString], verbose: bool) -> Result<ExitStatus> {
38    if verbose {
39        eprintln!("greentic-dev passthrough -> {} {:?}", bin.display(), args);
40        let _ = Command::new(bin)
41            .arg("--version")
42            .stdout(Stdio::inherit())
43            .stderr(Stdio::inherit())
44            .status();
45    }
46
47    Command::new(bin)
48        .args(args)
49        .stdin(Stdio::inherit())
50        .stdout(Stdio::inherit())
51        .stderr(Stdio::inherit())
52        .status()
53        .map_err(|e| anyhow!("failed to execute {}: {e}", bin.display()))
54}