Files
sausage/spikes/s2-shell/src/main.rs
T
surma 9e9cde5241 spikes: six v3 spikes (V8 harness, WASI shell, git, builder, http hook, esbuild)
Throwaway prototypes for Sausage v3. Plan and decisions:
~/research/sausage-v3/PLAN.md. Results and evidence: the spike READMEs.
2026-11-06 14:03:20 +00:00

91 lines
2.8 KiB
Rust

//! Runs the shell component against one virtual world root for the S2 experiment.
mod process;
use sausage_vfs::{
Host, Mounts, Process,
adapter::{self, Adapter, View},
};
use std::sync::Arc;
use wasmtime::{
Engine, Store,
component::{Component, Linker, ResourceTable},
};
use wasmtime_wasi::{WasiCtx, WasiCtxBuilder, WasiCtxView, WasiView};
struct State {
wasi: WasiCtx,
table: ResourceTable,
fs: Adapter,
runtime: Arc<process::Runtime>,
children: Vec<process::Child>,
}
impl WasiView for State {
fn ctx(&mut self) -> WasiCtxView<'_> {
WasiCtxView {
ctx: &mut self.wasi,
table: &mut self.table,
}
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let args: Vec<String> = std::env::args().collect();
anyhow::ensure!(
args.len() == 5 && args[3] == "-c",
"usage: s2-shell WORLD SHELL.wasm -c SCRIPT"
);
let mut config = wasmtime::Config::new();
let mut cache = wasmtime::CacheConfig::new();
cache.with_directory("/tmp/s2-shell/cache");
config.cache(Some(wasmtime::Cache::new(cache)?));
let engine = Engine::new(&config)?;
let component = Component::from_file(&engine, &args[2])?;
let runtime = Arc::new(process::Runtime {
engine: engine.clone(),
utility: Component::from_file(&engine, std::path::Path::new(&args[1]).join("bin/cat"))?,
world: args[1].clone().into(),
});
let mut mounts = Mounts::default();
mounts.mount(
"/",
Arc::new(Host::new(&args[1], Process::default())?),
false,
);
let mut linker = Linker::new(&engine);
wasmtime_wasi::p2::add_to_linker_async(&mut linker)?;
adapter::add_to_linker(&mut linker, |s: &mut State| View {
adapter: &mut s.fs,
table: &mut s.table,
})?;
process::add(&mut linker)?;
let mut wasi = WasiCtxBuilder::new();
wasi.inherit_stdio()
.args(&["sh", "--noprofile", "--norc", "-c", &args[4]])
.env("PATH", "/bin")
.env("HOME", "/")
.env("PWD", "/")
.initial_cwd("/");
let mut store = Store::new(
&engine,
State {
wasi: wasi.build(),
table: ResourceTable::new(),
fs: Adapter::new(mounts),
runtime,
children: Vec::new(),
},
);
let command =
wasmtime_wasi::p2::bindings::Command::instantiate_async(&mut store, &component, &linker)
.await?;
let code = match command.wasi_cli_run().call_run(&mut store).await {
Ok(Ok(())) => 0,
Ok(Err(())) => 1,
Err(error) => match error.downcast_ref::<wasmtime_wasi::I32Exit>() {
Some(exit) => exit.0,
None => return Err(error.into()),
},
};
std::process::exit(code);
}