Debkit (Debkit v0.1.1)

Copy Markdown View Source

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

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

Types

A failure reason. See the "Errors" section above.

A supported compression format.

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

error()

@type error() :: :corrupt | :unsupported | :name_too_long

A failure reason. See the "Errors" section above.

format()

@type format() :: :gzip | :xz | :zstd

A supported compression format.

Functions

compress(format, data)

@spec compress(format(), binary()) :: {:ok, binary()} | {:error, error()}

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"}

compress!(format, data)

@spec compress!(format(), binary()) :: binary()

Like compress/2 but returns the bytes directly, raising Debkit.Error on failure.

decompress(format, data)

@spec decompress(format(), binary()) :: {:ok, binary()} | {:error, error()}

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}

decompress!(format, data)

@spec decompress!(format(), binary()) :: binary()

Like decompress/2 but returns the bytes directly, raising Debkit.Error on failure.