1use clap::{Parser, Subcommand};
3use std::path::PathBuf;
4
5#[derive(Parser)]
7#[command(name = "hexz", version, about, long_about = None)]
8#[command(disable_help_flag = true)] #[command(styles = get_styles())]
10pub struct Cli {
11 #[arg(short, long, action = clap::ArgAction::SetTrue)]
12 pub help: bool,
13
14 #[command(subcommand)]
15 pub command: Option<Commands>,
16}
17
18fn get_styles() -> clap::builder::Styles {
19 use clap::builder::styling::{AnsiColor, Effects, Styles};
20 Styles::styled()
21 .header(AnsiColor::Yellow.on_default() | Effects::BOLD)
22 .usage(AnsiColor::Green.on_default() | Effects::BOLD)
23 .literal(AnsiColor::Cyan.on_default() | Effects::BOLD)
24 .placeholder(AnsiColor::Cyan.on_default())
25}
26
27#[derive(Subcommand)]
29pub enum Commands {
30 #[command(display_order = 1)]
35 #[command(
36 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."
37 )]
38 #[command(
39 after_help = "hexz pack --disk ./model.bin --output model.hxz --compression zstd --cdc"
40 )]
41 Pack {
42 #[arg(long)]
44 disk: Option<PathBuf>,
45
46 #[arg(long)]
48 memory: Option<PathBuf>,
49
50 #[arg(short, long)]
52 output: PathBuf,
53
54 #[arg(long, default_value = "lz4")]
56 compression: String,
57
58 #[arg(long)]
60 encrypt: bool,
61
62 #[arg(long)]
64 train_dict: bool,
65
66 #[arg(long, default_value_t = 65536, value_parser = clap::value_parser!(u32).range(1..))]
68 block_size: u32,
69
70 #[arg(long)]
72 cdc: bool,
73
74 #[arg(long, default_value_t = 16384, value_parser = clap::value_parser!(u32).range(1..))]
76 min_chunk: u32,
77
78 #[arg(long, default_value_t = 65536, value_parser = clap::value_parser!(u32).range(1..))]
80 avg_chunk: u32,
81
82 #[arg(long, default_value_t = 131072, value_parser = clap::value_parser!(u32).range(1..))]
84 max_chunk: u32,
85
86 #[arg(long, short)]
88 silent: bool,
89 },
90
91 #[command(display_order = 2)]
93 #[command(
94 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."
95 )]
96 #[command(after_help = "hexz info ./model.hxz --json")]
97 Info {
98 snap: PathBuf,
100
101 #[arg(long)]
103 json: bool,
104 },
105
106 #[cfg(feature = "diagnostics")]
108 #[command(display_order = 3)]
109 #[command(
110 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."
111 )]
112 #[command(after_help = "hexz diff --overlay finetuned.hxz --blocks")]
113 Diff {
114 overlay: PathBuf,
116
117 #[arg(long)]
119 blocks: bool,
120
121 #[arg(long)]
123 files: bool,
124 },
125
126 #[command(display_order = 4)]
128 #[command(
129 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."
130 )]
131 #[command(after_help = "hexz build --source ./checkpoints/ --output archive.hxz")]
132 Build {
133 #[arg(long)]
135 source: PathBuf,
136
137 #[arg(long)]
139 memory: Option<PathBuf>,
140
141 #[arg(short, long)]
143 output: PathBuf,
144
145 #[arg(long)]
147 profile: Option<String>,
148
149 #[arg(long)]
151 encrypt: bool,
152
153 #[arg(long)]
155 cdc: bool,
156 },
157
158 #[cfg(feature = "diagnostics")]
160 #[command(display_order = 5)]
161 #[command(
162 long_about = "Performs a deep structural analysis of the archive format.\n\nUsed primarily for debugging corruption issues or optimizing block alignment strategies."
163 )]
164 #[command(after_help = "hexz analyze ./corrupt_image.hxz")]
165 Analyze {
166 input: PathBuf,
168 },
169
170 #[command(display_order = 6)]
172 #[command(
173 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."
174 )]
175 #[command(after_help = "hexz convert --format tar --input data.tar --output data.hxz")]
176 Convert {
177 format: String,
179
180 input: PathBuf,
182
183 output: PathBuf,
185
186 #[arg(long, default_value = "lz4")]
188 compression: String,
189
190 #[arg(long, default_value_t = 65536)]
192 block_size: u32,
193
194 #[arg(long)]
196 profile: Option<String>,
197
198 #[arg(long, short)]
200 silent: bool,
201 },
202
203 #[cfg(feature = "fuse")]
208 #[command(display_order = 10)]
209 #[command(
210 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."
211 )]
212 #[command(after_help = "hexz boot --snap ubuntu.hxz --ram 4G --no-graphics")]
213 Boot {
214 snap: String,
216
217 #[arg(long)]
219 ram: Option<String>,
220
221 #[arg(long)]
223 no_kvm: bool,
224
225 #[arg(long, default_value = "user")]
227 network: String,
228
229 #[arg(long, default_value = "qemu")]
231 backend: String,
232
233 #[arg(long)]
235 persist: Option<PathBuf>,
236
237 #[arg(long)]
239 qmp_socket: Option<PathBuf>,
240
241 #[arg(long)]
243 no_graphics: bool,
244
245 #[arg(long)]
247 vnc: bool,
248 },
249
250 #[cfg(feature = "fuse")]
252 #[command(display_order = 11)]
253 #[command(
254 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."
255 )]
256 #[command(after_help = "hexz install --iso alpine.iso --output alpine-base.hxz")]
257 Install {
258 #[arg(long)]
260 iso: PathBuf,
261
262 #[arg(long, default_value = "10G")]
264 primary_size: String,
265
266 #[arg(long, default_value = "4G")]
268 ram: String,
269
270 #[arg(short, long)]
272 output: PathBuf,
273
274 #[arg(long)]
276 no_graphics: bool,
277
278 #[arg(long)]
280 vnc: bool,
281
282 #[arg(long)]
284 cdc: bool,
285 },
286
287 #[cfg(unix)]
289 #[command(display_order = 12)]
290 #[command(
291 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."
292 )]
293 #[command(after_help = "hexz snap --socket /tmp/qmp.sock --base base.hxz --output live.hxz")]
294 Snap {
295 #[arg(long)]
297 socket: PathBuf,
298
299 #[arg(long)]
301 base: PathBuf,
302
303 #[arg(long)]
305 overlay: PathBuf,
306
307 #[arg(short, long)]
309 output: PathBuf,
310 },
311
312 #[command(display_order = 13)]
314 #[command(
315 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."
316 )]
317 #[command(after_help = "hexz commit base.hxz overlay.bin new_model.hxz --thin")]
318 Commit {
319 base: PathBuf,
321
322 overlay: PathBuf,
324
325 output: PathBuf,
327
328 #[arg(long, default_value = "lz4")]
330 compression: String,
331
332 #[arg(long, default_value_t = 65536, value_parser = clap::value_parser!(u32).range(1..))]
334 block_size: u32,
335
336 #[arg(long)]
338 keep_overlay: bool,
339
340 #[arg(long)]
342 flatten: bool,
343
344 #[arg(long)]
346 message: Option<String>,
347
348 #[arg(long)]
350 thin: bool,
351 },
352
353 #[cfg(feature = "fuse")]
355 #[command(display_order = 14)]
356 #[command(
357 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."
358 )]
359 #[command(after_help = "hexz mount model.hxz /mnt/model --rw")]
360 Mount {
361 snap: String,
363
364 mountpoint: PathBuf,
366
367 #[arg(long)]
369 overlay: Option<PathBuf>,
370
371 #[arg(short, long)]
373 daemon: bool,
374
375 #[arg(long)]
377 rw: bool,
378
379 #[arg(long)]
381 cache_size: Option<String>,
382
383 #[arg(long, default_value_t = 1000)]
385 uid: u32,
386
387 #[arg(long, default_value_t = 1000)]
389 gid: u32,
390
391 #[arg(long)]
393 nbd: bool,
394 },
395
396 #[cfg(feature = "fuse")]
398 #[command(display_order = 15)]
399 #[command(long_about = "Unmounts a previously mounted Hexz filesystem.")]
400 #[command(after_help = "hexz unmount /mnt/model")]
401 Unmount {
402 mountpoint: PathBuf,
404 },
405
406 #[cfg(feature = "diagnostics")]
411 #[command(display_order = 20)]
412 #[command(
413 long_about = "Checks the system for compatibility with Hexz features (FUSE, KVM, AVX2, etc.)."
414 )]
415 #[command(after_help = "hexz doctor")]
416 Doctor,
417
418 #[cfg(feature = "diagnostics")]
420 #[command(display_order = 21)]
421 #[command(
422 long_about = "Runs read/write benchmarks on a specific archive to test throughput and latency."
423 )]
424 #[command(after_help = "hexz bench model.hxz --threads 4")]
425 Bench {
426 image: PathBuf,
428
429 #[arg(long)]
431 block_size: Option<u32>,
432
433 #[arg(long)]
435 duration: Option<u64>,
436
437 #[arg(long)]
439 threads: Option<usize>,
440 },
441
442 #[cfg(feature = "server")]
444 #[command(display_order = 22)]
445 #[command(
446 long_about = "Starts an HTTP/S3 compatible server to stream the snapshot over the network.\n\nClients can fetch specific byte ranges efficiently."
447 )]
448 #[command(after_help = "hexz serve model.hxz --port 8080")]
449 Serve {
450 snap: String,
452
453 #[arg(long, default_value_t = 8080)]
455 port: u16,
456
457 #[arg(short, long)]
459 daemon: bool,
460
461 #[arg(long)]
463 nbd: bool,
464
465 #[arg(long)]
467 s3: bool,
468 },
469
470 #[cfg(feature = "signing")]
472 #[command(display_order = 23)]
473 #[command(long_about = "Generates an Ed25519 keypair for signing Hexz archives.")]
474 #[command(after_help = "hexz keygen --output-dir ~/.hexz/keys")]
475 Keygen {
476 #[arg(short, long)]
478 output_dir: Option<PathBuf>,
479 },
480
481 #[cfg(feature = "signing")]
483 #[command(display_order = 24)]
484 #[command(long_about = "Cryptographically signs a Hexz archive using a private key.")]
485 #[command(after_help = "hexz sign --key private.pem model.hxz")]
486 Sign {
487 #[arg(long)]
489 key: PathBuf,
490
491 image: PathBuf,
493 },
494
495 #[cfg(feature = "signing")]
497 #[command(display_order = 25)]
498 #[command(
499 long_about = "Verifies the cryptographic signature of an archive using a public key."
500 )]
501 #[command(after_help = "hexz verify --key public.pem model.hxz")]
502 Verify {
503 #[arg(long)]
505 key: PathBuf,
506
507 image: PathBuf,
509 },
510}