11use anyhow:: Result ;
2+ use clap:: { Parser , Subcommand } ;
23use hyperlight_nanvix:: { cache, RuntimeConfig , Sandbox } ;
34use nanvix:: log;
45use nanvix:: registry:: Registry ;
5- use std:: env;
6- use std:: path:: Path ;
6+ use std:: path:: PathBuf ;
7+
8+ /// A Hyperlight VMM wrapper with out-of-the-box support for running Nanvix microkernel guests
9+ #[ derive( Parser ) ]
10+ #[ command( name = "hyperlight-nanvix" ) ]
11+ #[ command( about = "Run scripts in a Nanvix microkernel guest" ) ]
12+ #[ command(
13+ after_help = "Supported file types: .js, .mjs (JavaScript), .py (Python), .elf, .o (Binary)"
14+ ) ]
15+ struct Cli {
16+ /// Show detailed nanvix logging
17+ #[ arg( long) ]
18+ verbose : bool ,
19+
20+ #[ command( subcommand) ]
21+ command : Option < Commands > ,
22+
23+ /// Path to the script to run
24+ #[ arg( value_name = "SCRIPT" ) ]
25+ script_path : Option < PathBuf > ,
26+ }
27+
28+ #[ derive( Subcommand ) ]
29+ enum Commands {
30+ /// Download nanvix registry and show compilation instructions
31+ SetupRegistry ,
32+ /// Clear the nanvix registry cache
33+ ClearRegistry ,
34+ }
735
836/// Default log-level (overridden by RUST_LOG environment variable if set).
937const DEFAULT_LOG_LEVEL : & str = "info" ;
@@ -78,48 +106,31 @@ async fn clear_registry_command() -> Result<()> {
78106 }
79107 }
80108
81- println ! ( "Run 'cargo run -- -- setup-registry' to re-download if needed." ) ;
109+ println ! ( "Run 'cargo run -- setup-registry' to re-download if needed." ) ;
82110 Ok ( ( ) )
83111}
84112
85113#[ tokio:: main]
86114async fn main ( ) -> Result < ( ) > {
87- // Parse command line arguments first
88- let args: Vec < String > = env:: args ( ) . collect ( ) ;
89-
90- // Check for flags
91- let verbose = args. contains ( & "--verbose" . to_string ( ) ) ;
92- let setup_registry = args. contains ( & "--setup-registry" . to_string ( ) ) ;
93- let clear_registry = args. contains ( & "--clear-registry" . to_string ( ) ) ;
94-
95- // Handle setup-registry command
96- if setup_registry {
97- return setup_registry_command ( ) . await ;
115+ let cli = Cli :: parse ( ) ;
116+
117+ // Handle subcommands
118+ if let Some ( command) = cli. command {
119+ return match command {
120+ Commands :: SetupRegistry => setup_registry_command ( ) . await ,
121+ Commands :: ClearRegistry => clear_registry_command ( ) . await ,
122+ } ;
98123 }
99124
100- // Handle clear-registry command
101- if clear_registry {
102- return clear_registry_command ( ) . await ;
103- }
104-
105- // Find the script argument (first non-flag argument)
106- let script_arg = args
107- . iter ( )
108- . position ( |arg| !arg. starts_with ( "--" ) && !arg. ends_with ( "hyperlight-nanvix" ) ) ;
109-
110- let script_path = if let Some ( idx) = script_arg {
111- Path :: new ( & args[ idx] )
112- } else {
113- eprintln ! ( "Usage: {} [--verbose] <script_path>" , args[ 0 ] ) ;
114- eprintln ! ( " {} --setup-registry" , args[ 0 ] ) ;
115- eprintln ! ( " {} --clear-registry" , args[ 0 ] ) ;
116- eprintln ! ( "Supported file types: .js, .mjs (JavaScript), .py (Python), .elf, .o (Binary)" ) ;
117- eprintln ! ( "Options:" ) ;
118- eprintln ! ( " --verbose Show detailed nanvix logging" ) ;
119- eprintln ! ( " --setup-registry Download nanvix registry and show compilation instructions" ) ;
120- eprintln ! ( " --clear-registry Clear the nanvix registry cache" ) ;
125+ // Require script path for default operation
126+ let script_path = cli. script_path . unwrap_or_else ( || {
127+ eprintln ! ( "error: the following required arguments were not provided:\n <SCRIPT>\n " ) ;
128+ eprintln ! ( "Usage: hyperlight-nanvix [OPTIONS] <SCRIPT>" ) ;
129+ eprintln ! ( " hyperlight-nanvix setup-registry" ) ;
130+ eprintln ! ( " hyperlight-nanvix clear-registry" ) ;
131+ eprintln ! ( "\n For more information, try '--help'." ) ;
121132 std:: process:: exit ( 1 ) ;
122- } ;
133+ } ) ;
123134
124135 // Check if file exists
125136 if !script_path. exists ( ) {
@@ -128,7 +139,7 @@ async fn main() -> Result<()> {
128139 }
129140
130141 // Initialize nanvix logging only when --verbose is specified
131- if verbose {
142+ if cli . verbose {
132143 log:: init (
133144 false ,
134145 DEFAULT_LOG_LEVEL ,
@@ -146,7 +157,7 @@ async fn main() -> Result<()> {
146157 let mut sandbox = Sandbox :: new ( config) ?;
147158
148159 // Run the workload
149- match sandbox. run ( script_path) . await {
160+ match sandbox. run ( & script_path) . await {
150161 Ok ( ( ) ) => { }
151162 Err ( e) => {
152163 eprintln ! ( "Error running workload: {}" , e) ;
0 commit comments