Skip to content

Commit 5c09881

Browse files
authored
Add some CLI flags for component-creation options (#16)
* Switch `--wasi-proxy-adapter` to `--wasi-adapter=...` * Add `--adapt` like `wasm-tools component new`
1 parent 5a7d486 commit 5c09881

4 files changed

Lines changed: 188 additions & 36 deletions

File tree

Cargo.lock

Lines changed: 100 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ anyhow = "1.0.80"
1212
clap = { version = "4.5.4", features = ['derive'] }
1313
lexopt = "0.3.0"
1414
tempfile = "3.10.0"
15-
wasmparser = "0.202.0"
16-
wit-component = "0.202.0"
15+
wasmparser = "0.206.0"
16+
wat = "1.206.0"
17+
wit-component = "0.206.0"

src/main.rs

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use clap::{ArgAction, CommandFactory, FromArgMatches};
33
use lexopt::Arg;
44
use std::env;
55
use std::ffi::OsString;
6-
use std::path::PathBuf;
6+
use std::path::{Path, PathBuf};
77
use std::process::Command;
8+
use std::str::FromStr;
89
use wasmparser::Payload;
910

1011
struct LldFlag {
@@ -171,10 +172,10 @@ struct App {
171172
#[derive(clap::Parser, Default)]
172173
#[command(version)]
173174
struct ComponentLdArgs {
174-
/// Instructs the "proxy" adapter to be used for use in a `wasi:http/proxy`
175-
/// world.
176-
#[clap(long)]
177-
wasi_proxy_adapter: bool,
175+
/// Which default WASI adapter, if any, to use when creating the output
176+
/// component.
177+
#[clap(long, name = "command|reactor|proxy|none")]
178+
wasi_adapter: Option<WasiAdapter>,
178179

179180
/// Location of where to find `wasm-ld`.
180181
///
@@ -199,6 +200,58 @@ struct ComponentLdArgs {
199200
/// This defaults to `true`.
200201
#[clap(long)]
201202
validate_component: Option<bool>,
203+
204+
/// Adapters to use when creating the final component.
205+
#[clap(long = "adapt", value_name = "[NAME=]MODULE", value_parser = parse_adapter)]
206+
adapters: Vec<(String, Vec<u8>)>,
207+
}
208+
209+
fn parse_adapter(s: &str) -> Result<(String, Vec<u8>)> {
210+
let (name, path) = parse_optionally_name_file(s);
211+
let wasm = wat::parse_file(path)?;
212+
Ok((name.to_string(), wasm))
213+
}
214+
215+
fn parse_optionally_name_file(s: &str) -> (&str, &str) {
216+
let mut parts = s.splitn(2, '=');
217+
let name_or_path = parts.next().unwrap();
218+
match parts.next() {
219+
Some(path) => (name_or_path, path),
220+
None => {
221+
let name = Path::new(name_or_path)
222+
.file_name()
223+
.unwrap()
224+
.to_str()
225+
.unwrap();
226+
let name = match name.find('.') {
227+
Some(i) => &name[..i],
228+
None => name,
229+
};
230+
(name, name_or_path)
231+
}
232+
}
233+
}
234+
235+
#[derive(Debug, Copy, Clone)]
236+
enum WasiAdapter {
237+
Command,
238+
Reactor,
239+
Proxy,
240+
None,
241+
}
242+
243+
impl FromStr for WasiAdapter {
244+
type Err = anyhow::Error;
245+
246+
fn from_str(s: &str) -> Result<Self, Self::Err> {
247+
match s {
248+
"none" => Ok(WasiAdapter::None),
249+
"command" => Ok(WasiAdapter::Command),
250+
"reactor" => Ok(WasiAdapter::Reactor),
251+
"proxy" => Ok(WasiAdapter::Proxy),
252+
_ => bail!("unknown wasi adapter {s}, must be one of: none, command, reactor, proxy"),
253+
}
254+
}
202255
}
203256

204257
fn main() {
@@ -426,22 +479,35 @@ impl App {
426479
}
427480
}
428481

429-
let adapter = if exports_start {
430-
&command_adapter[..]
431-
} else if self.component.wasi_proxy_adapter {
432-
&proxy_adapter[..]
482+
let mut encoder = wit_component::ComponentEncoder::default()
483+
.module(&core_module)
484+
.context("failed to parse core wasm for componentization")?
485+
.validate(self.component.validate_component.unwrap_or(true));
486+
let adapter = self.component.wasi_adapter.unwrap_or(if exports_start {
487+
WasiAdapter::Command
433488
} else {
434-
&reactor_adapter[..]
489+
WasiAdapter::Reactor
490+
});
491+
let adapter = match adapter {
492+
WasiAdapter::Command => Some(&command_adapter[..]),
493+
WasiAdapter::Reactor => Some(&reactor_adapter[..]),
494+
WasiAdapter::Proxy => Some(&proxy_adapter[..]),
495+
WasiAdapter::None => None,
435496
};
436497

437-
let component = wit_component::ComponentEncoder::default()
438-
.module(&core_module)
439-
.context("failed to parse core wasm for componentization")?
440-
.adapter("wasi_snapshot_preview1", adapter)
441-
.context("failed to inject adapter")?
442-
.validate(self.component.validate_component.unwrap_or(true))
443-
.encode()
444-
.context("failed to encode component")?;
498+
if let Some(adapter) = adapter {
499+
encoder = encoder
500+
.adapter("wasi_snapshot_preview1", adapter)
501+
.context("failed to inject adapter")?;
502+
}
503+
504+
for (name, adapter) in self.component.adapters.iter() {
505+
encoder = encoder
506+
.adapter(name, adapter)
507+
.with_context(|| format!("failed to inject adapter {name:?}"))?;
508+
}
509+
510+
let component = encoder.encode().context("failed to encode component")?;
445511

446512
std::fs::write(self.component.output.as_ref().unwrap(), &component)
447513
.context("failed to write output file")?;

tests/all.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,7 @@ fn compile(args: &[&str], src: &str) -> Vec<u8> {
3737

3838
fn assert_component(bytes: &[u8]) {
3939
assert!(wasmparser::Parser::is_component(&bytes));
40-
wasmparser::Validator::new_with_features(wasmparser::WasmFeatures {
41-
component_model: true,
42-
..wasmparser::WasmFeatures::default()
43-
})
44-
.validate_all(&bytes)
45-
.unwrap();
40+
wasmparser::Validator::new().validate_all(&bytes).unwrap();
4641
}
4742

4843
#[test]

0 commit comments

Comments
 (0)