Skip to main content

bctx_forge/substrate/
mod.rs

1pub mod local;
2pub mod null;
3
4use anyhow::Result;
5
6#[derive(Debug, Clone)]
7pub struct SubstrateCommand {
8    pub program: String,
9    pub args: Vec<String>,
10    pub working_dir: Option<String>,
11    pub timeout_secs: u64,
12    pub capture_stderr: bool,
13    pub env: Vec<(String, String)>,
14}
15
16impl SubstrateCommand {
17    pub fn new(program: impl Into<String>) -> Self {
18        Self {
19            program: program.into(),
20            args: Vec::new(),
21            working_dir: None,
22            timeout_secs: 30,
23            capture_stderr: true,
24            env: Vec::new(),
25        }
26    }
27
28    pub fn args(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
29        self.args = args.into_iter().map(Into::into).collect();
30        self
31    }
32
33    pub fn cwd(mut self, dir: impl Into<String>) -> Self {
34        self.working_dir = Some(dir.into());
35        self
36    }
37
38    pub fn timeout(mut self, secs: u64) -> Self {
39        self.timeout_secs = secs;
40        self
41    }
42}
43
44#[derive(Debug, Clone)]
45pub struct SubstrateResult {
46    pub stdout: Vec<u8>,
47    pub stderr: Vec<u8>,
48    pub exit_code: i32,
49    pub duration_ms: u64,
50}
51
52impl SubstrateResult {
53    pub fn stdout_str(&self) -> String {
54        String::from_utf8_lossy(&self.stdout).into_owned()
55    }
56
57    pub fn stderr_str(&self) -> String {
58        String::from_utf8_lossy(&self.stderr).into_owned()
59    }
60
61    pub fn succeeded(&self) -> bool {
62        self.exit_code == 0
63    }
64}
65
66#[derive(Debug, thiserror::Error)]
67pub enum SubstrateError {
68    #[error("command not found: {0}")]
69    NotFound(String),
70    #[error("execution timed out after {0}s")]
71    Timeout(u64),
72    #[error("io error: {0}")]
73    Io(#[from] std::io::Error),
74    #[error("spawn failed: {0}")]
75    Spawn(String),
76}
77
78pub trait Substrate: Send + Sync {
79    fn execute(&self, cmd: SubstrateCommand) -> Result<SubstrateResult, SubstrateError>;
80    fn is_available(&self) -> bool;
81}