wasmer_wit_component/
cli.rs1#![deny(missing_docs)]
4
5use crate::{
6 decode_interface_component, ComponentEncoder, InterfaceEncoder, InterfacePrinter,
7 StringEncoding,
8};
9use anyhow::{bail, Context, Result};
10use clap::Parser;
11use std::path::{Path, PathBuf};
12use wasmer_wit_parser::Interface;
13
14fn parse_named_interface(s: &str) -> Result<Interface> {
15 let (name, path) = s
16 .split_once('=')
17 .ok_or_else(|| anyhow::anyhow!("expected a value with format `NAME=INTERFACE`"))?;
18
19 parse_interface(Some(name.to_string()), Path::new(path))
20}
21
22fn parse_unnamed_interface(s: &str) -> Result<Interface> {
23 parse_interface(None, Path::new(s))
24}
25
26fn parse_interface(name: Option<String>, path: &Path) -> Result<Interface> {
27 if !path.is_file() {
28 bail!("interface file `{}` does not exist", path.display(),);
29 }
30
31 let mut interface = Interface::parse_file(&path)
32 .with_context(|| format!("failed to parse interface file `{}`", path.display()))?;
33
34 interface.name = name.unwrap_or_else(|| "".to_string());
35
36 Ok(interface)
37}
38
39#[derive(Debug, Parser)]
43#[clap(name = "component-encoder", version = env!("CARGO_PKG_VERSION"))]
44pub struct WitComponentApp {
45 #[clap(long = "import", value_name = "NAME=INTERFACE", parse(try_from_str = parse_named_interface))]
47 pub imports: Vec<Interface>,
48
49 #[clap(long = "export", value_name = "NAME=INTERFACE", parse(try_from_str = parse_named_interface))]
51 pub exports: Vec<Interface>,
52
53 #[clap(long, short = 'o', value_name = "OUTPUT")]
55 pub output: Option<PathBuf>,
56
57 #[clap(long, short = 'i', value_name = "INTERFACE", parse(try_from_str = parse_unnamed_interface))]
59 pub interface: Option<Interface>,
60
61 #[clap(long)]
63 pub skip_validation: bool,
64
65 #[clap(long, value_name = "ENCODING")]
68 pub encoding: Option<StringEncoding>,
69
70 #[clap(index = 1, value_name = "MODULE")]
72 pub module: PathBuf,
73}
74
75impl WitComponentApp {
76 pub fn execute(self) -> Result<()> {
78 if !self.module.is_file() {
79 bail!(
80 "module `{}` does not exist as a file",
81 self.module.display()
82 );
83 }
84
85 let output = self.output.unwrap_or_else(|| {
86 let mut stem: PathBuf = self.module.file_stem().unwrap().into();
87 stem.set_extension("wasm");
88 stem
89 });
90
91 let module = wat::parse_file(&self.module)
92 .with_context(|| format!("failed to parse module `{}`", self.module.display()))?;
93
94 let mut encoder = ComponentEncoder::default()
95 .module(&module)
96 .imports(&self.imports)
97 .exports(&self.exports)
98 .validate(!self.skip_validation);
99
100 if let Some(interface) = &self.interface {
101 encoder = encoder.interface(interface);
102 }
103
104 if let Some(encoding) = &self.encoding {
105 encoder = encoder.encoding(*encoding);
106 }
107
108 let bytes = encoder.encode().with_context(|| {
109 format!(
110 "failed to encode a component from module `{}`",
111 self.module.display()
112 )
113 })?;
114
115 std::fs::write(&output, bytes)
116 .with_context(|| format!("failed to write output file `{}`", output.display()))?;
117
118 println!("encoded component `{}`", output.display());
119
120 Ok(())
121 }
122}
123
124#[derive(Debug, Parser)]
128#[clap(name = "wit2wasm", version = env!("CARGO_PKG_VERSION"))]
129pub struct WitToWasmApp {
130 #[clap(long, short = 'o', value_name = "OUTPUT")]
132 pub output: Option<PathBuf>,
133
134 #[clap(index = 1, value_name = "INTERFACE")]
136 pub interface: PathBuf,
137}
138
139impl WitToWasmApp {
140 pub fn execute(self) -> Result<()> {
142 let output = self.output.unwrap_or_else(|| {
143 let mut stem: PathBuf = self.interface.file_stem().unwrap().into();
144 stem.set_extension("wasm");
145 stem
146 });
147
148 let interface = parse_interface(None, &self.interface)?;
149
150 let encoder = InterfaceEncoder::new(&interface).validate(true);
151
152 let bytes = encoder.encode().with_context(|| {
153 format!(
154 "failed to encode a component from interface `{}`",
155 self.interface.display()
156 )
157 })?;
158
159 std::fs::write(&output, bytes)
160 .with_context(|| format!("failed to write output file `{}`", output.display()))?;
161
162 println!("encoded interface as component `{}`", output.display());
163
164 Ok(())
165 }
166}
167
168#[derive(Debug, Parser)]
172#[clap(name = "wit2wasm", version = env!("CARGO_PKG_VERSION"))]
173pub struct WasmToWitApp {
174 #[clap(long, short = 'o', value_name = "OUTPUT")]
176 pub output: Option<PathBuf>,
177
178 #[clap(index = 1, value_name = "COMPONENT")]
180 pub component: PathBuf,
181}
182
183impl WasmToWitApp {
184 pub fn execute(self) -> Result<()> {
186 let output = self.output.unwrap_or_else(|| {
187 let mut stem: PathBuf = self.component.file_stem().unwrap().into();
188 stem.set_extension("wit");
189 stem
190 });
191
192 if !self.component.is_file() {
193 bail!(
194 "component `{}` does not exist as a file",
195 self.component.display()
196 );
197 }
198
199 let bytes = wat::parse_file(&self.component)
200 .with_context(|| format!("failed to parse component `{}`", self.component.display()))?;
201
202 let interface = decode_interface_component(&bytes).with_context(|| {
203 format!("failed to decode component `{}`", self.component.display())
204 })?;
205
206 let mut printer = InterfacePrinter::default();
207
208 std::fs::write(&output, printer.print(&interface)?)
209 .with_context(|| format!("failed to write output file `{}`", output.display()))?;
210
211 println!("decoded interface to `{}`", output.display());
212
213 Ok(())
214 }
215}