diff --git a/lib/oci/registry.ex b/lib/oci/registry.ex index 2d26f49..c0a81d7 100644 --- a/lib/oci/registry.ex +++ b/lib/oci/registry.ex @@ -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 @@ -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 @@ -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 -> @@ -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 @@ -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 @@ -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 diff --git a/lib/oci/storage/adapter.ex b/lib/oci/storage/adapter.ex index 8c14dec..9c6c7bf 100644 --- a/lib/oci/storage/adapter.ex +++ b/lib/oci/storage/adapter.ex @@ -35,6 +35,8 @@ defmodule OCI.Storage.Adapter do ``` """ + alias OCI.Registry + @type t :: struct() @type error_details_t :: any() @@ -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() @@ -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 @@ -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} @@ -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} @@ -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()} @@ -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()} @@ -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()} @@ -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} @@ -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()} @@ -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() @@ -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} @@ -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} @@ -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} @@ -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 @@ -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() @@ -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() ) :: @@ -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() ) :: @@ -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()