Stevedore.Layer (Stevedore v0.2.0)

Copy Markdown View Source

Read and merge image layers in memory, without root.

A layer is a tar (usually gzip- or zstd-compressed) describing a changeset relative to the layer below. merged_view/2 applies a stack of layers bottom-to-top into the effective filesystem, honoring OCI whiteouts:

  • .wh.<name> removes <name> (and its subtree) from the lower layers
  • .wh..wh..opq makes its directory opaque — the lower layers' contents of that directory are hidden

This is the content-inspection surface a registry uses and the reading half a runtime's rootfs materialization builds on. It never writes to disk.

Spec: OCI image-spec, layer "Representing Changes".

Summary

Functions

Diffs two layers' file contents, returning the paths :added, :modified, and :removed going from a to b. Whiteout entries are ignored (compare actual content).

Reads a single layer's tar entries, decompressing as needed.

Returns the effective filesystem as a flat list of tar entries (with content), sorted by path — the input for re-tarring a flattened image.

Computes the whiteout-aware effective filesystem of a layer stack as a map of path to fs_node/0 (metadata; use Stevedore.Analyze.read_file/2 for bytes).

Types

fs_node()

@type fs_node() :: %{
  path: String.t(),
  type: :regular | :directory | :symlink | :hardlink,
  mode: non_neg_integer(),
  size: non_neg_integer(),
  linkname: String.t() | nil,
  from_layer: non_neg_integer()
}

layer_source()

@type layer_source() :: binary() | Stevedore.Descriptor.t()

Functions

diff(a, b, opts \\ [])

@spec diff(layer_source(), layer_source(), keyword()) ::
  {:ok, %{added: [String.t()], modified: [String.t()], removed: [String.t()]}}
  | {:error, term()}

Diffs two layers' file contents, returning the paths :added, :modified, and :removed going from a to b. Whiteout entries are ignored (compare actual content).

entries(layer, opts \\ [])

@spec entries(
  layer_source(),
  keyword()
) :: {:ok, [Stevedore.Archive.entry()]} | {:error, term()}

Reads a single layer's tar entries, decompressing as needed.

A Stevedore.Descriptor.t/0 is decompressed by its media type and its bytes fetched from opts[:image]; a binary is decompressed by opts[:media_type] or sniffed by magic bytes.

Examples

iex> tar = Stevedore.Archive.write!([%{name: "f", type: :regular, mode: 0o644, size: 1, linkname: nil, content: "x"}])
iex> {:ok, [entry]} = Stevedore.Layer.entries(Stevedore.Archive.gzip(tar))
iex> entry.name
"f"

merged_entries(input, opts \\ [])

@spec merged_entries(
  Stevedore.Image.t() | [binary()],
  keyword()
) :: {:ok, [Stevedore.Archive.entry()]} | {:error, term()}

Returns the effective filesystem as a flat list of tar entries (with content), sorted by path — the input for re-tarring a flattened image.

merged_view(input, opts \\ [])

@spec merged_view(
  Stevedore.Image.t() | [binary()],
  keyword()
) :: {:ok, %{optional(String.t()) => fs_node()}} | {:error, term()}

Computes the whiteout-aware effective filesystem of a layer stack as a map of path to fs_node/0 (metadata; use Stevedore.Analyze.read_file/2 for bytes).

Accepts a Stevedore.Image.t/0 or a list of layer binaries, ordered bottom-to-top.