1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
use anyhow::Result;
use crate::instance::InstanceNet;
use crate::pool::{BuildRevision, PoolSpec};
use crate::tenant::{TenantConfig, TenantNet};
/// Minimal shell execution abstraction used by dev-mode builds.
///
/// This trait provides just shell execution and logging — enough for
/// `dev_build()` which runs `nix build` directly in the Lima VM.
pub trait ShellEnvironment: Send + Sync {
/// Execute a shell script in the VM.
fn shell_exec(&self, script: &str) -> Result<()>;
/// Execute a shell script in the VM and capture stdout.
fn shell_exec_stdout(&self, script: &str) -> Result<String>;
/// Execute a shell script with visible output.
fn shell_exec_visible(&self, script: &str) -> Result<()>;
/// Log an informational message.
fn log_info(&self, msg: &str);
/// Log a success message.
fn log_success(&self, msg: &str);
/// Log a warning (optional; default no-op for test fakes).
fn log_warn(&self, _msg: &str) {
// default implementation: no-op
}
/// Execute a shell script, capturing both stdout and stderr.
///
/// Returns `(stdout, stderr)` on success. On failure, returns the exit code and
/// captured stderr in the error. Used by the build pipeline to capture nix build
/// errors for structured reporting.
///
/// Default: falls back to `shell_exec_stdout` (stderr not captured).
fn shell_exec_capture(&self, script: &str) -> Result<(String, String)> {
let stdout = self.shell_exec_stdout(script)?;
Ok((stdout, String::new()))
}
}
/// Full build environment for orchestrated pool builds.
///
/// Extends [`ShellEnvironment`] with tenant/pool/network operations needed
/// by the pool build pipeline (ephemeral FC builder VMs, artifact recording).
/// mvm-build depends on mvm-core only. At runtime, the orchestrator provides
/// a concrete implementation that delegates to the runtime modules.
pub trait BuildEnvironment: ShellEnvironment {
/// Load a pool spec from the filesystem.
fn load_pool_spec(&self, tenant_id: &str, pool_id: &str) -> Result<PoolSpec>;
/// Load a tenant config from the filesystem.
fn load_tenant_config(&self, tenant_id: &str) -> Result<TenantConfig>;
/// Ensure the tenant network bridge is up.
fn ensure_bridge(&self, net: &TenantNet) -> Result<()>;
/// Create and attach a TAP device for a VM.
fn setup_tap(&self, net: &InstanceNet, bridge_name: &str) -> Result<()>;
/// Remove a TAP device.
fn teardown_tap(&self, tap_dev: &str) -> Result<()>;
/// Record a build revision and update the current symlink.
fn record_revision(
&self,
tenant_id: &str,
pool_id: &str,
revision: &BuildRevision,
) -> Result<()>;
}