11use anyhow:: Result ;
2+ use std:: path:: Path ;
23use tinywasm:: types:: ExportType ;
34use tinywasm:: { ModuleInstance , Store } ;
5+ use tinywasm_wasi:: p1:: WasiCtx ;
46
7+ use crate :: WasiExit ;
58use crate :: cli:: RunArgs ;
69use crate :: load:: load_module;
710use crate :: output:: print_results;
@@ -10,15 +13,45 @@ use crate::value_parse::parse_invocation_args;
1013pub fn run ( args : RunArgs ) -> Result < ( ) > {
1114 let module_path = args. module . as_deref ( ) . ok_or_else ( || anyhow:: anyhow!( "missing module path" ) ) ?;
1215 let loaded = load_module ( module_path) ?;
13- let mut store = Store :: new ( args. engine . build_engine ( ) ?) ;
14- let instance = ModuleInstance :: instantiate_no_start ( & mut store, & loaded. module , None ) ?;
16+ let argv0 = Path :: new ( module_path) . file_name ( ) . and_then ( |name| name. to_str ( ) ) . unwrap_or ( module_path) ;
17+ let guest_args = if args. invoke . is_none ( ) {
18+ std:: iter:: once ( argv0. to_owned ( ) ) . chain ( args. args . iter ( ) . cloned ( ) ) . collect ( )
19+ } else {
20+ vec ! [ argv0. to_owned( ) ]
21+ } ;
22+ let env = args
23+ . env
24+ . iter ( )
25+ . map ( |value| {
26+ value
27+ . split_once ( '=' )
28+ . filter ( |( name, _) | !name. is_empty ( ) )
29+ . map ( |( name, value) | ( name. to_owned ( ) , value. to_owned ( ) ) )
30+ . ok_or_else ( || anyhow:: anyhow!( "invalid --env value `{value}`, expected NAME=VALUE" ) )
31+ } )
32+ . collect :: < Result < Vec < _ > > > ( ) ?;
33+ let mut wasi = WasiCtx :: new ( ) . with_args ( guest_args) ?. with_env ( env) ?. inherit_stdio ( ) ;
34+ for mapping in & args. dirs {
35+ let ( host, guest) = mapping. split_once ( "::" ) . unwrap_or ( ( mapping, mapping) ) ;
36+ if host. is_empty ( ) || guest. is_empty ( ) {
37+ return Err ( anyhow:: anyhow!( "invalid --dir value `{mapping}`, expected HOST or HOST::GUEST" ) ) ;
38+ }
39+ wasi = wasi. preopen_dir ( host, guest) ?;
40+ }
41+ let mut store = Store :: new ( args. engine . build_engine ( ) ?) . with_state ( wasi) ;
42+ let imports = tinywasm_wasi:: p1:: imports ( ) ;
43+ let instance = ModuleInstance :: instantiate_no_start ( & mut store, & loaded. module , Some ( & imports) ) ?;
44+
45+ let ran_core_start = if loaded. module . start_func . is_some ( ) {
46+ let result = instance. start ( & mut store) ;
47+ finish_wasi_call ( result, & mut store) ?;
48+ true
49+ } else {
50+ false
51+ } ;
1552
1653 match args. invoke . as_deref ( ) {
1754 Some ( export) => {
18- if loaded. module . start_func . is_some ( ) {
19- let _ = instance. start ( & mut store) ?;
20- }
21-
2255 let func_ty = loaded
2356 . module
2457 . exports ( )
@@ -30,23 +63,38 @@ pub fn run(args: RunArgs) -> Result<()> {
3063 let func = instance. func_untyped ( & store, export) ?;
3164 let params = parse_invocation_args ( func_ty, & args. args ) ?;
3265 let mut results = vec ! [ tinywasm:: WasmValue :: I32 ( 0 ) ; func. ty( & store) ?. results( ) . len( ) ] ;
33- func. call ( & mut store, & params, & mut results) ?;
66+ let result = func. call ( & mut store, & params, & mut results) ;
67+ finish_wasi_call ( result, & mut store) ?;
3468 print_results ( & results) ;
3569 Ok ( ( ) )
3670 }
3771 None => {
38- if instance. start_func ( & store) ? . is_some ( ) {
39- let _ = instance . start ( & mut store ) ? ;
40- return Ok ( ( ) ) ;
41- }
42-
43- let start = instance . func_untyped ( & store , " _start" ) . map_err ( |_| {
44- anyhow :: anyhow! (
45- "module has no start function or `_start` export. Use `tinywasm inspect {module_path}` or `tinywasm run --invoke <export> {module_path}`"
46- )
47- } ) ? ;
48- start . call ( & mut store , & [ ] , & mut [ ] ) ?;
72+ let start = match instance. func_untyped ( & store, "_start" ) {
73+ Ok ( start ) => start,
74+ Err ( _ ) if ran_core_start => return Ok ( ( ) ) ,
75+ Err ( _ ) => {
76+ return Err ( anyhow :: anyhow! (
77+ "module has no start function or ` _start` export. Use `tinywasm inspect {module_path}` or `tinywasm run --invoke <export> {module_path}`"
78+ ) ) ;
79+ }
80+ } ;
81+ let result = start . call ( & mut store , & [ ] , & mut [ ] ) ;
82+ finish_wasi_call ( result , & mut store ) ?;
4983 Ok ( ( ) )
5084 }
5185 }
5286}
87+
88+ fn finish_wasi_call < T > ( result : tinywasm:: Result < T > , store : & mut Store ) -> Result < T > {
89+ match result {
90+ Ok ( value) => Ok ( value) ,
91+ Err ( error) => {
92+ if let Some ( wasi) = store. state_mut :: < WasiCtx > ( )
93+ && let Some ( status) = wasi. take_exit_status ( )
94+ {
95+ return Err ( WasiExit ( status) . into ( ) ) ;
96+ }
97+ Err ( error. into ( ) )
98+ }
99+ }
100+ }
0 commit comments