use std::path::PathBuf;
use async_trait::async_trait;
use machi_types::{ErrorCode, MachiError};
use crate::host::SpawnOpts;
#[derive(Debug, Clone, Default)]
pub struct IsolationEnv {
pub cwd: Option<PathBuf>,
pub label: Option<String>,
}
#[async_trait]
pub trait IsolationBackend: Send + Sync {
fn name(&self) -> &'static str;
async fn prepare(&self, opts: &SpawnOpts) -> Result<IsolationEnv, MachiError>;
async fn cleanup(&self, env: &IsolationEnv) -> Result<(), MachiError>;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct InProcessIsolation;
#[async_trait]
impl IsolationBackend for InProcessIsolation {
fn name(&self) -> &'static str {
"in_process"
}
async fn prepare(&self, opts: &SpawnOpts) -> Result<IsolationEnv, MachiError> {
Ok(IsolationEnv {
cwd: None,
label: opts.label.clone(),
})
}
async fn cleanup(&self, _env: &IsolationEnv) -> Result<(), MachiError> {
Ok(())
}
}
#[must_use]
pub fn isolation_error(backend: &str, message: impl Into<String>) -> MachiError {
MachiError::new(
ErrorCode::HostIsolation,
format!("isolation backend '{backend}': {}", message.into()),
)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::host::SpawnOpts;
#[tokio::test]
async fn in_process_prepare_cleanup() {
let backend = InProcessIsolation;
assert_eq!(backend.name(), "in_process");
let env = backend
.prepare(&SpawnOpts::new("hi").with_label("child"))
.await
.expect("prepare");
assert_eq!(env.label.as_deref(), Some("child"));
assert!(env.cwd.is_none());
backend.cleanup(&env).await.expect("cleanup");
}
}