Stevedore.Archive (Stevedore v0.2.0)

Copy Markdown View Source

A pure tar reader/writer plus gzip helpers.

OCI layers are tar archives (optionally gzip- or zstd-compressed). This reads and writes them without shelling out to tar: the writer emits POSIX ustar headers; the reader also understands GNU long-name (L) and PAX extended-header (x) records, which real registry images use for paths longer than 100 bytes. zstd is added in a later phase (optional NIF); gzip is native via Erlang's :zlib.

Spec: POSIX pax/ustar format.

Summary

Functions

Decompresses gzip data, returning {:error, :gzip} on malformed input.

Gzip-compresses data (RFC 1952).

Reads a tar archive into a list of entries, in archive order.

Decompresses zstd data. Raises a clear error if the optional :ezstd NIF isn't available.

Writes entries to a tar archive, returning {:ok, binary} or an error tuple.

Writes entries to a tar archive (ustar). Raises Stevedore.Archive.Error on an unencodable entry (e.g. a path too long for ustar headers).

Zstd-compresses data. Raises a clear error if the optional :ezstd NIF isn't available.

Whether zstd support is available — i.e. the optional :ezstd NIF is loaded. gzip is always available natively; zstd requires adding {:ezstd, "~> 1.1"} to your deps.

Types

entry()

@type entry() :: %{
  name: String.t(),
  type: :regular | :directory | :symlink | :hardlink,
  mode: non_neg_integer(),
  size: non_neg_integer(),
  linkname: String.t() | nil,
  content: binary() | nil
}

Functions

gunzip(data)

@spec gunzip(binary()) :: {:ok, binary()} | {:error, :gzip}

Decompresses gzip data, returning {:error, :gzip} on malformed input.

gzip(data)

@spec gzip(iodata()) :: binary()

Gzip-compresses data (RFC 1952).

Examples

iex> Stevedore.Archive.gunzip(Stevedore.Archive.gzip("payload"))
{:ok, "payload"}

read(tar)

@spec read(binary()) :: {:ok, [entry()]} | {:error, Stevedore.Archive.Error.t()}

Reads a tar archive into a list of entries, in archive order.

Examples

iex> tar = Stevedore.Archive.write!([%{name: "a.txt", type: :regular, mode: 0o644, size: 2, linkname: nil, content: "hi"}])
iex> {:ok, [entry]} = Stevedore.Archive.read(tar)
iex> {entry.name, entry.content}
{"a.txt", "hi"}

unzstd(data)

@spec unzstd(binary()) :: {:ok, binary()} | {:error, :zstd}

Decompresses zstd data. Raises a clear error if the optional :ezstd NIF isn't available.

write(entries)

@spec write([entry()]) :: {:ok, binary()} | {:error, Stevedore.Archive.Error.t()}

Writes entries to a tar archive, returning {:ok, binary} or an error tuple.

Examples

iex> {:ok, tar} = Stevedore.Archive.write([%{name: "a", type: :regular, mode: 0o644, size: 0, linkname: nil, content: ""}])
iex> is_binary(tar)
true

write!(entries)

@spec write!([entry()]) :: binary()

Writes entries to a tar archive (ustar). Raises Stevedore.Archive.Error on an unencodable entry (e.g. a path too long for ustar headers).

Examples

iex> tar = Stevedore.Archive.write!([%{name: "d", type: :directory, mode: 0o755, size: 0, linkname: nil, content: nil}])
iex> {:ok, [entry]} = Stevedore.Archive.read(tar)
iex> entry.type
:directory

zstd(data)

@spec zstd(iodata()) :: binary()

Zstd-compresses data. Raises a clear error if the optional :ezstd NIF isn't available.

zstd_available?()

@spec zstd_available?() :: boolean()

Whether zstd support is available — i.e. the optional :ezstd NIF is loaded. gzip is always available natively; zstd requires adding {:ezstd, "~> 1.1"} to your deps.