machi_runtime/
isolation.rs1use std::path::PathBuf;
7
8use async_trait::async_trait;
9use machi_types::{ErrorCode, MachiError};
10
11use crate::host::SpawnOpts;
12
13#[derive(Debug, Clone, Default)]
15pub struct IsolationEnv {
16 pub cwd: Option<PathBuf>,
18 pub label: Option<String>,
20}
21
22#[async_trait]
27pub trait IsolationBackend: Send + Sync {
28 fn name(&self) -> &'static str;
30
31 async fn prepare(&self, opts: &SpawnOpts) -> Result<IsolationEnv, MachiError>;
37
38 async fn cleanup(&self, env: &IsolationEnv) -> Result<(), MachiError>;
44}
45
46#[derive(Debug, Default, Clone, Copy)]
51pub struct InProcessIsolation;
52
53#[async_trait]
54impl IsolationBackend for InProcessIsolation {
55 fn name(&self) -> &'static str {
56 "in_process"
57 }
58
59 async fn prepare(&self, opts: &SpawnOpts) -> Result<IsolationEnv, MachiError> {
60 Ok(IsolationEnv {
62 cwd: None,
63 label: opts.label.clone(),
64 })
65 }
66
67 async fn cleanup(&self, _env: &IsolationEnv) -> Result<(), MachiError> {
68 Ok(())
69 }
70}
71
72#[must_use]
74pub fn isolation_error(backend: &str, message: impl Into<String>) -> MachiError {
75 MachiError::new(
76 ErrorCode::HostIsolation,
77 format!("isolation backend '{backend}': {}", message.into()),
78 )
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::host::SpawnOpts;
85
86 #[tokio::test]
87 async fn in_process_prepare_cleanup() {
88 let backend = InProcessIsolation;
89 assert_eq!(backend.name(), "in_process");
90 let env = backend
91 .prepare(&SpawnOpts::new("hi").with_label("child"))
92 .await
93 .expect("prepare");
94 assert_eq!(env.label.as_deref(), Some("child"));
95 assert!(env.cwd.is_none());
96 backend.cleanup(&env).await.expect("cleanup");
97 }
98}