Skip to content

Contributing

Terminal window
git clone https://github.com/masonschafercodes/zpack
cd zpack
zig build test

You need Zig 0.16.0 and nothing else. zpack has no dependencies.

Command Does
zig build Debug build, into zig-out/bin/
zig build test Every test, plus builds every example
zig build examples Build the four examples without running them
zig build example-01 Build and run one example
zig build run -- list game.zpak Run the CLI without installing
zig fmt build.zig src tests examples Format. CI checks this with --check
zig build -Dtarget=aarch64-macos Cross-compile; no extra toolchain needed

zig build test depends on the examples step, so a stale example fails the test run rather than rotting quietly.

File Holds
src/root.zig The module’s public surface, buffer size constants, Stats
src/format.zig The wire format: constants, serialization, assetId, validatePath
src/Archive.zig Opening, validating, looking up, reading, verifying, extracting
src/pack.zig Scanning a tree and streaming it into an archive
src/EntryReader.zig One entry’s original bytes, decompressing
src/StoredReader.zig One entry’s stored bytes, bounded to the entry
src/ignore.zig .zpackignore parsing and glob matching
src/main.zig Argument handling and output formatting. Nothing else

The split between main.zig and the rest is load-bearing: everything the CLI does, the library does, so a change to behaviour belongs in the library and a change to presentation belongs in main.zig.

Each file under tests/ is its own test binary, listed in build.zig:

File Covers
round_trip.zig Pack then extract, byte for byte
reading.zig find, read, readAlloc, entryReader
compression.zig The store-versus-deflate decision
integrity.zig Hash checking
corruption.zig Damaged archives failing cleanly
paths.zig Path validation and normalization
asset_ids.zig assetId stability and collision detection
manifest.zig Manifest output
output.zig CLI formatting
ignore.zig .zpackignore patterns
support.zig Shared helpers - not a test file itself

Adding a test file means adding it to the test_files array in build.zig. Tests inside src/ run through the mod_tests step, wired up by the test block at the bottom of root.zig.

Comments say why, not what. The code says what it does. A comment earns its place by explaining a decision, a constraint, or a trap - the colon-in-path rule, the saturating multiply, the rewind that costs a second read.

Doc comments on public declarations, including the non-obvious constraints: which buffer sizes are required, who owns returned memory, what is not checked.

Errors are named for their cause, not their symptom. AssetIdCollision rather than BadArchive. Every one is listed in the error reference; adding a new one means adding a row there.

Nothing is written to disk as a struct. The format is serialized field by field so struct layout can never change the format by accident.

Some things to keep in mind:

Does it change the archive format? If a v1 reader can no longer read what you produce, the format version has to move. See compatibility.

Does it allocate per file? The design holds that packing a 40 GB tree costs the same working set as a 40 MB one. A per-file allocation breaks that.

Does it read attacker-controlled sizes? Bound them against something real - usually the file size - before allocating or looping. See the security model.

Does it break reproducibility? Anything that lets walk order, timestamps, or environment reach the output does. See reproducible archives.

This site is an Astro Starlight project in docs/:

Terminal window
cd docs
bun install
bun run dev # http://localhost:4321
bun run build # also validates every internal link

The site uses Bun. bun.lock is committed, so bun install --frozen-lockfile is what CI runs.

CI builds it on every PR, and starlight-links-validator fails the build on a link to a page that was renamed or never written - so a broken link is a failed check rather than a 404 someone finds later.

Pages live in docs/src/content/docs/; the sidebar is in docs/astro.config.mjs. Adding a page means adding it to both.

Bugs and features: issues.

Security: a security advisory rather than a public issue. A crash, a read or write outside the intended bounds, or an allocation disproportionate to the input all count.