1use clap::{Parser, Subcommand};
2use std::path::PathBuf;
3
4#[derive(Parser)]
6#[command(name = "hexz", version, about, long_about = None)]
7#[command(disable_help_flag = true)] #[command(styles = get_styles())]
9pub struct Cli {
10 #[arg(short, long, action = clap::ArgAction::SetTrue)]
11 pub help: bool,
12
13 #[command(subcommand)]
14 pub command: Option<Commands>,
15}
16
17fn get_styles() -> clap::builder::Styles {
18 use clap::builder::styling::{AnsiColor, Effects, Styles};
19 Styles::styled()
20 .header(AnsiColor::Yellow.on_default() | Effects::BOLD)
21 .usage(AnsiColor::Green.on_default() | Effects::BOLD)
22 .literal(AnsiColor::Cyan.on_default() | Effects::BOLD)
23 .placeholder(AnsiColor::Cyan.on_default())
24}
25
26#[derive(Subcommand)]
28pub enum Commands {
29 #[command(display_order = 1)]
34 #[command(
35 long_about = "Creates a highly compressed, encrypted, and deduplicated archive from a disk image or memory dump.\n\nIt uses Content-Defined Chunking (CDC) to ensure that only changed weights are stored when archiving multiple versions of a model. This is the primary way to ingest data into Hexz."
36 )]
37 #[command(after_help = "hexz pack model.hxz --disk ./model.bin --compression zstd --cdc")]
38 Pack {
39 output: PathBuf,
41
42 #[arg(long)]
44 disk: Option<PathBuf>,
45
46 #[arg(long)]
48 memory: Option<PathBuf>,
49
50 #[arg(long, default_value = "lz4")]
52 compression: String,
53
54 #[arg(long)]
56 encrypt: bool,
57
58 #[arg(long)]
60 train_dict: bool,
61
62 #[arg(long, default_value_t = 65536, value_parser = clap::value_parser!(u32).range(1..))]
64 block_size: u32,
65
66 #[arg(long)]
68 cdc: bool,
69
70 #[arg(long, default_value_t = 16384, value_parser = clap::value_parser!(u32).range(1..))]
72 min_chunk: u32,
73
74 #[arg(long, default_value_t = 65536, value_parser = clap::value_parser!(u32).range(1..))]
76 avg_chunk: u32,
77
78 #[arg(long, default_value_t = 131072, value_parser = clap::value_parser!(u32).range(1..))]
80 max_chunk: u32,
81
82 #[arg(long, short)]
84 silent: bool,
85 },
86
87 #[command(display_order = 2)]
89 #[command(
90 long_about = "Reads the header and index of a Hexz archive without decompressing the full body.\n\nUse this to verify archive integrity, check compression ratios, or view metadata about the stored snapshot."
91 )]
92 #[command(after_help = "hexz inspect ./model.hxz --json")]
93 Inspect {
94 snap: PathBuf,
96
97 #[arg(long)]
99 json: bool,
100 },
101
102 #[cfg(feature = "diagnostics")]
104 #[command(display_order = 3)]
105 #[command(
106 long_about = "Analyzes the differences between a base image and an overlay.\n\nThis is useful for auditing what changed in a fine-tuning run or verifying that a thin snapshot only contains the expected deltas."
107 )]
108 #[command(after_help = "hexz diff finetuned.overlay --blocks")]
109 Diff {
110 overlay: PathBuf,
112
113 #[arg(long)]
115 blocks: bool,
116
117 #[arg(long)]
119 files: bool,
120 },
121
122 #[command(display_order = 4)]
124 #[command(
125 long_about = "Recursively builds a Hexz archive from a local directory structure.\n\nUnlike 'pack' which handles raw disk images, 'build' is designed for file-system level packing."
126 )]
127 #[command(after_help = "hexz build ./checkpoints/ archive.hxz")]
128 Build {
129 source: PathBuf,
131
132 output: PathBuf,
134
135 #[arg(long)]
137 memory: Option<PathBuf>,
138
139 #[arg(long)]
141 profile: Option<String>,
142
143 #[arg(long)]
145 encrypt: bool,
146
147 #[arg(long)]
149 cdc: bool,
150 },
151
152 #[cfg(feature = "diagnostics")]
154 #[command(display_order = 5)]
155 #[command(
156 long_about = "Performs a deep structural analysis of the archive format.\n\nUsed primarily for debugging corruption issues or optimizing block alignment strategies."
157 )]
158 #[command(after_help = "hexz analyze ./corrupt_image.hxz")]
159 Analyze {
160 input: PathBuf,
162 },
163
164 #[command(display_order = 6)]
166 #[command(
167 long_about = "Ingests external formats like tar, HDF5, or WebDataset into a Hexz snapshot.\n\nThis allows legacy datasets to benefit from Hexz's random access and deduplication features."
168 )]
169 #[command(after_help = "hexz convert tar data.tar data.hxz")]
170 Convert {
171 format: String,
173
174 input: PathBuf,
176
177 output: PathBuf,
179
180 #[arg(long, default_value = "lz4")]
182 compression: String,
183
184 #[arg(long, default_value_t = 65536)]
186 block_size: u32,
187
188 #[arg(long)]
190 profile: Option<String>,
191
192 #[arg(long, short)]
194 silent: bool,
195 },
196
197 #[cfg(feature = "fuse")]
202 #[command(display_order = 10)]
203 #[command(
204 long_about = "Boots a transient Virtual Machine directly from a Hexz snapshot.\n\nThe VM uses a copy-on-write overlay, meaning the original snapshot remains immutable. Changes are lost on shutdown unless --persist is used."
205 )]
206 #[command(after_help = "hexz boot ubuntu.hxz --ram 4G --no-graphics")]
207 Boot {
208 snap: String,
210
211 #[arg(long)]
213 ram: Option<String>,
214
215 #[arg(long)]
217 no_kvm: bool,
218
219 #[arg(long, default_value = "user")]
221 network: String,
222
223 #[arg(long, default_value = "qemu")]
225 backend: String,
226
227 #[arg(long)]
229 persist: Option<PathBuf>,
230
231 #[arg(long)]
233 qmp_socket: Option<PathBuf>,
234
235 #[arg(long)]
237 no_graphics: bool,
238
239 #[arg(long)]
241 vnc: bool,
242 },
243
244 #[cfg(feature = "fuse")]
246 #[command(display_order = 11)]
247 #[command(
248 long_about = "Runs an OS installer from an ISO and captures the result into a new Hexz snapshot.\n\nThis automates the process of creating base images for VMs."
249 )]
250 #[command(after_help = "hexz install alpine.iso alpine-base.hxz")]
251 Install {
252 iso: PathBuf,
254
255 output: PathBuf,
257
258 #[arg(long, default_value = "10G")]
260 primary_size: String,
261
262 #[arg(long, default_value = "4G")]
264 ram: String,
265
266 #[arg(long)]
268 no_graphics: bool,
269
270 #[arg(long)]
272 vnc: bool,
273
274 #[arg(long)]
276 cdc: bool,
277 },
278
279 #[cfg(unix)]
281 #[command(display_order = 12)]
282 #[command(
283 long_about = "Triggers a live snapshot of a running VM via the QMP socket.\n\nThis allows for capturing the state of a running system without shutting it down."
284 )]
285 #[command(after_help = "hexz snap /tmp/qmp.sock base.hxz overlay.bin live.hxz")]
286 Snap {
287 socket: PathBuf,
289
290 base: PathBuf,
292
293 overlay: PathBuf,
295
296 output: PathBuf,
298 },
299
300 #[command(display_order = 13)]
302 #[command(
303 long_about = "Finalizes a writable overlay into a new immutable snapshot.\n\nSupports 'thin' snapshots which only store the deltas referencing the parent, ideal for iterative model fine-tuning."
304 )]
305 #[command(after_help = "hexz commit base.hxz overlay.bin new_model.hxz --thin")]
306 Commit {
307 base: PathBuf,
309
310 overlay: PathBuf,
312
313 output: PathBuf,
315
316 #[arg(long, default_value = "lz4")]
318 compression: String,
319
320 #[arg(long, default_value_t = 65536, value_parser = clap::value_parser!(u32).range(1..))]
322 block_size: u32,
323
324 #[arg(long)]
326 keep_overlay: bool,
327
328 #[arg(long)]
330 flatten: bool,
331
332 #[arg(long)]
334 message: Option<String>,
335
336 #[arg(long)]
338 thin: bool,
339 },
340
341 #[cfg(feature = "fuse")]
343 #[command(display_order = 14)]
344 #[command(
345 long_about = "Mounts a Hexz snapshot as a FUSE filesystem.\n\nAllows standard tools to read data from the snapshot as if it were a normal directory."
346 )]
347 #[command(after_help = "hexz mount model.hxz /mnt/model --rw")]
348 Mount {
349 snap: String,
351
352 mountpoint: PathBuf,
354
355 #[arg(long)]
357 overlay: Option<PathBuf>,
358
359 #[arg(short, long)]
361 daemon: bool,
362
363 #[arg(long)]
365 rw: bool,
366
367 #[arg(long)]
369 cache_size: Option<String>,
370
371 #[arg(long, default_value_t = 1000)]
373 uid: u32,
374
375 #[arg(long, default_value_t = 1000)]
377 gid: u32,
378
379 #[arg(long)]
381 nbd: bool,
382 },
383
384 #[cfg(feature = "fuse")]
386 #[command(display_order = 15)]
387 #[command(long_about = "Unmounts a previously mounted Hexz filesystem.")]
388 #[command(after_help = "hexz unmount /mnt/model")]
389 Unmount {
390 mountpoint: PathBuf,
392 },
393
394 #[cfg(feature = "diagnostics")]
399 #[command(display_order = 20)]
400 #[command(
401 long_about = "Checks the system for compatibility with Hexz features (FUSE, KVM, AVX2, etc.)."
402 )]
403 #[command(after_help = "hexz doctor")]
404 Doctor,
405
406 #[cfg(feature = "diagnostics")]
408 #[command(display_order = 21)]
409 #[command(
410 long_about = "Runs read/write benchmarks on a specific archive to test throughput and latency."
411 )]
412 #[command(after_help = "hexz bench model.hxz --threads 4")]
413 Bench {
414 image: PathBuf,
416
417 #[arg(long)]
419 block_size: Option<u32>,
420
421 #[arg(long)]
423 duration: Option<u64>,
424
425 #[arg(long)]
427 threads: Option<usize>,
428 },
429
430 #[cfg(feature = "server")]
432 #[command(display_order = 22)]
433 #[command(
434 long_about = "Starts an HTTP/S3 compatible server to stream the snapshot over the network.\n\nClients can fetch specific byte ranges efficiently."
435 )]
436 #[command(after_help = "hexz serve model.hxz --port 8080")]
437 Serve {
438 snap: String,
440
441 #[arg(long, default_value_t = 8080)]
443 port: u16,
444
445 #[arg(short, long)]
447 daemon: bool,
448
449 #[arg(long)]
451 nbd: bool,
452
453 #[arg(long)]
455 s3: bool,
456 },
457
458 #[cfg(feature = "signing")]
460 #[command(display_order = 23)]
461 #[command(long_about = "Generates an Ed25519 keypair for signing Hexz archives.")]
462 #[command(after_help = "hexz keygen --output-dir ~/.hexz/keys")]
463 Keygen {
464 #[arg(short, long)]
466 output_dir: Option<PathBuf>,
467 },
468
469 #[cfg(feature = "signing")]
471 #[command(display_order = 24)]
472 #[command(long_about = "Cryptographically signs a Hexz archive using a private key.")]
473 #[command(after_help = "hexz sign private.pem model.hxz")]
474 Sign {
475 key: PathBuf,
477
478 image: PathBuf,
480 },
481
482 #[cfg(feature = "signing")]
484 #[command(display_order = 25)]
485 #[command(
486 long_about = "Verifies the cryptographic signature of an archive using a public key."
487 )]
488 #[command(after_help = "hexz verify public.pem model.hxz")]
489 Verify {
490 key: PathBuf,
492
493 image: PathBuf,
495 },
496}