Skip to content

Commit 76c6af6

Browse files
Integrate wasi-virt at crate level instead of CLI
1 parent a0e7d0c commit 76c6af6

File tree

4 files changed

+129
-19
lines changed

4 files changed

+129
-19
lines changed

Cargo.lock

Lines changed: 24 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/ruby_wasm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ wizer = "4.0.0"
1616
wasi-vfs-cli = { git = "https://github.com/kateinoigakukun/wasi-vfs/", tag = "0.5.2" }
1717
structopt = "0.3.26"
1818
wit-component = "0.203.0"
19+
wasm-compose = "0.203.0"
1920
wasi-virt = { git = "https://github.com/bytecodealliance/wasi-virt", rev = "b2581ff6e993c7c3cb6f5d899977bbce3d4c6c60" }

ext/ruby_wasm/src/lib.rs

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{collections::HashMap, path::PathBuf};
1+
use std::{collections::HashMap, env, path::PathBuf, time::SystemTime};
22

33
use magnus::{
44
eval, exception, function, method,
@@ -8,6 +8,7 @@ use magnus::{
88
};
99
use structopt::StructOpt;
1010
use wizer::Wizer;
11+
use wasi_virt;
1112

1213
static RUBY_WASM: value::Lazy<RModule> =
1314
value::Lazy::new(|ruby| ruby.define_module("RubyWasmExt").unwrap());
@@ -222,6 +223,96 @@ impl ComponentEncode {
222223
}
223224
}
224225

226+
#[wrap(class = "RubyWasmExt::WasiVirt")]
227+
struct WasiVirt(std::cell::RefCell<Option<wasi_virt::WasiVirt>>);
228+
229+
impl WasiVirt {
230+
fn new() -> Self {
231+
Self(std::cell::RefCell::new(Some(wasi_virt::WasiVirt::new())))
232+
}
233+
234+
fn virt<R>(
235+
&self,
236+
body: impl FnOnce(&mut wasi_virt::WasiVirt) -> Result<R, Error>,
237+
) -> Result<R, Error> {
238+
let mut virt = self.0.take().ok_or_else(|| {
239+
Error::new(
240+
exception::standard_error(),
241+
"wasi virt is already consumed".to_string(),
242+
)
243+
})?;
244+
let result = body(&mut virt)?;
245+
self.0.replace(Some(virt));
246+
Ok(result)
247+
}
248+
249+
fn allow_all(&self) -> Result<(), Error> {
250+
self.virt(|virt| {
251+
virt.allow_all();
252+
Ok(())
253+
})
254+
}
255+
256+
fn map_dir(&self, guest_dir: String, host_dir: String) -> Result<(), Error> {
257+
self.virt(|virt| {
258+
virt.fs().virtual_preopen(guest_dir, host_dir);
259+
Ok(())
260+
})
261+
}
262+
263+
fn finish(&self) -> Result<bytes::Bytes, Error> {
264+
self.virt(|virt| {
265+
let result = virt.finish().map_err(|e| {
266+
Error::new(
267+
exception::standard_error(),
268+
format!("failed to generate virtualization adapter: {}", e),
269+
)
270+
})?;
271+
Ok(result.adapter.into())
272+
})
273+
}
274+
275+
fn compose(&self, component_bytes: bytes::Bytes) -> Result<bytes::Bytes, Error> {
276+
let virt_adapter = self.finish()?;
277+
let tmpdir = env::temp_dir();
278+
let tmp_virt = tmpdir.join(format!("virt{}.wasm", timestamp()));
279+
std::fs::write(&tmp_virt, &virt_adapter).map_err(|e| {
280+
Error::new(
281+
exception::standard_error(),
282+
format!("failed to write virt adapter: {}", e),
283+
)
284+
})?;
285+
let tmp_component = tmpdir.join(format!("component{}.wasm", timestamp()));
286+
std::fs::write(&tmp_component, &component_bytes).map_err(|e| {
287+
Error::new(
288+
exception::standard_error(),
289+
format!("failed to write component: {}", e),
290+
)
291+
})?;
292+
293+
use wasm_compose::{composer, config};
294+
let config = config::Config {
295+
definitions: vec![tmp_virt],
296+
..Default::default()
297+
};
298+
let composer = composer::ComponentComposer::new(&tmp_component, &config);
299+
let composed = composer.compose().map_err(|e| {
300+
Error::new(
301+
exception::standard_error(),
302+
format!("failed to compose component: {}", e),
303+
)
304+
})?;
305+
return Ok(composed.into());
306+
307+
fn timestamp() -> u64 {
308+
match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
309+
Ok(n) => n.as_secs(),
310+
Err(_) => panic!(),
311+
}
312+
}
313+
}
314+
}
315+
225316
#[magnus::init]
226317
fn init(ruby: &Ruby) -> Result<(), Error> {
227318
let module = RUBY_WASM.get_inner_with(ruby);
@@ -266,5 +357,12 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
266357
)?;
267358
component_encode.define_method("encode", method!(ComponentEncode::encode, 0))?;
268359

360+
let wasi_virt = module.define_class("WasiVirt", ruby.class_object())?;
361+
wasi_virt.define_singleton_method("new", function!(WasiVirt::new, 0))?;
362+
wasi_virt.define_method("allow_all", method!(WasiVirt::allow_all, 0))?;
363+
wasi_virt.define_method("map_dir", method!(WasiVirt::map_dir, 2))?;
364+
wasi_virt.define_method("finish", method!(WasiVirt::finish, 0))?;
365+
wasi_virt.define_method("compose", method!(WasiVirt::compose, 1))?;
366+
269367
Ok(())
270368
}

lib/ruby_wasm/packager.rb

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,13 @@ def package(executor, dest_dir, options)
5555
wasm_bytes = ruby_core.link_gem_exts(executor, fs.ruby_root, fs.bundle_dir, wasm_bytes)
5656

5757
if features.support_component_model?
58-
tmp_file = "tmp/ruby.component.wasm"
59-
tmp_virt_file = "tmp/ruby.component.virt.wasm"
60-
File.write(tmp_file, wasm_bytes)
61-
args = [
62-
"wasi-virt",
63-
"--allow-fs",
64-
"--allow-random", "--allow-clocks", "--allow-exit",
65-
"--stdin=allow", "--stdout=allow", "--stderr=allow",
66-
"--allow-all",
67-
"--debug"
68-
]
58+
wasi_virt = RubyWasmExt::WasiVirt.new
59+
wasi_virt.allow_all
6960
[["/bundle", fs.bundle_dir], ["/usr", File.dirname(fs.ruby_root)]].each do |guest, host|
70-
args += ["--mount", "#{guest}=#{host}"]
61+
RubyWasm.logger.debug "Adding files into VFS: #{host} => #{guest}"
62+
wasi_virt.map_dir(guest, host)
7163
end
72-
args += ["--out", tmp_virt_file]
73-
args += [tmp_file]
74-
75-
executor.system(*args)
76-
wasm_bytes = File.binread(tmp_virt_file)
64+
wasm_bytes = wasi_virt.compose(wasm_bytes)
7765
end
7866

7967
wasm_bytes = RubyWasmExt.preinitialize(wasm_bytes) if options[:optimize]

0 commit comments

Comments
 (0)