Skip to main content

hexz_cli/
args.rs

1//! Command-line argument definitions for the Hexz CLI.
2//!
3//! This module defines all Clap argument structures using a nested "Noun-Verb"
4//! command hierarchy (e.g., `hexz data pack`, `hexz vm boot`).
5//!
6//! **Design principle:** Arguments are defined separately from handlers to keep
7//! CLI structure clear and testable. The actual command implementations live in
8//! the `cmd` module.
9
10use clap::{Parser, Subcommand};
11use std::path::PathBuf;
12
13/// Hexz - High-performance snapshot and streaming engine
14#[derive(Parser)]
15#[command(name = "hexz", version, about, long_about = None)]
16pub struct Cli {
17    #[command(subcommand)]
18    pub command: Commands,
19}
20
21/// Top-level command categories
22#[derive(Subcommand)]
23pub enum Commands {
24    /// Data operations (pack, inspect, diff)
25    #[command(subcommand)]
26    Data(DataCommands),
27
28    /// Virtual machine operations (boot, install, snap, commit)
29    #[command(subcommand)]
30    Vm(VmCommands),
31
32    /// System utilities (doctor, bench, serve, keygen)
33    #[command(subcommand)]
34    Sys(SysCommands),
35}
36
37#[derive(Subcommand)]
38pub enum DataCommands {
39    /// Pack data into a Hexz archive
40    Pack {
41        /// Path to disk image to pack
42        #[arg(long)]
43        disk: Option<PathBuf>,
44
45        /// Path to memory dump to pack
46        #[arg(long)]
47        memory: Option<PathBuf>,
48
49        /// Output archive path (.hxz)
50        #[arg(short, long)]
51        output: PathBuf,
52
53        /// Compression algorithm (lz4, zstd, none)
54        #[arg(long, default_value = "lz4")]
55        compression: String,
56
57        /// Enable encryption
58        #[arg(long)]
59        encrypt: bool,
60
61        /// Train compression dictionary
62        #[arg(long)]
63        train_dict: bool,
64
65        /// Block size in bytes (must be > 0)
66        #[arg(long, default_value_t = 65536, value_parser = clap::value_parser!(u32).range(1..))]
67        block_size: u32,
68
69        /// Enable content-defined chunking (CDC)
70        #[arg(long)]
71        cdc: bool,
72
73        /// Minimum chunk size for CDC
74        #[arg(long, default_value_t = 16384, value_parser = clap::value_parser!(u32).range(1..))]
75        min_chunk: u32,
76
77        /// Average chunk size for CDC
78        #[arg(long, default_value_t = 65536, value_parser = clap::value_parser!(u32).range(1..))]
79        avg_chunk: u32,
80
81        /// Maximum chunk size for CDC
82        #[arg(long, default_value_t = 131072, value_parser = clap::value_parser!(u32).range(1..))]
83        max_chunk: u32,
84
85        /// Suppress all output and progress bars
86        #[arg(long, short)]
87        silent: bool,
88    },
89
90    /// Inspect archive metadata
91    Info {
92        /// Path to archive
93        snap: PathBuf,
94
95        /// Output as JSON
96        #[arg(long)]
97        json: bool,
98    },
99
100    /// Show differences in overlay
101    #[cfg(feature = "diagnostics")]
102    Diff {
103        /// Path to overlay
104        overlay: PathBuf,
105
106        /// Show block-level differences
107        #[arg(long)]
108        blocks: bool,
109
110        /// Show file-level differences
111        #[arg(long)]
112        files: bool,
113    },
114
115    /// Build archive from source directory
116    Build {
117        /// Source directory
118        #[arg(long)]
119        source: PathBuf,
120
121        /// Optional memory dump
122        #[arg(long)]
123        memory: Option<PathBuf>,
124
125        /// Output archive path
126        #[arg(short, long)]
127        output: PathBuf,
128
129        /// Build profile
130        #[arg(long)]
131        profile: Option<String>,
132
133        /// Enable encryption
134        #[arg(long)]
135        encrypt: bool,
136
137        /// Enable CDC
138        #[arg(long)]
139        cdc: bool,
140    },
141
142    /// Analyze archive structure
143    #[cfg(feature = "diagnostics")]
144    Analyze {
145        /// Archive to analyze
146        input: PathBuf,
147    },
148
149    /// Convert external formats to Hexz snapshot
150    Convert {
151        /// Source format (tar, hdf5, webdataset)
152        format: String,
153
154        /// Input file path
155        input: PathBuf,
156
157        /// Output snapshot path (.hxz)
158        output: PathBuf,
159
160        /// Compression algorithm (lz4, zstd)
161        #[arg(long, default_value = "lz4")]
162        compression: String,
163
164        /// Block size in bytes
165        #[arg(long, default_value_t = 65536)]
166        block_size: u32,
167
168        /// Build profile (ml, eda, embedded, generic, archival)
169        #[arg(long)]
170        profile: Option<String>,
171
172        /// Suppress output
173        #[arg(long, short)]
174        silent: bool,
175    },
176}
177
178#[derive(Subcommand)]
179pub enum VmCommands {
180    /// Boot a virtual machine from snapshot
181    #[cfg(feature = "fuse")]
182    Boot {
183        /// Snapshot to boot from
184        snap: String,
185
186        /// RAM size (e.g., "4G")
187        #[arg(long)]
188        ram: Option<String>,
189
190        /// Disable KVM acceleration
191        #[arg(long)]
192        no_kvm: bool,
193
194        /// Network mode (user, bridge, none)
195        #[arg(long, default_value = "user")]
196        network: String,
197
198        /// Hypervisor backend (qemu, firecracker)
199        #[arg(long, default_value = "qemu")]
200        backend: String,
201
202        /// Persistent overlay path
203        #[arg(long)]
204        persist: Option<PathBuf>,
205
206        /// QMP socket path for control
207        #[arg(long)]
208        qmp_socket: Option<PathBuf>,
209
210        /// Disable graphics (headless mode)
211        #[arg(long)]
212        no_graphics: bool,
213
214        /// Enable VNC server
215        #[arg(long)]
216        vnc: bool,
217    },
218
219    /// Install OS from ISO to snapshot
220    #[cfg(feature = "fuse")]
221    Install {
222        /// Path to ISO image
223        #[arg(long)]
224        iso: PathBuf,
225
226        /// Virtual disk size (e.g., "10G")
227        #[arg(long, default_value = "10G")]
228        disk_size: String,
229
230        /// RAM size (e.g., "4G")
231        #[arg(long, default_value = "4G")]
232        ram: String,
233
234        /// Output snapshot path
235        #[arg(short, long)]
236        output: PathBuf,
237
238        /// Disable graphics
239        #[arg(long)]
240        no_graphics: bool,
241
242        /// Enable VNC
243        #[arg(long)]
244        vnc: bool,
245
246        /// Enable CDC
247        #[arg(long)]
248        cdc: bool,
249    },
250
251    /// Create snapshot via QMP
252    #[cfg(unix)]
253    Snap {
254        /// QMP socket path
255        #[arg(long)]
256        socket: PathBuf,
257
258        /// Base snapshot
259        #[arg(long)]
260        base: PathBuf,
261
262        /// Overlay path
263        #[arg(long)]
264        overlay: PathBuf,
265
266        /// Output snapshot
267        #[arg(short, long)]
268        output: PathBuf,
269    },
270
271    /// Commit overlay changes to new snapshot
272    Commit {
273        /// Base snapshot
274        base: PathBuf,
275
276        /// Overlay with changes
277        overlay: PathBuf,
278
279        /// Output snapshot
280        output: PathBuf,
281
282        /// Compression algorithm
283        #[arg(long, default_value = "lz4")]
284        compression: String,
285
286        /// Block size (must be > 0)
287        #[arg(long, default_value_t = 65536, value_parser = clap::value_parser!(u32).range(1..))]
288        block_size: u32,
289
290        /// Keep overlay file after commit
291        #[arg(long)]
292        keep_overlay: bool,
293
294        /// Flatten all layers into single archive
295        #[arg(long)]
296        flatten: bool,
297
298        /// Commit message
299        #[arg(long)]
300        message: Option<String>,
301
302        /// Create thin snapshot (reference base)
303        #[arg(long)]
304        thin: bool,
305    },
306
307    /// Mount snapshot as filesystem
308    #[cfg(feature = "fuse")]
309    Mount {
310        /// Snapshot to mount
311        snap: String,
312
313        /// Mount point directory
314        mountpoint: PathBuf,
315
316        /// Overlay for writes
317        #[arg(long)]
318        overlay: Option<PathBuf>,
319
320        /// Run as daemon
321        #[arg(short, long)]
322        daemon: bool,
323
324        /// Enable read-write mode
325        #[arg(long)]
326        rw: bool,
327
328        /// Cache size (e.g., "1G")
329        #[arg(long)]
330        cache_size: Option<String>,
331
332        /// User ID for files
333        #[arg(long, default_value_t = 1000)]
334        uid: u32,
335
336        /// Group ID for files
337        #[arg(long, default_value_t = 1000)]
338        gid: u32,
339
340        /// Export as NBD device
341        #[arg(long)]
342        nbd: bool,
343    },
344
345    /// Unmount filesystem
346    #[cfg(feature = "fuse")]
347    Unmount {
348        /// Mount point to unmount
349        mountpoint: PathBuf,
350    },
351}
352
353#[derive(Subcommand)]
354pub enum SysCommands {
355    /// Run system diagnostics
356    #[cfg(feature = "diagnostics")]
357    Doctor,
358
359    /// Benchmark archive performance
360    #[cfg(feature = "diagnostics")]
361    Bench {
362        /// Archive to benchmark
363        image: PathBuf,
364
365        /// Block size for testing
366        #[arg(long)]
367        block_size: Option<u32>,
368
369        /// Duration in seconds
370        #[arg(long)]
371        duration: Option<u64>,
372
373        /// Number of threads
374        #[arg(long)]
375        threads: Option<usize>,
376    },
377
378    /// Serve archive over network
379    #[cfg(feature = "server")]
380    Serve {
381        /// Snapshot to serve
382        snap: String,
383
384        /// Server port
385        #[arg(long, default_value_t = 8080)]
386        port: u16,
387
388        /// Run as daemon
389        #[arg(short, long)]
390        daemon: bool,
391
392        /// Enable NBD protocol
393        #[arg(long)]
394        nbd: bool,
395
396        /// Enable S3-compatible API
397        #[arg(long)]
398        s3: bool,
399    },
400
401    /// Generate signing keys
402    #[cfg(feature = "signing")]
403    Keygen {
404        /// Output directory for keys
405        #[arg(short, long)]
406        output_dir: Option<PathBuf>,
407    },
408
409    /// Sign archive
410    #[cfg(feature = "signing")]
411    Sign {
412        /// Private key path
413        #[arg(long)]
414        key: PathBuf,
415
416        /// Archive to sign
417        image: PathBuf,
418    },
419
420    /// Verify archive signature
421    #[cfg(feature = "signing")]
422    Verify {
423        /// Public key path
424        #[arg(long)]
425        key: PathBuf,
426
427        /// Archive to verify
428        image: PathBuf,
429    },
430}