bctx_forge/substrate/
local.rs1use super::{Substrate, SubstrateCommand, SubstrateError, SubstrateResult};
2use std::process::Command;
3use std::time::Instant;
4
5pub struct LocalSubstrate;
6
7impl Substrate for LocalSubstrate {
8 fn execute(&self, cmd: SubstrateCommand) -> Result<SubstrateResult, SubstrateError> {
9 let start = Instant::now();
10
11 let mut builder = Command::new(&cmd.program);
12 builder.args(&cmd.args);
13
14 if let Some(ref cwd) = cmd.working_dir {
15 builder.current_dir(cwd);
16 }
17
18 let inherited_path = std::env::var("PATH").unwrap_or_default();
21 #[cfg(not(windows))]
22 {
23 let augmented = if inherited_path.is_empty() {
24 "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin".to_string()
25 } else {
26 format!("/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:{inherited_path}")
27 };
28 builder.env("PATH", augmented);
29 }
30 #[cfg(windows)]
31 if !inherited_path.is_empty() {
32 builder.env("PATH", &inherited_path);
33 }
34
35 for (k, v) in &cmd.env {
36 builder.env(k, v);
37 }
38
39 let output = builder.output().map_err(|e| {
40 if e.kind() == std::io::ErrorKind::NotFound {
41 SubstrateError::NotFound(cmd.program.clone())
42 } else {
43 SubstrateError::Io(e)
44 }
45 })?;
46
47 let duration_ms = start.elapsed().as_millis() as u64;
48
49 Ok(SubstrateResult {
50 stdout: output.stdout,
51 stderr: output.stderr,
52 exit_code: output.status.code().unwrap_or(-1),
53 duration_ms,
54 })
55 }
56
57 fn is_available(&self) -> bool {
58 true
59 }
60}