Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions lib/oci/registry.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,21 @@ defmodule OCI.Registry do

use TypedStruct

@typedoc "Repository name, e.g. `\"myorg/myrepo\"`"
@type repo_t :: String.t()

@typedoc "Content-addressable digest, e.g. `\"sha256:abc123...\"`"
@type digest_t :: String.t()

@typedoc "A tag or digest used to identify a manifest"
@type reference_t :: String.t()

@typedoc "Human-readable tag, e.g. `\"latest\"` or `\"v1.0.0\"`"
@type tag_t :: String.t()

@typedoc "Upload session identifier (UUID)"
@type uuid_t :: String.t()

@repo_name_pattern ~r/^([a-z0-9]+(?:[._-][a-z0-9]+)*)(\/[a-z0-9]+(?:[._-][a-z0-9]+)*)*$/

typedstruct do
Expand Down Expand Up @@ -64,8 +79,8 @@ defmodule OCI.Registry do
adapter(auth).challenge(registry)
end

@spec validate_repository_name(registry :: t(), repo :: String.t()) ::
{:ok, repo :: String.t()} | {:error, :NAME_INVALID, String.t()}
@spec validate_repository_name(registry :: t(), repo :: repo_t()) ::
{:ok, repo :: repo_t()} | {:error, :NAME_INVALID, String.t()}

