Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
97 lines
3.3 KiB
Rust
97 lines
3.3 KiB
Rust
use anyhow::Context;
|
|
use std::path::Path;
|
|
use wasi_common::pipe::WritePipe;
|
|
use wasmtime::{Config, Engine, Linker, Module, Store};
|
|
use wasmtime_wasi::tokio::{add_to_linker, WasiCtxBuilder};
|
|
|
|
pub fn instantiate(data: &[u8], bin_name: &str, workspace: Option<&Path>) -> anyhow::Result<()> {
|
|
run(data, bin_name, workspace, false)
|
|
}
|
|
pub fn instantiate_inherit_stdio(
|
|
data: &[u8],
|
|
bin_name: &str,
|
|
workspace: Option<&Path>,
|
|
) -> anyhow::Result<()> {
|
|
run(data, bin_name, workspace, true)
|
|
}
|
|
|
|
fn run(
|
|
data: &[u8],
|
|
bin_name: &str,
|
|
workspace: Option<&Path>,
|
|
inherit_stdio: bool,
|
|
) -> anyhow::Result<()> {
|
|
let stdout = WritePipe::new_in_memory();
|
|
let stdout_ = stdout.clone();
|
|
let stderr = WritePipe::new_in_memory();
|
|
let stderr_ = stderr.clone();
|
|
|
|
let r = tokio::runtime::Runtime::new()
|
|
.expect("create runtime")
|
|
.block_on(async move {
|
|
let mut config = Config::new();
|
|
config.async_support(true);
|
|
let engine = Engine::new(&config)?;
|
|
let module = Module::new(&engine, &data).context("failed to create wasm module")?;
|
|
let mut linker = Linker::new(&engine);
|
|
add_to_linker(&mut linker, |cx| cx)?;
|
|
|
|
// Create our wasi context.
|
|
let mut builder = WasiCtxBuilder::new();
|
|
|
|
if inherit_stdio {
|
|
builder = builder.inherit_stdio();
|
|
} else {
|
|
builder = builder
|
|
.stdout(Box::new(stdout_.clone()))
|
|
.stderr(Box::new(stderr_.clone()));
|
|
}
|
|
|
|
builder = builder.arg(bin_name)?.arg(".")?;
|
|
|
|
if let Some(workspace) = workspace {
|
|
println!("preopen: {:?}", workspace);
|
|
let preopen_dir = unsafe { cap_std::fs::Dir::open_ambient_dir(workspace) }?;
|
|
builder = builder.preopened_dir(preopen_dir, ".")?;
|
|
}
|
|
|
|
for (var, val) in super::test_suite_environment() {
|
|
builder = builder.env(var, val)?;
|
|
}
|
|
|
|
// tokio does not yet support the sync family of fdflags, because cap-std-sync
|
|
// does not.
|
|
builder = builder.env("NO_FDFLAGS_SYNC_SUPPORT", "1")?;
|
|
|
|
let mut store = Store::new(&engine, builder.build());
|
|
|
|
let instance = linker.instantiate_async(&mut store, &module).await?;
|
|
let start = instance.get_typed_func::<(), (), _>(&mut store, "_start")?;
|
|
start
|
|
.call_async(&mut store, ())
|
|
.await
|
|
.map_err(anyhow::Error::from)
|
|
});
|
|
|
|
match r {
|
|
Ok(()) => Ok(()),
|
|
Err(trap) => {
|
|
let stdout = stdout
|
|
.try_into_inner()
|
|
.expect("sole ref to stdout")
|
|
.into_inner();
|
|
if !stdout.is_empty() {
|
|
println!("guest stdout:\n{}\n===", String::from_utf8_lossy(&stdout));
|
|
}
|
|
let stderr = stderr
|
|
.try_into_inner()
|
|
.expect("sole ref to stderr")
|
|
.into_inner();
|
|
if !stderr.is_empty() {
|
|
println!("guest stderr:\n{}\n===", String::from_utf8_lossy(&stderr));
|
|
}
|
|
Err(trap.context(format!("error while testing Wasm module '{}'", bin_name,)))
|
|
}
|
|
}
|
|
}
|