# `Stevedore.Manifest`
[🔗](https://github.com/oshlabs/stevedore/blob/v0.2.0/lib/stevedore/manifest.ex#L1)

An image manifest **or** an image index (multi-arch manifest list).

The decoded `json` is kept alongside the **raw bytes** it was parsed from, because a manifest's
digest is computed over those exact bytes — re-serializing JSON would change the digest. Always
move manifests by their `raw` field.

Handles both OCI and Docker schema-2 vocabularies, and recognizes (read-only) legacy Docker
schema-1 manifests.

Spec: [OCI manifest](https://github.com/opencontainers/image-spec/blob/main/manifest.md) and
[image-index](https://github.com/opencontainers/image-spec/blob/main/image-index.md).

# `kind`

```elixir
@type kind() :: :manifest | :index
```

# `t`

```elixir
@type t() :: %Stevedore.Manifest{
  digest: Stevedore.Digest.t() | nil,
  json: map(),
  media_type: String.t(),
  raw: binary()
}
```

# `config`

```elixir
@spec config(t()) ::
  {:ok, Stevedore.Descriptor.t()}
  | {:error, :not_a_manifest | {:bad_input, term()}}
```

The config descriptor of an image manifest.

# `host_platform`

```elixir
@spec host_platform() :: keyword()
```

The host platform as a keyword (`os`, `architecture`), mapping the BEAM's architecture string
to OCI/Go naming (`x86_64` → `amd64`, `aarch64` → `arm64`, …).

# `kind`

```elixir
@spec kind(t()) :: kind()
```

Whether the manifest is a single image (`:manifest`) or a multi-arch index (`:index`).

# `layers`

```elixir
@spec layers(t()) ::
  {:ok, [Stevedore.Descriptor.t()]}
  | {:error, :not_a_manifest | {:bad_input, term()}}
```

The ordered layer descriptors of an image manifest.

# `manifests`

```elixir
@spec manifests(t()) ::
  {:ok, [Stevedore.Descriptor.t()]}
  | {:error, :not_an_index | {:bad_input, term()}}
```

The per-platform manifest descriptors of an index.

# `parse`

```elixir
@spec parse(binary(), String.t() | nil) :: {:ok, t()} | {:error, {:bad_input, term()}}
```

Parses raw manifest bytes, using `content_type` (the registry's `Content-Type`) when given and
otherwise sniffing the media type from the JSON. The `digest` is computed over `raw`.

## Examples

    iex> raw = ~s({"schemaVersion":2,"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[]})
    iex> {:ok, m} = Stevedore.Manifest.parse(raw)
    iex> Stevedore.Manifest.kind(m)
    :index

# `select`

```elixir
@spec select(
  t(),
  keyword()
) ::
  {:ok, Stevedore.Descriptor.t()}
  | {:error, :no_match | :not_an_index | {:bad_input, term()}}
```

Selects the manifest descriptor from an index matching a platform.

`platform` is a keyword of `:os`, `:architecture`, and optional `:variant`; it defaults to the
host platform. Errors with `:not_an_index` for a single manifest and `:no_match` when no entry
matches.

## Examples

    iex> raw = ~s({"mediaType":"application/vnd.oci.image.index.v1+json","manifests":[
    ...>   {"mediaType":"application/vnd.oci.image.manifest.v1+json","size":1,
    ...>    "digest":"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    ...>    "platform":{"os":"linux","architecture":"arm64"}}]})
    iex> {:ok, m} = Stevedore.Manifest.parse(raw)
    iex> {:ok, d} = Stevedore.Manifest.select(m, os: "linux", architecture: "arm64")
    iex> d.platform.architecture
    "arm64"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
