A tight codec library for the formats nested inside a Debian .deb.
A .deb is four formats deep: an ar
container holding debian-binary, control.tar.* and data.tar.* members;
each .tar is a tar archive; and each tar is compressed with gzip,
xz, or zstd. Debkit gives you a small, faithful codec for each layer
and nothing else — assembling them into a valid .deb (and parsing the control
fields) is left to the caller.
┌─ ar ──────────────────────────────────┐
│ debian-binary │
│ control.tar.gz ─► tar ─► gzip/xz/zstd │
│ data.tar.xz ─► tar ─► gzip/xz/zstd │
└────────────────────────────────────────┘Everything is in-memory and deterministic: writers zero out mtime / uid
/ gid and omit the ar symbol table, so the same input bytes always produce the
same output bytes (the basis for reproducible packages). The whole thing is a
thin Rustler NIF over the mature ar, tar,
flate2, xz2, and zstd crates — no xz/zstd/ar/tar binaries at
runtime, no shelling out.
Modules
Debkit—compress/2anddecompress/2for:gzip | :xz | :zstd.Debkit.Ar— read and writearcontainers.Debkit.Tar— read and writetararchives.
Errors
The non-bang functions return {:ok, result} or {:error, t:error/0}; they
never raise across the NIF boundary. The ! variants raise Debkit.Error
with the same reason. The documented reasons are:
:corrupt— the input is malformed for the codec (bad magic, truncated stream, bad headers, decompression failure).:unsupported— the input is well-formed but uses a feature this library does not implement (e.g. a tar entry that is not a regular file).:name_too_long— (writers only) a member name does not fit the target archive format.
Example: round-trip a gzip stream
iex> {:ok, gz} = Debkit.compress(:gzip, "hello, deb")
iex> Debkit.decompress(:gzip, gz)
{:ok, "hello, deb"}
Summary
Functions
Compresses data with the given format.
Like compress/2 but returns the bytes directly, raising Debkit.Error on
failure.
Decompresses data, which must be a single format stream.
Like decompress/2 but returns the bytes directly, raising Debkit.Error
on failure.
Types
Functions
Compresses data with the given format.
format is one of :gzip, :xz, or :zstd. Output is deterministic: the
gzip header carries no mtime or filename, and none of the codecs embed a
timestamp, so equal input yields equal output.
Examples
iex> {:ok, xz} = Debkit.compress(:xz, "control file body\n")
iex> Debkit.decompress(:xz, xz)
{:ok, "control file body\n"}
Like compress/2 but returns the bytes directly, raising Debkit.Error on
failure.
Decompresses data, which must be a single format stream.
format is given explicitly rather than sniffed from a filename or magic
bytes — in a .deb the format is known from the member name (control.tar.xz
→ :xz).
Returns {:error, :corrupt} if data is not a valid stream for format.
Examples
iex> {:ok, z} = Debkit.compress(:zstd, "data")
iex> Debkit.decompress(:zstd, z)
{:ok, "data"}
iex> Debkit.decompress(:gzip, "not actually gzip")
{:error, :corrupt}
Like decompress/2 but returns the bytes directly, raising Debkit.Error
on failure.