Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/znippy

.nornir/decompress-guide.md

znippy decompress — guide

Class: guide · audience: a techie restoring bytes from a .znippy archive. The what is in decompress-design.md; the why in decompress-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