znippy decompress — guide
Class:
guide· audience: a techie restoring bytes from a.znippyarchive. The what is indecompress-design.md; the why indecompress-reasoning.md. This file is the workflow.
f0 — restore an archive (the whole workflow)
Three shapes cover everything you'll do:
# 1. full restore into a directory
znippy decompress -i archive.znippy -o ./out
# 2. selective restore — only one pkg_type and/or repo (uses the data sub-index)
znippy decompress -i archive.znippy -o ./out --type maven --repo central
# 3. one file, to stdout or to a path
znippy get -i archive.znippy -p org/foo/Bar.class # → stdout
znippy get -i archive.znippy -p org/foo/Bar.class -o Bar.class
# 4. verify every chunk's blake3 without writing files
znippy verify -i archive.znippy
An empty --type/--repo filter equals a full restore. Restore is core-count-independent: the same archive yields byte-identical output on any machine, because each chunk's checksum is bound to its chunk_seq. If a checksum fails, the command errors — it never writes a bad file and never panics.
f1 — restore from Rust
Link znippy-decompress and call the re-exported top-level functions:
use std::path::Path;
use znippy_decompress::{decompress_archive, decompress_archive_filtered};
// full restore; returns a VerifyReport (every chunk was blake3-checked)
let report = decompress_archive(Path::new("archive.znippy"), Path::new("out"))?;
// selective: keep only rows whose sub-index matches the filter
let filter = /* (pkg_type, repo) selector */;
let report = decompress_archive_filtered(
Path::new("archive.znippy"), Path::new("out"), filter)?;
Under the hood these fan out to N workers over a shared atomic row cursor; you get NVMe queue depth for free (parallel pread). Nothing to tune — no reader thread, no channel, no buffer pool to size. Output paths are sanitized (zip-slip / absolute paths rejected) before any write.
f2 — pull a single file from Rust
For one or a few files, skip the full restore:
use std::path::Path;
use znippy_common::get_file;
// resolves the chunk run via the trie/lookup, preads + verifies, returns the bytes
let bytes: Vec<u8> = get_file(Path::new("archive.znippy"), "org/foo/Bar.class")?;
get_file never materializes the whole index — it locates the file's contiguous chunk run, preads each blob, decompresses (or copies raw), blake3-verifies, and reassembles by fdata_offset. Use it when Holger asks for one path. If you hold one archive and pull many files, prefer ZnippyArchive::open + extract_file instead — see index-guide.md f1.
f3 — verify, and reading the report
znippy verify -i <archive> is the restore engine with writes suppressed: it decompresses every chunk and checks every blake3 against the index, producing a VerifyReport but no files. Use it as a cheap integrity gate in CI before shipping an archive: it exits non-zero when the report carries any corrupt file or corrupt byte, so znippy verify -i A && ship really does gate on integrity (it prints the counters either way — read the exit status, not stdout). From Rust the same VerifyReport comes back from decompress_archive, which returns Ok even for a corrupt archive — corruption is reported in report.corrupt_files / report.corrupt_bytes, so a caller must inspect those counters rather than rely on ?.
Selective restore cheatsheet
| you want… | command |
| everything | znippy decompress -i A -o out |
| just the maven artifacts | znippy decompress -i A -o out --type maven |
| one repo's rust crates | znippy decompress -i A -o out --type rust --repo crates-io |
| one file to stdout | znippy get -i A -p path/to/file |
| integrity only, no output | znippy verify -i A |