6
6
) ]
7
7
8
8
use anyhow:: { anyhow, bail, Context as _, Error , Result } ;
9
- use clap:: builder:: { OsStringValueParser , TypedValueParser } ;
10
9
use clap:: Parser ;
11
- use std:: ffi:: OsStr ;
12
- use std:: ffi:: OsString ;
13
10
use std:: fs:: File ;
14
11
use std:: io:: Write ;
15
12
use std:: path:: { Path , PathBuf } ;
@@ -38,18 +35,6 @@ use wasmtime_wasi_threads::WasiThreadsCtx;
38
35
#[ cfg( feature = "wasi-http" ) ]
39
36
use wasmtime_wasi_http:: WasiHttpCtx ;
40
37
41
- fn parse_module ( s : OsString ) -> anyhow:: Result < PathBuf > {
42
- // Do not accept wasmtime subcommand names as the module name
43
- match s. to_str ( ) {
44
- Some ( "help" ) | Some ( "config" ) | Some ( "run" ) | Some ( "wast" ) | Some ( "compile" ) => {
45
- bail ! ( "module name cannot be the same as a subcommand" )
46
- }
47
- #[ cfg( unix) ]
48
- Some ( "-" ) => Ok ( PathBuf :: from ( "/dev/stdin" ) ) ,
49
- _ => Ok ( s. into ( ) ) ,
50
- }
51
- }
52
-
53
38
fn parse_env_var ( s : & str ) -> Result < ( String , Option < String > ) > {
54
39
let mut parts = s. splitn ( 2 , '=' ) ;
55
40
Ok ( (
@@ -100,7 +85,7 @@ fn parse_profile(s: &str) -> Result<Profile> {
100
85
101
86
/// Runs a WebAssembly module
102
87
#[ derive( Parser ) ]
103
- #[ structopt( name = "run" , trailing_var_arg = true ) ]
88
+ #[ structopt( name = "run" ) ]
104
89
pub struct RunCommand {
105
90
#[ clap( flatten) ]
106
91
common : CommonOptions ,
@@ -137,14 +122,6 @@ pub struct RunCommand {
137
122
#[ clap( long, value_name = "FUNCTION" ) ]
138
123
invoke : Option < String > ,
139
124
140
- /// The path of the WebAssembly module to run
141
- #[ clap(
142
- required = true ,
143
- value_name = "MODULE" ,
144
- value_parser = OsStringValueParser :: new( ) . try_map( parse_module) ,
145
- ) ]
146
- module : PathBuf ,
147
-
148
125
/// Load the given WebAssembly module before the main module
149
126
#[ clap(
150
127
long = "preload" ,
@@ -176,10 +153,13 @@ pub struct RunCommand {
176
153
) ]
177
154
profile : Option < Profile > ,
178
155
179
- // NOTE: this must come last for trailing varargs
180
- /// The arguments to pass to the module
181
- #[ clap( value_name = "ARGS" ) ]
182
- module_args : Vec < String > ,
156
+ /// The WebAssembly module to run and arguments to pass to it.
157
+ ///
158
+ /// Arguments passed to the wasm module will be configured as WASI CLI
159
+ /// arguments unless the `--invoke` CLI argument is passed in which case
160
+ /// arguments will be interpreted as arguments to the function specified.
161
+ #[ clap( value_name = "WASM" , trailing_var_arg = true , required = true ) ]
162
+ module_and_args : Vec < PathBuf > ,
183
163
}
184
164
185
165
#[ derive( Clone ) ]
@@ -242,7 +222,7 @@ impl RunCommand {
242
222
let engine = Engine :: new ( & config) ?;
243
223
244
224
// Read the wasm module binary either as `*.wat` or a raw binary.
245
- let main = self . load_module ( & engine, & self . module ) ?;
225
+ let main = self . load_module ( & engine, & self . module_and_args [ 0 ] ) ?;
246
226
247
227
// Validate coredump-on-trap argument
248
228
if let Some ( coredump_path) = & self . common . debug . coredump {
@@ -335,8 +315,12 @@ impl RunCommand {
335
315
// Load the main wasm module.
336
316
match self
337
317
. load_main_module ( & mut store, & mut linker, & main, modules)
338
- . with_context ( || format ! ( "failed to run main module `{}`" , self . module. display( ) ) )
339
- {
318
+ . with_context ( || {
319
+ format ! (
320
+ "failed to run main module `{}`" ,
321
+ self . module_and_args[ 0 ] . display( )
322
+ )
323
+ } ) {
340
324
Ok ( ( ) ) => ( ) ,
341
325
Err ( e) => {
342
326
// Exit the process if Wasmtime understands the error;
@@ -377,27 +361,25 @@ impl RunCommand {
377
361
Ok ( listeners)
378
362
}
379
363
380
- fn compute_argv ( & self ) -> Vec < String > {
364
+ fn compute_argv ( & self ) -> Result < Vec < String > > {
381
365
let mut result = Vec :: new ( ) ;
382
366
383
- // Add argv[0], which is the program name. Only include the base name of the
384
- // main wasm module, to avoid leaking path information.
385
- result. push (
386
- self . module
387
- . components ( )
388
- . next_back ( )
389
- . map ( |c| c. as_os_str ( ) )
390
- . and_then ( OsStr :: to_str)
391
- . unwrap_or ( "" )
392
- . to_owned ( ) ,
393
- ) ;
394
-
395
- // Add the remaining arguments.
396
- for arg in self . module_args . iter ( ) {
397
- result. push ( arg. clone ( ) ) ;
367
+ for ( i, arg) in self . module_and_args . iter ( ) . enumerate ( ) {
368
+ // For argv[0], which is the program name. Only include the base
369
+ // name of the main wasm module, to avoid leaking path information.
370
+ let arg = if i == 0 {
371
+ arg. components ( ) . next_back ( ) . unwrap ( ) . as_os_str ( )
372
+ } else {
373
+ arg. as_ref ( )
374
+ } ;
375
+ result. push (
376
+ arg. to_str ( )
377
+ . ok_or_else ( || anyhow ! ( "failed to convert {arg:?} to utf-8" ) ) ?
378
+ . to_string ( ) ,
379
+ ) ;
398
380
}
399
381
400
- result
382
+ Ok ( result)
401
383
}
402
384
403
385
fn setup_epoch_handler (
@@ -406,7 +388,7 @@ impl RunCommand {
406
388
modules : Vec < ( String , Module ) > ,
407
389
) -> Box < dyn FnOnce ( & mut Store < Host > ) > {
408
390
if let Some ( Profile :: Guest { path, interval } ) = & self . profile {
409
- let module_name = self . module . to_str ( ) . unwrap_or ( "<main module>" ) ;
391
+ let module_name = self . module_and_args [ 0 ] . to_str ( ) . unwrap_or ( "<main module>" ) ;
410
392
let interval = * interval;
411
393
store. data_mut ( ) . guest_profiler =
412
394
Some ( Arc :: new ( GuestProfiler :: new ( module_name, interval, modules) ) ) ;
@@ -512,9 +494,10 @@ impl RunCommand {
512
494
CliLinker :: Core ( linker) => {
513
495
// Use "" as a default module name.
514
496
let module = module. unwrap_core ( ) ;
515
- linker
516
- . module ( & mut * store, "" , & module)
517
- . context ( format ! ( "failed to instantiate {:?}" , self . module) ) ?;
497
+ linker. module ( & mut * store, "" , & module) . context ( format ! (
498
+ "failed to instantiate {:?}" ,
499
+ self . module_and_args[ 0 ]
500
+ ) ) ?;
518
501
519
502
// If a function to invoke was given, invoke it.
520
503
let func = if let Some ( name) = & self . invoke {
@@ -569,7 +552,7 @@ impl RunCommand {
569
552
is experimental and may break in the future"
570
553
) ;
571
554
}
572
- let mut args = self . module_args . iter ( ) ;
555
+ let mut args = self . module_and_args . iter ( ) . skip ( 1 ) ;
573
556
let mut values = Vec :: new ( ) ;
574
557
for ty in ty. params ( ) {
575
558
let val = match args. next ( ) {
@@ -582,6 +565,9 @@ impl RunCommand {
582
565
}
583
566
}
584
567
} ;
568
+ let val = val
569
+ . to_str ( )
570
+ . ok_or_else ( || anyhow ! ( "argument is not valid utf-8: {val:?}" ) ) ?;
585
571
values. push ( match ty {
586
572
// TODO: integer parsing here should handle hexadecimal notation
587
573
// like `0x0...`, but the Rust standard library currently only
@@ -639,7 +625,9 @@ impl RunCommand {
639
625
if !err. is :: < wasmtime:: Trap > ( ) {
640
626
return err;
641
627
}
642
- let source_name = self . module . to_str ( ) . unwrap_or_else ( || "unknown" ) ;
628
+ let source_name = self . module_and_args [ 0 ]
629
+ . to_str ( )
630
+ . unwrap_or_else ( || "unknown" ) ;
643
631
644
632
if let Err ( coredump_err) = generate_coredump ( & err, & source_name, coredump_path) {
645
633
eprintln ! ( "warning: coredump failed to generate: {}" , coredump_err) ;
@@ -884,7 +872,7 @@ impl RunCommand {
884
872
885
873
fn set_preview1_ctx ( & self , store : & mut Store < Host > ) -> Result < ( ) > {
886
874
let mut builder = WasiCtxBuilder :: new ( ) ;
887
- builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ) ?;
875
+ builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ? ) ?;
888
876
889
877
for ( key, value) in self . vars . iter ( ) {
890
878
let value = match value {
@@ -916,7 +904,7 @@ impl RunCommand {
916
904
917
905
fn set_preview2_ctx ( & self , store : & mut Store < Host > ) -> Result < ( ) > {
918
906
let mut builder = preview2:: WasiCtxBuilder :: new ( ) ;
919
- builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ) ;
907
+ builder. inherit_stdio ( ) . args ( & self . compute_argv ( ) ? ) ;
920
908
921
909
for ( key, value) in self . vars . iter ( ) {
922
910
let value = match value {
0 commit comments