Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.

Commit 0c2658b

Browse files
committed
refactor: switch CLI argument parsing to clap
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
1 parent 66c1985 commit 0c2658b

3 files changed

Lines changed: 174 additions & 37 deletions

File tree

Cargo.lock

Lines changed: 128 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ description = "A Hyperlight VMM wrapper with out-of-the-box support for running
88
nanvix = { git = "https://github.com/nanvix/nanvix", rev = "4cde8f1903f54b6cf6117f0ea5061a1c00a68973", features = ["single-process", "hyperlight"] }
99
tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }
1010
anyhow = "1.0"
11+
clap = { version = "4", features = ["derive"] }
1112
libc = "0.2.178"
1213

1314
# NAPI bindings (optional)

src/bin/hyperlight-nanvix.rs

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,35 @@
11
use anyhow::Result;
2+
use clap::{Parser, Subcommand};
23
use hyperlight_nanvix::{cache, RuntimeConfig, Sandbox};
34
use nanvix::log;
45
use 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(after_help = "Supported file types: .js, .mjs (JavaScript), .py (Python), .elf, .o (Binary)")]
13+
struct Cli {
14+
/// Show detailed nanvix logging
15+
#[arg(long)]
16+
verbose: bool,
17+
18+
#[command(subcommand)]
19+
command: Option<Commands>,
20+
21+
/// Path to the script to run
22+
#[arg(value_name = "SCRIPT")]
23+
script_path: Option<PathBuf>,
24+
}
25+
26+
#[derive(Subcommand)]
27+
enum Commands {
28+
/// Download nanvix registry and show compilation instructions
29+
SetupRegistry,
30+
/// Clear the nanvix registry cache
31+
ClearRegistry,
32+
}
733

834
/// Default log-level (overridden by RUST_LOG environment variable if set).
935
const DEFAULT_LOG_LEVEL: &str = "info";
@@ -76,42 +102,25 @@ async fn clear_registry_command() -> Result<()> {
76102

77103
#[tokio::main]
78104
async fn main() -> Result<()> {
79-
// Parse command line arguments first
80-
let args: Vec<String> = env::args().collect();
105+
let cli = Cli::parse();
81106

82-
// Check for flags
83-
let verbose = args.contains(&"--verbose".to_string());
84-
let setup_registry = args.contains(&"--setup-registry".to_string());
85-
let clear_registry = args.contains(&"--clear-registry".to_string());
86-
87-
// Handle setup-registry command
88-
if setup_registry {
89-
return setup_registry_command().await;
90-
}
91-
92-
// Handle clear-registry command
93-
if clear_registry {
94-
return clear_registry_command().await;
107+
// Handle subcommands
108+
if let Some(command) = cli.command {
109+
return match command {
110+
Commands::SetupRegistry => setup_registry_command().await,
111+
Commands::ClearRegistry => clear_registry_command().await,
112+
};
95113
}
96114

97-
// Find the script argument (first non-flag argument)
98-
let script_arg = args
99-
.iter()
100-
.position(|arg| !arg.starts_with("--") && !arg.ends_with("hyperlight-nanvix"));
101-
102-
let script_path = if let Some(idx) = script_arg {
103-
Path::new(&args[idx])
104-
} else {
105-
eprintln!("Usage: {} [--verbose] <script_path>", args[0]);
106-
eprintln!(" {} --setup-registry", args[0]);
107-
eprintln!(" {} --clear-registry", args[0]);
108-
eprintln!("Supported file types: .js, .mjs (JavaScript), .py (Python), .elf, .o (Binary)");
109-
eprintln!("Options:");
110-
eprintln!(" --verbose Show detailed nanvix logging");
111-
eprintln!(" --setup-registry Download nanvix registry and show compilation instructions");
112-
eprintln!(" --clear-registry Clear the nanvix registry cache");
115+
// Require script path for default operation
116+
let script_path = cli.script_path.unwrap_or_else(|| {
117+
eprintln!("error: the following required arguments were not provided:\n <SCRIPT>\n");
118+
eprintln!("Usage: hyperlight-nanvix [OPTIONS] <SCRIPT>");
119+
eprintln!(" hyperlight-nanvix setup-registry");
120+
eprintln!(" hyperlight-nanvix clear-registry");
121+
eprintln!("\nFor more information, try '--help'.");
113122
std::process::exit(1);
114-
};
123+
});
115124

116125
// Check if file exists
117126
if !script_path.exists() {
@@ -120,7 +129,7 @@ async fn main() -> Result<()> {
120129
}
121130

122131
// Initialize nanvix logging only when --verbose is specified
123-
if verbose {
132+
if cli.verbose {
124133
log::init(
125134
false,
126135
DEFAULT_LOG_LEVEL,
@@ -138,7 +147,7 @@ async fn main() -> Result<()> {
138147
let mut sandbox = Sandbox::new(config)?;
139148

140149
// Run the workload
141-
match sandbox.run(script_path).await {
150+
match sandbox.run(&script_path).await {
142151
Ok(()) => {}
143152
Err(e) => {
144153
eprintln!("Error running workload: {}", e);

0 commit comments

Comments
 (0)