Skip to content
This repository was archived by the owner on Jan 27, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
809 changes: 479 additions & 330 deletions Cargo.lock

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ path = "src/main.rs"

[dependencies]
clap = { version = "4.5.53", features = ["derive"] }
wizer = "10.0.0"
anyhow = { workspace = true }
wasmtime = "36"
wasmtime-wasi = "36"
tokio = { version = "1", features = ["macros"] }
wasmtime = "39"
wasmtime-wasi = "39"
wasmtime-wizer = { version = "39", features = ["wasmtime"] }

[dev-dependencies]
criterion = "0.8.0"
Expand Down
4 changes: 2 additions & 2 deletions crates/cli/benches/benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use anyhow::{bail, Result};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use wasmtime::{Engine, Linker, Module, Store};
use wasmtime_wasi::{
p1::WasiP1Ctx,
p2::pipe::{MemoryInputPipe, MemoryOutputPipe},
preview1::WasiP1Ctx,
WasiCtxBuilder,
};

Expand Down Expand Up @@ -112,7 +112,7 @@ impl WasmCase {
.stderr(MemoryOutputPipe::new(usize::MAX))
.args(&self.wasi_args)
.build_p1();
wasmtime_wasi::preview1::add_to_linker_sync(&mut linker, |cx| cx)?;
wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |cx| cx)?;
let store = Store::new(engine, wasi);
let module = Module::new(engine, &self.wasm)?;
Ok((linker, module, store))
Expand Down
118 changes: 46 additions & 72 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
use anyhow::Result;
use clap::Parser;
use std::{
fs,
path::{Path, PathBuf},
process,
rc::Rc,
sync::OnceLock,
use std::{fs, path::PathBuf, process};
use wasmtime::{Config, Engine, Linker, Store};
use wasmtime_wasi::{
p1::WasiP1Ctx, p2::pipe::MemoryInputPipe, DirPerms, FilePerms, WasiCtxBuilder,
};
use wasmtime::Linker;
use wasmtime_wasi::{p2::pipe::MemoryInputPipe, DirPerms, FilePerms, WasiCtxBuilder};
use wizer::{StoreData, Wizer};

static INPUT: OnceLock<MemoryInputPipe> = OnceLock::new();
static PRELOAD_PATH: OnceLock<Option<PathBuf>> = OnceLock::new();
use wasmtime_wizer::Wizer;

#[derive(Debug, Parser)]
#[clap(name = "ruvy_cli", about = "Compile ruby code into a Wasm module.")]
Expand All @@ -29,7 +22,8 @@ struct Opt {
output: PathBuf,
}

fn main() -> Result<()> {
#[tokio::main]
async fn main() -> Result<()> {
let opt = Opt::parse();
let ruby_code = match fs::read_to_string(&opt.input) {
Ok(code) => code,
Expand All @@ -39,71 +33,51 @@ fn main() -> Result<()> {
}
};

let engine = include_bytes!(concat!(env!("OUT_DIR"), "/engine.wasm"));
let wizer = setup_wizer(&ruby_code, opt.preload)?;
let user_wasm = wizer.run(engine)?;
fs::write(opt.output, user_wasm)?;
let ruby_engine = include_bytes!(concat!(env!("OUT_DIR"), "/engine.wasm"));
let user_wasm = wizen(ruby_engine, &ruby_code, opt.preload).await?;

fs::write(opt.output, user_wasm)?;
Ok(())
}

fn setup_wizer(ruby_code: &str, preload_path: Option<PathBuf>) -> Result<Wizer> {
// We lose the ability to return an error when performing this operation
// inside `add_to_linker_sync` so we perform the same operation here so
// can return an error if it fails.
if let Some(preload_path) = &preload_path {
let mut wasi_builder = WasiCtxBuilder::new();
add_preload_path_to_wasi_ctx(&mut wasi_builder, preload_path)?;
}

// We can't move the ruby code or preload path into the `make_linker`
// since they don't implement copy so put them in a static `OnceLock`
// instead. This assumes this code is only only called once during the
// process's lifetime.
INPUT
.set(MemoryInputPipe::new(ruby_code.as_bytes().to_vec()))
.expect("Input OnceLock should not be set at this point");
PRELOAD_PATH
.set(preload_path)
.expect("Preload path OnceLock should not be set at this point");

let mut wizer = Wizer::new();
wizer
.wasm_bulk_memory(true)
.make_linker(Some(Rc::new(|engine| {
async fn wizen(
ruby_engine: &[u8],
ruby_code: &str,
preload_path: Option<PathBuf>,
) -> Result<Vec<u8>> {
let mut cfg = Config::new();
cfg.async_support(true);
let engine = Engine::new(&cfg)?;
let mut store = Store::new(&engine, wasi(ruby_code, preload_path)?);
let user_wasm = Wizer::new()
.run(&mut store, ruby_engine, async |store, module| {
let engine = store.engine();
let mut linker = Linker::new(engine);
wasmtime_wasi::preview1::add_to_linker_sync(&mut linker, |cx: &mut StoreData| {
if cx.wasi_ctx.is_none() {
let mut wasi_builder = WasiCtxBuilder::new();
wasi_builder
.stdin(INPUT.get().unwrap().clone())
.inherit_stdout()
.inherit_stderr();
if let Some(preload_path) = PRELOAD_PATH.get().unwrap() {
wasi_builder.env("RUVY_PRELOAD_PATH", preload_path.to_string_lossy());
add_preload_path_to_wasi_ctx(&mut wasi_builder, preload_path)
.expect("Should have failed earlier when tested earlier");
}
cx.wasi_ctx = Some(wasi_builder.build_p1());
}
cx.wasi_ctx.as_mut().unwrap()
})?;
Ok(linker)
})))?;

Ok(wizer)
wasmtime_wasi::p1::add_to_linker_async(&mut linker, |cx| cx)?;
let instance = linker.instantiate_async(store, module).await?;
Ok(instance)
})
.await?;
Ok(user_wasm)
}

fn add_preload_path_to_wasi_ctx(
wasi_builder: &mut WasiCtxBuilder,
preload_path: &Path,
) -> Result<()> {
fn wasi(ruby_code: &str, preload_path: Option<PathBuf>) -> Result<WasiP1Ctx> {
let mut wasi_builder = WasiCtxBuilder::new();
wasi_builder
.preopened_dir(
preload_path,
preload_path.to_string_lossy(),
DirPerms::READ,
FilePerms::READ,
)
.map(|_| ())
.stdin(MemoryInputPipe::new(ruby_code.as_bytes().to_owned()))
.inherit_stdout()
.inherit_stderr();
if let Some(preload_path) = preload_path {
let guest_preload_path = preload_path.to_string_lossy();
wasi_builder
.env("RUVY_PRELOAD_PATH", &guest_preload_path)
.preopened_dir(
&preload_path,
&guest_preload_path,
DirPerms::READ,
FilePerms::READ,
)
.map(|_| ())?;
}
Ok(wasi_builder.build_p1())
}
4 changes: 2 additions & 2 deletions crates/cli/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use std::{env, path::Path, process::Command, str};
use anyhow::{bail, Result};
use wasmtime::{Engine, Linker, Module, Store};
use wasmtime_wasi::{
p1::WasiP1Ctx,
p2::pipe::{MemoryInputPipe, MemoryOutputPipe},
preview1::WasiP1Ctx,
WasiCtxBuilder,
};

Expand Down Expand Up @@ -74,7 +74,7 @@ fn run_ruvy(wasm_path: &str, input_path: &str, preload: Option<&str>) -> Result<
fn run_wasm(wasm_path: impl AsRef<Path>, input: &str) -> Result<String> {
let engine = Engine::default();
let mut linker = Linker::new(&engine);
wasmtime_wasi::preview1::add_to_linker_sync(&mut linker, |cx: &mut Context| &mut cx.wasi)?;
wasmtime_wasi::p1::add_to_linker_sync(&mut linker, |cx: &mut Context| &mut cx.wasi)?;
let mut store = Store::new(&engine, Context::new(input.as_bytes()));

let module = Module::from_file(&engine, wasm_path)?;
Expand Down
2 changes: 1 addition & 1 deletion crates/core/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {
cleanup_ruby().unwrap();
}

#[export_name = "wizer.initialize"]
#[export_name = "wizer-initialize"]
pub extern "C" fn load_user_code() {
let _wasm_ctx = WasmCtx::new();

Expand Down
68 changes: 58 additions & 10 deletions supply-chain/audits.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ end = "2025-11-04"
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
start = "2019-07-23"
end = "2024-09-21"
end = "2026-12-01"

[[trusted.byteorder]]
criteria = "safe-to-deploy"
Expand Down Expand Up @@ -187,14 +187,20 @@ end = "2025-01-03"
criteria = "safe-to-deploy"
user-id = 6825 # Dan Gohman (sunfishcode)
start = "2020-09-15"
end = "2024-09-21"
end = "2026-12-01"

[[trusted.hashbrown]]
criteria = "safe-to-deploy"
user-id = 2915 # Amanieu d'Antras (Amanieu)
start = "2019-04-02"
end = "2025-01-02"

[[trusted.hashbrown]]
criteria = "safe-to-deploy"
user-id = 55123 # rust-lang-owner
start = "2025-04-30"
end = "2026-12-01"

[[trusted.http]]
criteria = "safe-to-deploy"
user-id = 359 # Sean McArthur (seanmonstar)
Expand Down Expand Up @@ -235,7 +241,7 @@ end = "2026-04-07"
criteria = "safe-to-deploy"
user-id = 539 # Josh Stone (cuviper)
start = "2020-01-15"
end = "2025-01-02"
end = "2026-12-01"

[[trusted.io-extras]]
criteria = "safe-to-deploy"
Expand Down Expand Up @@ -297,6 +303,12 @@ user-id = 2915 # Amanieu d'Antras (Amanieu)
start = "2022-02-06"
end = "2025-09-16"

[[trusted.libm]]
criteria = "safe-to-deploy"
user-id = 55123 # rust-lang-owner
start = "2024-10-26"
end = "2026-12-01"

[[trusted.linux-raw-sys]]
criteria = "safe-to-deploy"
user-id = 6825 # Dan Gohman (sunfishcode)
Expand Down Expand Up @@ -331,13 +343,13 @@ end = "2024-10-27"
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
start = "2019-04-23"
end = "2025-03-01"
end = "2026-12-01"

[[trusted.quote]]
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
start = "2019-04-09"
end = "2024-09-21"
end = "2026-12-01"

[[trusted.regex]]
criteria = "safe-to-deploy"
Expand Down Expand Up @@ -391,14 +403,20 @@ end = "2025-11-01"
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
start = "2021-05-25"
end = "2025-01-02"
end = "2026-12-01"

[[trusted.serde]]
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
start = "2019-03-01"
end = "2026-03-03"

[[trusted.serde_core]]
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
start = "2025-09-13"
end = "2026-12-01"

[[trusted.serde_derive]]
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
Expand All @@ -417,6 +435,12 @@ user-id = 6743 # Ed Page (epage)
start = "2023-01-20"
end = "2025-05-01"

[[trusted.serde_yaml]]
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
start = "2019-05-02"
end = "2026-12-01"

[[trusted.slab]]
criteria = "safe-to-deploy"
user-id = 6741 # Alice Ryhl (Darksonn)
Expand Down Expand Up @@ -445,7 +469,7 @@ end = "2026-03-03"
criteria = "safe-to-deploy"
user-id = 6825 # Dan Gohman (sunfishcode)
start = "2020-10-27"
end = "2024-09-21"
end = "2026-12-01"

[[trusted.target-lexicon]]
criteria = "safe-to-deploy"
Expand Down Expand Up @@ -483,24 +507,42 @@ user-id = 10
start = "2019-03-02"
end = "2025-06-03"

[[trusted.tokio-macros]]
criteria = "safe-to-deploy"
user-id = 6741 # Alice Ryhl (Darksonn)
start = "2020-10-26"
end = "2026-12-01"

[[trusted.toml]]
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2022-12-14"
end = "2025-05-01"
end = "2026-12-01"

[[trusted.toml_datetime]]
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2022-10-21"
end = "2025-05-01"
end = "2026-12-01"

[[trusted.toml_edit]]
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2021-09-13"
end = "2025-05-01"

[[trusted.toml_parser]]
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2025-07-08"
end = "2026-12-01"

[[trusted.toml_writer]]
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2025-07-08"
end = "2026-12-01"

[[trusted.unicase]]
criteria = "safe-to-deploy"
user-id = 359 # Sean McArthur (seanmonstar)
Expand All @@ -513,6 +555,12 @@ user-id = 3618 # David Tolnay (dtolnay)
start = "2021-10-02"
end = "2024-09-21"

[[trusted.unsafe-libyaml]]
criteria = "safe-to-deploy"
user-id = 3618 # David Tolnay (dtolnay)
start = "2022-07-03"
end = "2026-12-01"

[[trusted.walkdir]]
criteria = "safe-to-deploy"
user-id = 189 # Andrew Gallant (BurntSushi)
Expand Down Expand Up @@ -679,7 +727,7 @@ end = "2026-09-05"
criteria = "safe-to-deploy"
user-id = 6743 # Ed Page (epage)
start = "2023-02-22"
end = "2025-05-01"
end = "2026-12-01"

[[trusted.wit-parser]]
criteria = "safe-to-deploy"
Expand Down
Loading