Skip to content

Commit e5fa6b3

Browse files
authored
Merge pull request #27 from jsturtevant/copilot-worktree-2026-02-04T22-14-46
refactor: switch CLI argument parsing to clap
2 parents 91f4e01 + 0027169 commit e5fa6b3

File tree

5 files changed

+185
-46
lines changed

5 files changed

+185
-46
lines changed

.github/workflows/ci.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
run: cargo test --release
5353

5454
- name: Setup registry
55-
run: cargo run --release -- --setup-registry
55+
run: cargo run --release -- setup-registry
5656

5757
- name: Run CLI with JavaScript
5858
run: cargo run --release -- guest-examples/hello.js
@@ -102,7 +102,7 @@ jobs:
102102
run: npm run build
103103

104104
- name: Setup registry
105-
run: cargo run --release -- --setup-registry
105+
run: cargo run --release -- setup-registry
106106

107107
- name: Run Node.js example
108108
run: node examples/napi.js
@@ -149,7 +149,7 @@ jobs:
149149
run: .venv/bin/maturin develop --features python
150150

151151
- name: Setup registry
152-
run: cargo run --release -- --setup-registry
152+
run: cargo run --release -- setup-registry
153153

154154
- name: Run Python example
155155
run: .venv/bin/python examples/python_sdk_example.py

Cargo.lock

Lines changed: 129 additions & 2 deletions
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
@@ -11,6 +11,7 @@ nanvix = { git = "https://github.com/nanvix/nanvix", rev = "7752e9f2deb4a5606f98
1111
] }
1212
tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }
1313
anyhow = "1.0"
14+
clap = { version = "4", features = ["derive"] }
1415
libc = "0.2.178"
1516

1617
# NAPI bindings (optional)

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ For compiled languages, you'll need to compile first, then run.
5858
#### Setup (one-time)
5959

6060
```bash
61-
cargo run -- --setup-registry
61+
cargo run -- setup-registry
6262
```
6363

6464
This downloads the toolchain and runtime files to `~/.cache/nanvix-registry/`.
@@ -251,8 +251,8 @@ cargo run --example syscall_interception
251251
**Clear cache and re-download:**
252252

253253
```bash
254-
cargo run -- --clear-registry
255-
cargo run -- --setup-registry
254+
cargo run -- clear-registry
255+
cargo run -- setup-registry
256256
```
257257

258258
**Clean socket files if networking issues occur:**

src/bin/hyperlight-nanvix.rs

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,37 @@
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(
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).
937
const 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]
86114
async 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!("\nFor 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

Comments
 (0)