def validate_repository_name(registry, repo) do
if Regex.match?(registry.repo_name_pattern, repo) do
Expand Down Expand Up @@ -329,7 +344,7 @@ defmodule OCI.Registry do
iex> OCI.Registry.verify_digest("hello", "invalid-digest")
{:error, :DIGEST_INVALID, %{digest: "invalid-digest", msg: "Invalid digest format"}}
"""
@spec verify_digest(binary(), String.t()) :: :ok | {:error, :DIGEST_INVALID, map()}
@spec verify_digest(binary(), digest_t()) :: :ok | {:error, :DIGEST_INVALID, map()}
def verify_digest(data, digest) do
case digest do
"sha256:" <> hash ->
Expand Down Expand Up @@ -376,7 +391,7 @@ defmodule OCI.Registry do
iex> OCI.Registry.blobs_digest_path("myrepo", "sha256:abc123")
"/v2/myrepo/blobs/sha256:abc123"
"""
@spec blobs_digest_path(String.t(), String.t()) :: String.t()
@spec blobs_digest_path(repo_t(), digest_t()) :: String.t()
def blobs_digest_path(repo, digest) do
"/#{api_version()}/#{repo}/blobs/#{digest}"
end
Expand All @@ -395,7 +410,7 @@ defmodule OCI.Registry do
iex> OCI.Registry.manifests_reference_path("library/alpine", "sha256:24dda0a1be6293020e5355d4a09b9a8bb72a8b44c27b0ca8560669b8ed52d3ec")
"/v2/library/alpine/manifests/sha256:24dda0a1be6293020e5355d4a09b9a8bb72a8b44c27b0ca8560669b8ed52d3ec"
"""
@spec manifests_reference_path(String.t(), String.t()) :: String.t()
@spec manifests_reference_path(repo_t(), reference_t()) :: String.t()
def manifests_reference_path(repo, reference) do
"/#{api_version()}/#{repo}/manifests/#{reference}"
end
Expand All @@ -411,7 +426,7 @@ defmodule OCI.Registry do
iex> OCI.Registry.blobs_uploads_path("myrepo", "123e4567-e89b-12d3-a456-426614174000")
"/v2/myrepo/blobs/uploads/123e4567-e89b-12d3-a456-426614174000"
"""
@spec blobs_uploads_path(String.t(), String.t()) :: String.t()
@spec blobs_uploads_path(repo_t(), uuid_t()) :: String.t()
def blobs_uploads_path(repo, uuid) do
"/#{api_version()}/#{repo}/blobs/uploads/#{uuid}"
end
Expand Down
87 changes: 47 additions & 40 deletions lib/oci/storage/adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ defmodule OCI.Storage.Adapter do
```
"""

alias OCI.Registry

@type t :: struct()

@type error_details_t :: any()
Expand All @@ -44,8 +46,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback blob_exists?(
storage :: t(),
repo :: String.t(),
digest :: String.t(),
repo :: Registry.repo_t(),
digest :: Registry.digest_t(),
ctx :: OCI.Context.t()
) ::
boolean()
Expand All @@ -55,8 +57,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback cancel_blob_upload(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
repo :: Registry.repo_t(),
uuid :: Registry.uuid_t(),
ctx :: OCI.Context.t()
) ::
:ok
Expand All @@ -68,9 +70,9 @@ defmodule OCI.Storage.Adapter do
"""
@callback complete_blob_upload(
storage :: t(),
repo :: String.t(),
upload_id :: String.t(),
digest :: String.t(),
repo :: Registry.repo_t(),
upload_id :: Registry.uuid_t(),
digest :: Registry.digest_t(),
ctx :: OCI.Context.t()
) ::
:ok | {:error, atom()} | {:error, atom(), error_details_t}
Expand All @@ -80,8 +82,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback delete_blob(
storage :: t(),
repo :: String.t(),
digest :: String.t(),
repo :: Registry.repo_t(),
digest :: Registry.digest_t(),
ctx :: OCI.Context.t()
) ::
:ok | {:error, :BLOB_UNKNOWN} | {:error, :BLOB_UNKNOWN, error_details_t}
Expand All @@ -91,8 +93,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback delete_manifest(
storage :: t(),
repo :: String.t(),
reference :: String.t(),
repo :: Registry.repo_t(),
reference :: Registry.reference_t(),
ctx :: OCI.Context.t()
) ::
:ok | {:error, atom()}
Expand All @@ -102,8 +104,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback get_blob(
storage :: t(),
repo :: String.t(),
digest :: String.t(),
repo :: Registry.repo_t(),
digest :: Registry.digest_t(),
ctx :: OCI.Context.t()
) ::
{:ok, content :: binary()}
Expand All @@ -115,8 +117,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback get_manifest(
storage :: t(),
repo :: String.t(),
reference :: String.t(),
repo :: Registry.repo_t(),
reference :: Registry.reference_t(),
ctx :: OCI.Context.t()
) ::
{:ok, manifest :: binary(), content_type :: String.t()}
Expand All @@ -127,8 +129,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback get_blob_upload_status(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
repo :: Registry.repo_t(),
uuid :: Registry.uuid_t(),
ctx :: OCI.Context.t()
) ::
{:ok, range :: String.t()} | {:error, term()} | {:error, term(), error_details_t}
Expand All @@ -138,8 +140,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback get_blob_upload_offset(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
repo :: Registry.repo_t(),
uuid :: Registry.uuid_t(),
ctx :: OCI.Context.t()
) ::
{:ok, size :: non_neg_integer()}
Expand All @@ -151,8 +153,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback manifest_exists?(
storage :: t(),
repo :: String.t(),
reference :: String.t(),
repo :: Registry.repo_t(),
reference :: Registry.reference_t(),
ctx :: OCI.Context.t()
) ::
boolean()
Expand All @@ -166,8 +168,12 @@ defmodule OCI.Storage.Adapter do
@doc """
Initiates a blob upload session.
"""
@callback initiate_blob_upload(storage :: t(), repo :: String.t(), ctx :: OCI.Context.t()) ::
{:ok, upload_id :: String.t()}
@callback initiate_blob_upload(
storage :: t(),
repo :: Registry.repo_t(),
ctx :: OCI.Context.t()
) ::
{:ok, upload_id :: Registry.uuid_t()}
| {:error, term()}
| {:error, term(), error_details_t}

Expand All @@ -176,11 +182,11 @@ defmodule OCI.Storage.Adapter do
"""
@callback list_tags(
storage :: t(),
repo :: String.t(),
repo :: Registry.repo_t(),
pagination :: OCI.Pagination.t(),
ctx :: OCI.Context.t()
) ::
{:ok, tags :: [String.t()]}
{:ok, tags :: [Registry.tag_t()]}
| {:error, :NAME_UNKNOWN}
| {:error, :NAME_UNKNOWN, error_details_t}

Expand All @@ -189,9 +195,9 @@ defmodule OCI.Storage.Adapter do
"""
@callback mount_blob(
storage :: t(),
repo :: String.t(),
digest :: String.t(),
from_repo :: String.t(),
repo :: Registry.repo_t(),
digest :: Registry.digest_t(),
from_repo :: Registry.repo_t(),
ctx :: OCI.Context.t()
) ::
:ok | {:error, :BLOB_UNKNOWN} | {:error, :BLOB_UNKNOWN, error_details_t}
Expand All @@ -201,10 +207,10 @@ defmodule OCI.Storage.Adapter do
"""
@callback store_manifest(
storage :: t(),
repo :: String.t(),
reference :: String.t(),
repo :: Registry.repo_t(),
reference :: Registry.reference_t(),
manifest :: map(),
manifest_digest :: String.t(),
manifest_digest :: Registry.digest_t(),
ctx :: OCI.Context.t()
) ::
:ok
Expand All @@ -214,15 +220,16 @@ defmodule OCI.Storage.Adapter do
@doc """
Checks if a repository exists.
"""
@callback repo_exists?(storage :: t(), repo :: String.t(), ctx :: OCI.Context.t()) :: boolean()
@callback repo_exists?(storage :: t(), repo :: Registry.repo_t(), ctx :: OCI.Context.t()) ::
boolean()

@doc """
Uploads a chunk of data to an ongoing blob upload.
"""
@callback upload_blob_chunk(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
repo :: Registry.repo_t(),
uuid :: Registry.uuid_t(),
chunk :: binary(),
content_range :: String.t(),
ctx :: OCI.Context.t()
Expand All @@ -239,8 +246,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback list_referrers(
storage :: t(),
repo :: String.t(),
subject_digest :: String.t(),
repo :: Registry.repo_t(),
subject_digest :: Registry.digest_t(),
filters :: map(),
ctx :: OCI.Context.t()
) ::
Expand All @@ -251,8 +258,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback put_referrer(
storage :: t(),
repo :: String.t(),
subject_digest :: String.t(),
repo :: Registry.repo_t(),
subject_digest :: Registry.digest_t(),
descriptor :: map(),
ctx :: OCI.Context.t()
) ::
Expand All @@ -263,8 +270,8 @@ defmodule OCI.Storage.Adapter do
"""
@callback upload_exists?(
storage :: t(),
repo :: String.t(),
uuid :: String.t(),
repo :: Registry.repo_t(),
uuid :: Registry.uuid_t(),
ctx :: OCI.Context.t()
) ::
boolean()
Expand Down
Loading