1
0
mirror of https://github.com/regclient/regclient.git synced 2025-04-18 22:44:00 +03:00

Refactoring the type package

I feel like I need to explain, this is all to move the descriptor package.
The platform package could not use the predefined errors in types because of a circular dependency from descriptor.
The most appropriate way to reorg this is to move descriptor out of the type package since it was more complex than a self contained type.
When doing that, type aliases were needed to avoid breaking changes to existing users.
Those aliases themselves caused circular dependency loops because of the media types and errors, so those were also pulled out to separate packages.
All of the old values were aliased and deprecated, and to fix the linter, those deprecations were fixed by updating the imports... everywhere.

Signed-off-by: Brandon Mitchell <git@bmitch.net>
This commit is contained in:
Brandon Mitchell 2024-03-04 15:43:18 -05:00
parent b991f53ad7
commit eea06e2a5c
No known key found for this signature in database
GPG Key ID: 6E0FF28C767A8BEE
108 changed files with 2529 additions and 1721 deletions

36
blob.go
View File

@ -14,6 +14,8 @@ import (
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/blob" "github.com/regclient/regclient/types/blob"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -36,12 +38,12 @@ func BlobWithCallback(callback func(kind types.CallbackKind, instance string, st
// BlobCopy copies a blob between two locations. // BlobCopy copies a blob between two locations.
// If the blob already exists in the target, the copy is skipped. // If the blob already exists in the target, the copy is skipped.
// A server side cross repository blob mount is attempted. // A server side cross repository blob mount is attempted.
func (rc *RegClient) BlobCopy(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d types.Descriptor, opts ...BlobOpts) error { func (rc *RegClient) BlobCopy(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d descriptor.Descriptor, opts ...BlobOpts) error {
if !refSrc.IsSetRepo() { if !refSrc.IsSetRepo() {
return fmt.Errorf("refSrc is not set: %s%.0w", refSrc.CommonName(), types.ErrInvalidReference) return fmt.Errorf("refSrc is not set: %s%.0w", refSrc.CommonName(), errs.ErrInvalidReference)
} }
if !refTgt.IsSetRepo() { if !refTgt.IsSetRepo() {
return fmt.Errorf("refTgt is not set: %s%.0w", refTgt.CommonName(), types.ErrInvalidReference) return fmt.Errorf("refTgt is not set: %s%.0w", refTgt.CommonName(), errs.ErrInvalidReference)
} }
var opt blobOpt var opt blobOpt
for _, optFn := range opts { for _, optFn := range opts {
@ -173,9 +175,9 @@ func (rc *RegClient) BlobCopy(ctx context.Context, refSrc ref.Ref, refTgt ref.Re
// BlobDelete removes a blob from the registry. // BlobDelete removes a blob from the registry.
// This method should only be used to repair a damaged registry. // This method should only be used to repair a damaged registry.
// Typically a server side garbage collection should be used to purge unused blobs. // Typically a server side garbage collection should be used to purge unused blobs.
func (rc *RegClient) BlobDelete(ctx context.Context, r ref.Ref, d types.Descriptor) error { func (rc *RegClient) BlobDelete(ctx context.Context, r ref.Ref, d descriptor.Descriptor) error {
if !r.IsSetRepo() { if !r.IsSetRepo() {
return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
schemeAPI, err := rc.schemeGet(r.Scheme) schemeAPI, err := rc.schemeGet(r.Scheme)
if err != nil { if err != nil {
@ -186,13 +188,13 @@ func (rc *RegClient) BlobDelete(ctx context.Context, r ref.Ref, d types.Descript
// BlobGet retrieves a blob, returning a reader. // BlobGet retrieves a blob, returning a reader.
// This reader must be closed to free up resources that limit concurrent pulls. // This reader must be closed to free up resources that limit concurrent pulls.
func (rc *RegClient) BlobGet(ctx context.Context, r ref.Ref, d types.Descriptor) (blob.Reader, error) { func (rc *RegClient) BlobGet(ctx context.Context, r ref.Ref, d descriptor.Descriptor) (blob.Reader, error) {
data, err := d.GetData() data, err := d.GetData()
if err == nil { if err == nil {
return blob.NewReader(blob.WithDesc(d), blob.WithRef(r), blob.WithReader(bytes.NewReader(data))), nil return blob.NewReader(blob.WithDesc(d), blob.WithRef(r), blob.WithReader(bytes.NewReader(data))), nil
} }
if !r.IsSetRepo() { if !r.IsSetRepo() {
return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
schemeAPI, err := rc.schemeGet(r.Scheme) schemeAPI, err := rc.schemeGet(r.Scheme)
if err != nil { if err != nil {
@ -202,9 +204,9 @@ func (rc *RegClient) BlobGet(ctx context.Context, r ref.Ref, d types.Descriptor)
} }
// BlobGetOCIConfig retrieves an OCI config from a blob, automatically extracting the JSON. // BlobGetOCIConfig retrieves an OCI config from a blob, automatically extracting the JSON.
func (rc *RegClient) BlobGetOCIConfig(ctx context.Context, r ref.Ref, d types.Descriptor) (blob.OCIConfig, error) { func (rc *RegClient) BlobGetOCIConfig(ctx context.Context, r ref.Ref, d descriptor.Descriptor) (blob.OCIConfig, error) {
if !r.IsSetRepo() { if !r.IsSetRepo() {
return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
b, err := rc.BlobGet(ctx, r, d) b, err := rc.BlobGet(ctx, r, d)
if err != nil { if err != nil {
@ -214,9 +216,9 @@ func (rc *RegClient) BlobGetOCIConfig(ctx context.Context, r ref.Ref, d types.De
} }
// BlobHead is used to verify if a blob exists and is accessible. // BlobHead is used to verify if a blob exists and is accessible.
func (rc *RegClient) BlobHead(ctx context.Context, r ref.Ref, d types.Descriptor) (blob.Reader, error) { func (rc *RegClient) BlobHead(ctx context.Context, r ref.Ref, d descriptor.Descriptor) (blob.Reader, error) {
if !r.IsSetRepo() { if !r.IsSetRepo() {
return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
schemeAPI, err := rc.schemeGet(r.Scheme) schemeAPI, err := rc.schemeGet(r.Scheme)
if err != nil { if err != nil {
@ -226,12 +228,12 @@ func (rc *RegClient) BlobHead(ctx context.Context, r ref.Ref, d types.Descriptor
} }
// BlobMount attempts to perform a server side copy/mount of the blob between repositories. // BlobMount attempts to perform a server side copy/mount of the blob between repositories.
func (rc *RegClient) BlobMount(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d types.Descriptor) error { func (rc *RegClient) BlobMount(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d descriptor.Descriptor) error {
if !refSrc.IsSetRepo() { if !refSrc.IsSetRepo() {
return fmt.Errorf("ref is not set: %s%.0w", refSrc.CommonName(), types.ErrInvalidReference) return fmt.Errorf("ref is not set: %s%.0w", refSrc.CommonName(), errs.ErrInvalidReference)
} }
if !refTgt.IsSetRepo() { if !refTgt.IsSetRepo() {
return fmt.Errorf("ref is not set: %s%.0w", refTgt.CommonName(), types.ErrInvalidReference) return fmt.Errorf("ref is not set: %s%.0w", refTgt.CommonName(), errs.ErrInvalidReference)
} }
schemeAPI, err := rc.schemeGet(refSrc.Scheme) schemeAPI, err := rc.schemeGet(refSrc.Scheme)
if err != nil { if err != nil {
@ -247,13 +249,13 @@ func (rc *RegClient) BlobMount(ctx context.Context, refSrc ref.Ref, refTgt ref.R
// This will attempt an anonymous blob mount first which some registries may support. // This will attempt an anonymous blob mount first which some registries may support.
// It will then try doing a full put of the blob without chunking (most widely supported). // It will then try doing a full put of the blob without chunking (most widely supported).
// If the full put fails, it will fall back to a chunked upload (useful for flaky networks). // If the full put fails, it will fall back to a chunked upload (useful for flaky networks).
func (rc *RegClient) BlobPut(ctx context.Context, r ref.Ref, d types.Descriptor, rdr io.Reader) (types.Descriptor, error) { func (rc *RegClient) BlobPut(ctx context.Context, r ref.Ref, d descriptor.Descriptor, rdr io.Reader) (descriptor.Descriptor, error) {
if !r.IsSetRepo() { if !r.IsSetRepo() {
return types.Descriptor{}, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return descriptor.Descriptor{}, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
schemeAPI, err := rc.schemeGet(r.Scheme) schemeAPI, err := rc.schemeGet(r.Scheme)
if err != nil { if err != nil {
return types.Descriptor{}, err return descriptor.Descriptor{}, err
} }
return schemeAPI.BlobPut(ctx, r, d, rdr) return schemeAPI.BlobPut(ctx, r, d, rdr)
} }

View File

@ -18,7 +18,8 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/reqresp" "github.com/regclient/regclient/internal/reqresp"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -184,7 +185,7 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := rc.BlobGet(ctx, ref, types.Descriptor{Digest: d1, Size: int64(len(blob1))}) br, err := rc.BlobGet(ctx, ref, descriptor.Descriptor{Digest: d1, Size: int64(len(blob1))})
if err != nil { if err != nil {
t.Fatalf("Failed running BlobGet: %v", err) t.Fatalf("Failed running BlobGet: %v", err)
} }
@ -204,7 +205,7 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
desc := types.Descriptor{ desc := descriptor.Descriptor{
Digest: d1, Digest: d1,
Size: int64(len(blob1)), Size: int64(len(blob1)),
Data: blob1, Data: blob1,
@ -228,7 +229,7 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := rc.BlobHead(ctx, ref, types.Descriptor{Digest: d1}) br, err := rc.BlobHead(ctx, ref, descriptor.Descriptor{Digest: d1})
if err != nil { if err != nil {
t.Fatalf("Failed running BlobHead: %v", err) t.Fatalf("Failed running BlobHead: %v", err)
} }
@ -243,12 +244,12 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := rc.BlobGet(ctx, ref, types.Descriptor{Digest: dMissing}) br, err := rc.BlobGet(ctx, ref, descriptor.Descriptor{Digest: dMissing})
if err == nil { if err == nil {
defer br.Close() defer br.Close()
t.Fatalf("Unexpected success running BlobGet") t.Fatalf("Unexpected success running BlobGet")
} }
if !errors.Is(err, types.ErrNotFound) { if !errors.Is(err, errs.ErrNotFound) {
t.Errorf("Error does not match \"ErrNotFound\": %v", err) t.Errorf("Error does not match \"ErrNotFound\": %v", err)
} }
}) })
@ -258,7 +259,7 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := rc.BlobGet(ctx, ref, types.Descriptor{Digest: d2}) br, err := rc.BlobGet(ctx, ref, descriptor.Descriptor{Digest: d2})
if err != nil { if err != nil {
t.Fatalf("Failed running BlobGet: %v", err) t.Fatalf("Failed running BlobGet: %v", err)
} }
@ -277,12 +278,12 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := rc.BlobGet(ctx, ref, types.Descriptor{Digest: d1}) br, err := rc.BlobGet(ctx, ref, descriptor.Descriptor{Digest: d1})
if err == nil { if err == nil {
br.Close() br.Close()
t.Fatalf("Unexpected success running BlobGet") t.Fatalf("Unexpected success running BlobGet")
} }
if !errors.Is(err, types.ErrHTTPUnauthorized) { if !errors.Is(err, errs.ErrHTTPUnauthorized) {
t.Errorf("Error does not match \"ErrUnauthorized\": %v", err) t.Errorf("Error does not match \"ErrUnauthorized\": %v", err)
} }
}) })
@ -672,7 +673,7 @@ func TestBlobPut(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br := bytes.NewReader(blob1) br := bytes.NewReader(blob1)
dp, err := rc.BlobPut(ctx, ref, types.Descriptor{Digest: d1, Size: int64(len(blob1))}, br) dp, err := rc.BlobPut(ctx, ref, descriptor.Descriptor{Digest: d1, Size: int64(len(blob1))}, br)
if err != nil { if err != nil {
t.Fatalf("Failed running BlobPut: %v", err) t.Fatalf("Failed running BlobPut: %v", err)
} }
@ -691,7 +692,7 @@ func TestBlobPut(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br := bytes.NewReader(blob2) br := bytes.NewReader(blob2)
dp, err := rc.BlobPut(ctx, ref, types.Descriptor{Digest: d2, Size: int64(len(blob2))}, br) dp, err := rc.BlobPut(ctx, ref, descriptor.Descriptor{Digest: d2, Size: int64(len(blob2))}, br)
if err != nil { if err != nil {
t.Fatalf("Failed running BlobPut: %v", err) t.Fatalf("Failed running BlobPut: %v", err)
} }
@ -710,7 +711,7 @@ func TestBlobPut(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br := bytes.NewReader(blob3) br := bytes.NewReader(blob3)
dp, err := rc.BlobPut(ctx, ref, types.Descriptor{Digest: d3, Size: int64(len(blob3))}, br) dp, err := rc.BlobPut(ctx, ref, descriptor.Descriptor{Digest: d3, Size: int64(len(blob3))}, br)
if err != nil { if err != nil {
t.Fatalf("Failed running BlobPut: %v", err) t.Fatalf("Failed running BlobPut: %v", err)
} }
@ -1163,7 +1164,7 @@ func TestBlobCopy(t *testing.T) {
// same repo // same repo
t.Run("Copy Same Repo", func(t *testing.T) { t.Run("Copy Same Repo", func(t *testing.T) {
err = rc.BlobCopy(ctx, refA, refA, types.Descriptor{Digest: d1}) err = rc.BlobCopy(ctx, refA, refA, descriptor.Descriptor{Digest: d1})
if err != nil { if err != nil {
t.Fatalf("Failed to copy d1 from repo a to a: %v", err) t.Fatalf("Failed to copy d1 from repo a to a: %v", err)
} }
@ -1171,7 +1172,7 @@ func TestBlobCopy(t *testing.T) {
// copy blob // copy blob
t.Run("Copy Diff Repo", func(t *testing.T) { t.Run("Copy Diff Repo", func(t *testing.T) {
err = rc.BlobCopy(ctx, refA, refB, types.Descriptor{Digest: d1}) err = rc.BlobCopy(ctx, refA, refB, descriptor.Descriptor{Digest: d1})
if err != nil { if err != nil {
t.Fatalf("Failed to copy d1 from repo a to b: %v", err) t.Fatalf("Failed to copy d1 from repo a to b: %v", err)
} }
@ -1179,7 +1180,7 @@ func TestBlobCopy(t *testing.T) {
// blob exists // blob exists
t.Run("Copy Existing Blob", func(t *testing.T) { t.Run("Copy Existing Blob", func(t *testing.T) {
err = rc.BlobCopy(ctx, refA, refB, types.Descriptor{Digest: d1}) err = rc.BlobCopy(ctx, refA, refB, descriptor.Descriptor{Digest: d1})
if err != nil { if err != nil {
t.Fatalf("Failed to copy d1 from repo a to b: %v", err) t.Fatalf("Failed to copy d1 from repo a to b: %v", err)
} }
@ -1187,7 +1188,7 @@ func TestBlobCopy(t *testing.T) {
// copy fails on get, retry succeeds // copy fails on get, retry succeeds
t.Run("Copy Flaky Get", func(t *testing.T) { t.Run("Copy Flaky Get", func(t *testing.T) {
err = rc.BlobCopy(ctx, refA, refB, types.Descriptor{Digest: d2}) err = rc.BlobCopy(ctx, refA, refB, descriptor.Descriptor{Digest: d2})
if err != nil { if err != nil {
t.Fatalf("Failed to copy d2 from repo a to b: %v", err) t.Fatalf("Failed to copy d2 from repo a to b: %v", err)
} }
@ -1195,7 +1196,7 @@ func TestBlobCopy(t *testing.T) {
// copy fails on put, retry succeeds // copy fails on put, retry succeeds
t.Run("Copy Flaky Put", func(t *testing.T) { t.Run("Copy Flaky Put", func(t *testing.T) {
err = rc.BlobCopy(ctx, refA, refB, types.Descriptor{Digest: d3}) err = rc.BlobCopy(ctx, refA, refB, descriptor.Descriptor{Digest: d3})
if err != nil { if err != nil {
t.Fatalf("Failed to copy d3 from repo a to b: %v", err) t.Fatalf("Failed to copy d3 from repo a to b: %v", err)
} }

View File

@ -14,8 +14,8 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
lua "github.com/yuin/gopher-lua" lua "github.com/yuin/gopher-lua"
"github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/blob" "github.com/regclient/regclient/types/blob"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -113,7 +113,7 @@ func (s *Sandbox) blobGet(ls *lua.LState) int {
"ref": r.r.CommonName(), "ref": r.r.CommonName(),
"digest": d, "digest": d,
}).Debug("Retrieve blob") }).Debug("Retrieve blob")
b, err := s.rc.BlobGet(s.ctx, r.r, types.Descriptor{Digest: digest.Digest(d)}) b, err := s.rc.BlobGet(s.ctx, r.r, descriptor.Descriptor{Digest: digest.Digest(d)})
if err != nil { if err != nil {
ls.RaiseError("Failed retrieving \"%s\" blob \"%s\": %v", r.r.CommonName(), d, err) ls.RaiseError("Failed retrieving \"%s\" blob \"%s\": %v", r.r.CommonName(), d, err)
} }
@ -141,7 +141,7 @@ func (s *Sandbox) blobHead(ls *lua.LState) int {
"ref": r.r.CommonName(), "ref": r.r.CommonName(),
"digest": d, "digest": d,
}).Debug("Retrieve blob") }).Debug("Retrieve blob")
b, err := s.rc.BlobHead(s.ctx, r.r, types.Descriptor{Digest: digest.Digest(d)}) b, err := s.rc.BlobHead(s.ctx, r.r, descriptor.Descriptor{Digest: digest.Digest(d)})
if err != nil { if err != nil {
ls.RaiseError("Failed retrieving \"%s\" blob \"%s\": %v", r.r.CommonName(), d, err) ls.RaiseError("Failed retrieving \"%s\" blob \"%s\": %v", r.r.CommonName(), d, err)
} }
@ -192,7 +192,7 @@ func (s *Sandbox) blobPut(ls *lua.LState) int {
ls.ArgError(2, "blob content expected") ls.ArgError(2, "blob content expected")
} }
dOut, err := s.rc.BlobPut(s.ctx, r.r, types.Descriptor{Digest: d}, rdr) dOut, err := s.rc.BlobPut(s.ctx, r.r, descriptor.Descriptor{Digest: d}, rdr)
if err != nil { if err != nil {
ls.RaiseError("Failed to put blob: %v", err) ls.RaiseError("Failed to put blob: %v", err)
} }

View File

@ -22,7 +22,10 @@ import (
"github.com/regclient/regclient/pkg/template" "github.com/regclient/regclient/pkg/template"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -36,7 +39,7 @@ const (
) )
var manifestKnownTypes = []string{ var manifestKnownTypes = []string{
types.MediaTypeOCI1Manifest, mediatype.OCI1Manifest,
} }
var artifactFileKnownTypes = []string{ var artifactFileKnownTypes = []string{
"application/octet-stream", "application/octet-stream",
@ -197,7 +200,7 @@ regctl artifact tree --digest-tags ghcr.io/regclient/regsync:latest`,
artifactListCmd.Flags().StringVar(&artifactOpts.sortAnnot, "sort-annotation", "", "Annotation used for sorting results") artifactListCmd.Flags().StringVar(&artifactOpts.sortAnnot, "sort-annotation", "", "Annotation used for sorting results")
artifactListCmd.Flags().BoolVar(&artifactOpts.sortDesc, "sort-desc", false, "Sort in descending order") artifactListCmd.Flags().BoolVar(&artifactOpts.sortDesc, "sort-desc", false, "Sort in descending order")
artifactPutCmd.Flags().StringVarP(&artifactOpts.artifactMT, "media-type", "", types.MediaTypeOCI1Manifest, "EXPERIMENTAL: Manifest media-type") artifactPutCmd.Flags().StringVarP(&artifactOpts.artifactMT, "media-type", "", mediatype.OCI1Manifest, "EXPERIMENTAL: Manifest media-type")
_ = artifactPutCmd.RegisterFlagCompletionFunc("media-type", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { _ = artifactPutCmd.RegisterFlagCompletionFunc("media-type", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return manifestKnownTypes, cobra.ShellCompDirectiveNoFileComp return manifestKnownTypes, cobra.ShellCompDirectiveNoFileComp
}) })
@ -263,7 +266,7 @@ func (artifactOpts *artifactCmd) runArtifactGet(cmd *cobra.Command, args []strin
} }
r := ref.Ref{} r := ref.Ref{}
matchOpts := types.MatchOpt{ matchOpts := descriptor.MatchOpt{
ArtifactType: artifactOpts.filterAT, ArtifactType: artifactOpts.filterAT,
SortAnnotation: artifactOpts.sortAnnot, SortAnnotation: artifactOpts.sortAnnot,
SortDesc: artifactOpts.sortDesc, SortDesc: artifactOpts.sortDesc,
@ -335,13 +338,13 @@ func (artifactOpts *artifactCmd) runArtifactGet(cmd *cobra.Command, args []strin
if m.IsList() { if m.IsList() {
mi, ok := m.(manifest.Indexer) mi, ok := m.(manifest.Indexer)
if !ok { if !ok {
return fmt.Errorf("manifest list does not support index methods%.0w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest list does not support index methods%.0w", errs.ErrUnsupportedMediaType)
} }
dl, err := mi.GetManifestList() dl, err := mi.GetManifestList()
if err != nil { if err != nil {
return fmt.Errorf("failed to get descriptor list: %w", err) return fmt.Errorf("failed to get descriptor list: %w", err)
} }
d, err := types.DescriptorListSearch(dl, matchOpts) d, err := descriptor.DescriptorListSearch(dl, matchOpts)
if err != nil { if err != nil {
return fmt.Errorf("no matching artifacts found in index: %w", err) return fmt.Errorf("no matching artifacts found in index: %w", err)
} }
@ -353,7 +356,7 @@ func (artifactOpts *artifactCmd) runArtifactGet(cmd *cobra.Command, args []strin
} }
mi, ok := m.(manifest.Imager) mi, ok := m.(manifest.Imager)
if !ok { if !ok {
return fmt.Errorf("manifest does not support image methods%.0w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest does not support image methods%.0w", errs.ErrUnsupportedMediaType)
} }
// if config-file defined, create file as writer, perform a blob get // if config-file defined, create file as writer, perform a blob get
@ -527,7 +530,7 @@ func (artifactOpts *artifactCmd) runArtifactList(cmd *cobra.Command, args []stri
rc := artifactOpts.rootOpts.newRegClient() rc := artifactOpts.rootOpts.newRegClient()
defer rc.Close(ctx, rSubject) defer rc.Close(ctx, rSubject)
matchOpts := types.MatchOpt{ matchOpts := descriptor.MatchOpt{
ArtifactType: artifactOpts.filterAT, ArtifactType: artifactOpts.filterAT,
SortAnnotation: artifactOpts.sortAnnot, SortAnnotation: artifactOpts.sortAnnot,
SortDesc: artifactOpts.sortDesc, SortDesc: artifactOpts.sortDesc,
@ -613,10 +616,10 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
var err error var err error
switch artifactOpts.artifactMT { switch artifactOpts.artifactMT {
case types.MediaTypeOCI1Artifact: case mediatype.OCI1Artifact:
log.Warnf("changing media-type is experimental and non-portable") log.Warnf("changing media-type is experimental and non-portable")
hasConfig = false hasConfig = false
case "", types.MediaTypeOCI1Manifest: case "", mediatype.OCI1Manifest:
hasConfig = true hasConfig = true
default: default:
return fmt.Errorf("unsupported manifest media type: %s", artifactOpts.artifactMT) return fmt.Errorf("unsupported manifest media type: %s", artifactOpts.artifactMT)
@ -655,7 +658,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
// validate/set artifactType and config.mediaType // validate/set artifactType and config.mediaType
if hasConfig && artifactOpts.artifactConfigMT == "" { if hasConfig && artifactOpts.artifactConfigMT == "" {
if artifactOpts.artifactConfig == "" { if artifactOpts.artifactConfig == "" {
artifactOpts.artifactConfigMT = types.MediaTypeOCI1Empty artifactOpts.artifactConfigMT = mediatype.OCI1Empty
} else { } else {
if artifactOpts.artifactType != "" { if artifactOpts.artifactType != "" {
artifactOpts.artifactConfigMT = artifactOpts.artifactType artifactOpts.artifactConfigMT = artifactOpts.artifactType
@ -666,10 +669,10 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
} }
} }
if !hasConfig && (artifactOpts.artifactConfig != "" || artifactOpts.artifactConfigMT != "") { if !hasConfig && (artifactOpts.artifactConfig != "" || artifactOpts.artifactConfigMT != "") {
return fmt.Errorf("cannot set config-type or config-file on %s%.0w", artifactOpts.artifactMT, types.ErrUnsupportedMediaType) return fmt.Errorf("cannot set config-type or config-file on %s%.0w", artifactOpts.artifactMT, errs.ErrUnsupportedMediaType)
} }
if artifactOpts.artifactType == "" { if artifactOpts.artifactType == "" {
if !hasConfig || artifactOpts.artifactConfigMT == types.MediaTypeOCI1Empty { if !hasConfig || artifactOpts.artifactConfigMT == mediatype.OCI1Empty {
log.Warnf("using default value for artifact-type is not recommended") log.Warnf("using default value for artifact-type is not recommended")
artifactOpts.artifactType = defaultMTArtifact artifactOpts.artifactType = defaultMTArtifact
} }
@ -704,7 +707,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
rc := artifactOpts.rootOpts.newRegClient() rc := artifactOpts.rootOpts.newRegClient()
defer rc.Close(ctx, r) defer rc.Close(ctx, r)
var subjectDesc *types.Descriptor var subjectDesc *descriptor.Descriptor
if rSubject.IsSet() { if rSubject.IsSet() {
smh, err := rc.ManifestHead(ctx, rSubject, regclient.WithManifestRequireDigest()) smh, err := rc.ManifestHead(ctx, rSubject, regclient.WithManifestRequireDigest())
if err != nil { if err != nil {
@ -723,21 +726,21 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
if err != nil { if err != nil {
return fmt.Errorf("failed to get platform descriptor: %w", err) return fmt.Errorf("failed to get platform descriptor: %w", err)
} }
subjectDesc = &types.Descriptor{MediaType: d.MediaType, Digest: d.Digest, Size: d.Size} subjectDesc = &descriptor.Descriptor{MediaType: d.MediaType, Digest: d.Digest, Size: d.Size}
} else { } else {
d := smh.GetDescriptor() d := smh.GetDescriptor()
subjectDesc = &types.Descriptor{MediaType: d.MediaType, Digest: d.Digest, Size: d.Size} subjectDesc = &descriptor.Descriptor{MediaType: d.MediaType, Digest: d.Digest, Size: d.Size}
} }
} }
// read config, or initialize to an empty json config // read config, or initialize to an empty json config
confDesc := types.Descriptor{} confDesc := descriptor.Descriptor{}
if hasConfig { if hasConfig {
var configBytes []byte var configBytes []byte
var configDigest digest.Digest var configDigest digest.Digest
if artifactOpts.artifactConfig == "" { if artifactOpts.artifactConfig == "" {
configBytes = types.EmptyData configBytes = descriptor.EmptyData
configDigest = types.EmptyDigest configDigest = descriptor.EmptyDigest
} else { } else {
var err error var err error
configBytes, err = os.ReadFile(artifactOpts.artifactConfig) configBytes, err = os.ReadFile(artifactOpts.artifactConfig)
@ -747,19 +750,19 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
configDigest = digest.FromBytes(configBytes) configDigest = digest.FromBytes(configBytes)
} }
// push config to registry // push config to registry
_, err = rc.BlobPut(ctx, r, types.Descriptor{Digest: configDigest, Size: int64(len(configBytes))}, bytes.NewReader(configBytes)) _, err = rc.BlobPut(ctx, r, descriptor.Descriptor{Digest: configDigest, Size: int64(len(configBytes))}, bytes.NewReader(configBytes))
if err != nil { if err != nil {
return err return err
} }
// save config descriptor to manifest // save config descriptor to manifest
confDesc = types.Descriptor{ confDesc = descriptor.Descriptor{
MediaType: artifactOpts.artifactConfigMT, MediaType: artifactOpts.artifactConfigMT,
Digest: configDigest, Digest: configDigest,
Size: int64(len(configBytes)), Size: int64(len(configBytes)),
} }
} }
blobs := []types.Descriptor{} blobs := []descriptor.Descriptor{}
if len(artifactOpts.artifactFile) > 0 { if len(artifactOpts.artifactFile) > 0 {
// if files were passed // if files were passed
for i, f := range artifactOpts.artifactFile { for i, f := range artifactOpts.artifactFile {
@ -804,7 +807,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
} }
d := digester.Digest() d := digester.Digest()
// add layer to manifest // add layer to manifest
desc := types.Descriptor{ desc := descriptor.Descriptor{
MediaType: mt, MediaType: mt,
Digest: d, Digest: d,
Size: l, Size: l,
@ -825,7 +828,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
} }
blobs = append(blobs, desc) blobs = append(blobs, desc)
// if blob already exists, skip Put // if blob already exists, skip Put
bRdr, err := rc.BlobHead(ctx, r, types.Descriptor{Digest: d}) bRdr, err := rc.BlobHead(ctx, r, descriptor.Descriptor{Digest: d})
if err == nil { if err == nil {
_ = bRdr.Close() _ = bRdr.Close()
return nil return nil
@ -835,7 +838,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
if err != nil { if err != nil {
return err return err
} }
_, err = rc.BlobPut(ctx, r, types.Descriptor{Digest: d, Size: l}, rdr) _, err = rc.BlobPut(ctx, r, descriptor.Descriptor{Digest: d, Size: l}, rdr)
if err != nil { if err != nil {
return err return err
} }
@ -851,7 +854,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
if len(artifactOpts.artifactFileMT) > 0 { if len(artifactOpts.artifactFileMT) > 0 {
mt = artifactOpts.artifactFileMT[0] mt = artifactOpts.artifactFileMT[0]
} }
d, err := rc.BlobPut(ctx, r, types.Descriptor{}, cmd.InOrStdin()) d, err := rc.BlobPut(ctx, r, descriptor.Descriptor{}, cmd.InOrStdin())
if err != nil { if err != nil {
return err return err
} }
@ -860,19 +863,19 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
} }
switch artifactOpts.artifactMT { switch artifactOpts.artifactMT {
case types.MediaTypeOCI1Artifact: case mediatype.OCI1Artifact:
m := v1.ArtifactManifest{ m := v1.ArtifactManifest{
MediaType: types.MediaTypeOCI1Artifact, MediaType: mediatype.OCI1Artifact,
ArtifactType: artifactOpts.artifactType, ArtifactType: artifactOpts.artifactType,
Blobs: blobs, Blobs: blobs,
Annotations: annotations, Annotations: annotations,
Subject: subjectDesc, Subject: subjectDesc,
} }
mOpts = append(mOpts, manifest.WithOrig(m)) mOpts = append(mOpts, manifest.WithOrig(m))
case "", types.MediaTypeOCI1Manifest: case "", mediatype.OCI1Manifest:
m := v1.Manifest{ m := v1.Manifest{
Versioned: v1.ManifestSchemaVersion, Versioned: v1.ManifestSchemaVersion,
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
ArtifactType: artifactOpts.artifactType, ArtifactType: artifactOpts.artifactType,
Config: confDesc, Config: confDesc,
Layers: blobs, Layers: blobs,
@ -942,8 +945,8 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
// create a new index // create a new index
mii := v1.Index{ mii := v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Manifests: []types.Descriptor{d}, Manifests: []descriptor.Descriptor{d},
} }
mi, err := manifest.New(manifest.WithOrig(mii)) mi, err := manifest.New(manifest.WithOrig(mii))
if err != nil { if err != nil {
@ -981,7 +984,7 @@ func (artifactOpts *artifactCmd) runArtifactTree(cmd *cobra.Command, args []stri
referrerOpts := []scheme.ReferrerOpts{} referrerOpts := []scheme.ReferrerOpts{}
if artifactOpts.filterAT != "" { if artifactOpts.filterAT != "" {
referrerOpts = append(referrerOpts, scheme.WithReferrerMatchOpt(types.MatchOpt{ArtifactType: artifactOpts.filterAT})) referrerOpts = append(referrerOpts, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{ArtifactType: artifactOpts.filterAT}))
} }
if artifactOpts.filterAnnot != nil { if artifactOpts.filterAnnot != nil {
af := map[string]string{} af := map[string]string{}
@ -993,7 +996,7 @@ func (artifactOpts *artifactCmd) runArtifactTree(cmd *cobra.Command, args []stri
af[kv] = "" af[kv] = ""
} }
} }
referrerOpts = append(referrerOpts, scheme.WithReferrerMatchOpt(types.MatchOpt{Annotations: af})) referrerOpts = append(referrerOpts, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{Annotations: af}))
} }
// include digest tags if requested // include digest tags if requested

View File

@ -9,7 +9,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
func TestArtifactGet(t *testing.T) { func TestArtifactGet(t *testing.T) {
@ -28,12 +28,12 @@ func TestArtifactGet(t *testing.T) {
{ {
name: "Invalid ref", name: "Invalid ref",
args: []string{"artifact", "get", "invalid*ref"}, args: []string{"artifact", "get", "invalid*ref"},
expectErr: types.ErrInvalidReference, expectErr: errs.ErrInvalidReference,
}, },
{ {
name: "Missing manifest", name: "Missing manifest",
args: []string{"artifact", "get", "ocidir://../../testdata/testrepo:missing"}, args: []string{"artifact", "get", "ocidir://../../testdata/testrepo:missing"},
expectErr: types.ErrNotFound, expectErr: errs.ErrNotFound,
}, },
{ {
name: "By Manifest", name: "By Manifest",
@ -88,12 +88,12 @@ func TestArtifactList(t *testing.T) {
{ {
name: "Invalid ref", name: "Invalid ref",
args: []string{"artifact", "list", "invalid*ref"}, args: []string{"artifact", "list", "invalid*ref"},
expectErr: types.ErrInvalidReference, expectErr: errs.ErrInvalidReference,
}, },
{ {
name: "Missing manifest", name: "Missing manifest",
args: []string{"artifact", "list", "ocidir://../../testdata/testrepo:missing"}, args: []string{"artifact", "list", "ocidir://../../testdata/testrepo:missing"},
expectErr: types.ErrNotFound, expectErr: errs.ErrNotFound,
}, },
{ {
name: "No referrers", name: "No referrers",
@ -176,7 +176,7 @@ func TestArtifactPut(t *testing.T) {
{ {
name: "Invalid ref", name: "Invalid ref",
args: []string{"artifact", "put", "invalid*ref"}, args: []string{"artifact", "put", "invalid*ref"},
expectErr: types.ErrInvalidReference, expectErr: errs.ErrInvalidReference,
}, },
{ {
name: "Put artifact", name: "Put artifact",
@ -265,12 +265,12 @@ func TestArtifactTree(t *testing.T) {
{ {
name: "Invalid ref", name: "Invalid ref",
args: []string{"artifact", "tree", "invalid*ref"}, args: []string{"artifact", "tree", "invalid*ref"},
expectErr: types.ErrInvalidReference, expectErr: errs.ErrInvalidReference,
}, },
{ {
name: "Missing manifest", name: "Missing manifest",
args: []string{"artifact", "tree", "ocidir://../../testdata/testrepo:missing"}, args: []string{"artifact", "tree", "ocidir://../../testdata/testrepo:missing"},
expectErr: types.ErrNotFound, expectErr: errs.ErrNotFound,
}, },
{ {
name: "No referrers", name: "No referrers",

View File

@ -20,7 +20,7 @@ import (
"github.com/regclient/regclient/internal/diff" "github.com/regclient/regclient/internal/diff"
"github.com/regclient/regclient/pkg/template" "github.com/regclient/regclient/pkg/template"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -224,7 +224,7 @@ func (blobOpts *blobCmd) runBlobDelete(cmd *cobra.Command, args []string) error
"repository": r.Repository, "repository": r.Repository,
"digest": args[1], "digest": args[1],
}).Debug("Deleting blob") }).Debug("Deleting blob")
return rc.BlobDelete(ctx, r, types.Descriptor{Digest: d}) return rc.BlobDelete(ctx, r, descriptor.Descriptor{Digest: d})
} }
func (blobOpts *blobCmd) runBlobDiffConfig(cmd *cobra.Command, args []string) error { func (blobOpts *blobCmd) runBlobDiffConfig(cmd *cobra.Command, args []string) error {
@ -251,7 +251,7 @@ func (blobOpts *blobCmd) runBlobDiffConfig(cmd *cobra.Command, args []string) er
if err != nil { if err != nil {
return err return err
} }
c1, err := rc.BlobGetOCIConfig(ctx, r1, types.Descriptor{Digest: d1}) c1, err := rc.BlobGetOCIConfig(ctx, r1, descriptor.Descriptor{Digest: d1})
if err != nil { if err != nil {
return err return err
} }
@ -264,7 +264,7 @@ func (blobOpts *blobCmd) runBlobDiffConfig(cmd *cobra.Command, args []string) er
if err != nil { if err != nil {
return err return err
} }
c2, err := rc.BlobGetOCIConfig(ctx, r2, types.Descriptor{Digest: d2}) c2, err := rc.BlobGetOCIConfig(ctx, r2, descriptor.Descriptor{Digest: d2})
if err != nil { if err != nil {
return err return err
} }
@ -305,7 +305,7 @@ func (blobOpts *blobCmd) runBlobDiffLayer(cmd *cobra.Command, args []string) err
if err != nil { if err != nil {
return err return err
} }
b1, err := rc.BlobGet(ctx, r1, types.Descriptor{Digest: d1}) b1, err := rc.BlobGet(ctx, r1, descriptor.Descriptor{Digest: d1})
if err != nil { if err != nil {
return err return err
} }
@ -331,7 +331,7 @@ func (blobOpts *blobCmd) runBlobDiffLayer(cmd *cobra.Command, args []string) err
if err != nil { if err != nil {
return err return err
} }
b2, err := rc.BlobGet(ctx, r2, types.Descriptor{Digest: d2}) b2, err := rc.BlobGet(ctx, r2, descriptor.Descriptor{Digest: d2})
if err != nil { if err != nil {
return err return err
} }
@ -382,7 +382,7 @@ func (blobOpts *blobCmd) runBlobGet(cmd *cobra.Command, args []string) error {
"repository": r.Repository, "repository": r.Repository,
"digest": args[1], "digest": args[1],
}).Debug("Pulling blob") }).Debug("Pulling blob")
blob, err := rc.BlobGet(ctx, r, types.Descriptor{Digest: d}) blob, err := rc.BlobGet(ctx, r, descriptor.Descriptor{Digest: d})
if err != nil { if err != nil {
return err return err
} }
@ -424,7 +424,7 @@ func (blobOpts *blobCmd) runBlobGetFile(cmd *cobra.Command, args []string) error
"digest": args[1], "digest": args[1],
"filename": filename, "filename": filename,
}).Debug("Get file") }).Debug("Get file")
blob, err := rc.BlobGet(ctx, r, types.Descriptor{Digest: d}) blob, err := rc.BlobGet(ctx, r, descriptor.Descriptor{Digest: d})
if err != nil { if err != nil {
return err return err
} }
@ -486,7 +486,7 @@ func (blobOpts *blobCmd) runBlobHead(cmd *cobra.Command, args []string) error {
"repository": r.Repository, "repository": r.Repository,
"digest": args[1], "digest": args[1],
}).Debug("Blob head") }).Debug("Blob head")
blob, err := rc.BlobHead(ctx, r, types.Descriptor{Digest: d}) blob, err := rc.BlobHead(ctx, r, descriptor.Descriptor{Digest: d})
if err != nil { if err != nil {
return err return err
} }
@ -518,7 +518,7 @@ func (blobOpts *blobCmd) runBlobPut(cmd *cobra.Command, args []string) error {
"repository": r.Repository, "repository": r.Repository,
"digest": blobOpts.digest, "digest": blobOpts.digest,
}).Debug("Pushing blob") }).Debug("Pushing blob")
dOut, err := rc.BlobPut(ctx, r, types.Descriptor{Digest: digest.Digest(blobOpts.digest)}, cmd.InOrStdin()) dOut, err := rc.BlobPut(ctx, r, descriptor.Descriptor{Digest: digest.Digest(blobOpts.digest)}, cmd.InOrStdin())
if err != nil { if err != nil {
return err return err
} }
@ -556,7 +556,7 @@ func (blobOpts *blobCmd) runBlobCopy(cmd *cobra.Command, args []string) error {
"target": rTgt.CommonName(), "target": rTgt.CommonName(),
"digest": args[2], "digest": args[2],
}).Debug("Blob copy") }).Debug("Blob copy")
err = rc.BlobCopy(ctx, rSrc, rTgt, types.Descriptor{Digest: d}) err = rc.BlobCopy(ctx, rSrc, rTgt, descriptor.Descriptor{Digest: d})
if err != nil { if err != nil {
return err return err
} }

View File

@ -8,7 +8,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -107,12 +107,12 @@ func completeArgPlatform(cmd *cobra.Command, args []string, toComplete string) (
func completeArgMediaTypeManifest(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { func completeArgMediaTypeManifest(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{ return []string{
types.MediaTypeDocker2Manifest, mediatype.Docker2Manifest,
types.MediaTypeDocker2ManifestList, mediatype.Docker2ManifestList,
types.MediaTypeOCI1Manifest, mediatype.OCI1Manifest,
types.MediaTypeOCI1ManifestList, mediatype.OCI1ManifestList,
types.MediaTypeDocker1Manifest, mediatype.Docker1Manifest,
types.MediaTypeDocker1ManifestSigned, mediatype.Docker1ManifestSigned,
}, cobra.ShellCompDirectiveNoFileComp }, cobra.ShellCompDirectiveNoFileComp
} }

View File

@ -24,6 +24,7 @@ import (
"github.com/regclient/regclient/pkg/template" "github.com/regclient/regclient/pkg/template"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/blob" "github.com/regclient/regclient/types/blob"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
@ -842,7 +843,7 @@ func (imageOpts *imageCmd) runImageCheckBase(cmd *cobra.Command, args []string)
if err == nil { if err == nil {
log.Info("base image matches") log.Info("base image matches")
return nil return nil
} else if errors.Is(err, types.ErrMismatch) { } else if errors.Is(err, errs.ErrMismatch) {
log.WithFields(logrus.Fields{ log.WithFields(logrus.Fields{
"err": err, "err": err,
}).Info("base image mismatch") }).Info("base image mismatch")
@ -1200,7 +1201,7 @@ func (imageOpts *imageCmd) runImageGetFile(cmd *cobra.Command, args []string) er
} }
th, rdr, err := btr.ReadFile(filename) th, rdr, err := btr.ReadFile(filename)
if err != nil { if err != nil {
if errors.Is(err, types.ErrFileNotFound) { if errors.Is(err, errs.ErrFileNotFound) {
if err := btr.Close(); err != nil { if err := btr.Close(); err != nil {
return err return err
} }
@ -1244,7 +1245,7 @@ func (imageOpts *imageCmd) runImageGetFile(cmd *cobra.Command, args []string) er
return nil return nil
} }
// all layers exhausted, not found or deleted // all layers exhausted, not found or deleted
return types.ErrNotFound return errs.ErrNotFound
} }
func (imageOpts *imageCmd) runImageImport(cmd *cobra.Command, args []string) error { func (imageOpts *imageCmd) runImageImport(cmd *cobra.Command, args []string) error {
@ -1294,7 +1295,7 @@ func (imageOpts *imageCmd) runImageInspect(cmd *cobra.Command, args []string) er
} }
mi, ok := m.(manifest.Imager) mi, ok := m.(manifest.Imager)
if !ok { if !ok {
return fmt.Errorf("manifest does not support image methods%.0w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest does not support image methods%.0w", errs.ErrUnsupportedMediaType)
} }
cd, err := mi.GetConfig() cd, err := mi.GetConfig()
if err != nil { if err != nil {

View File

@ -10,17 +10,19 @@ import (
"github.com/regclient/regclient" "github.com/regclient/regclient"
"github.com/regclient/regclient/pkg/template" "github.com/regclient/regclient/pkg/template"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
var indexKnownTypes = []string{ var indexKnownTypes = []string{
types.MediaTypeOCI1ManifestList, mediatype.OCI1ManifestList,
types.MediaTypeDocker2ManifestList, mediatype.Docker2ManifestList,
} }
type indexCmd struct { type indexCmd struct {
@ -116,7 +118,7 @@ regctl index delete registry.example.org/repo:v1 \
indexCreateCmd.Flags().StringVar(&indexOpts.format, "format", "", "Format output with go template syntax") indexCreateCmd.Flags().StringVar(&indexOpts.format, "format", "", "Format output with go template syntax")
indexCreateCmd.Flags().BoolVar(&indexOpts.incDigestTags, "digest-tags", false, "Include digest tags") indexCreateCmd.Flags().BoolVar(&indexOpts.incDigestTags, "digest-tags", false, "Include digest tags")
indexCreateCmd.Flags().BoolVar(&indexOpts.incReferrers, "referrers", false, "Include referrers") indexCreateCmd.Flags().BoolVar(&indexOpts.incReferrers, "referrers", false, "Include referrers")
indexCreateCmd.Flags().StringVarP(&indexOpts.mediaType, "media-type", "m", types.MediaTypeOCI1ManifestList, "Media-type for manifest list or OCI Index") indexCreateCmd.Flags().StringVarP(&indexOpts.mediaType, "media-type", "m", mediatype.OCI1ManifestList, "Media-type for manifest list or OCI Index")
indexCreateCmd.Flags().StringVar(&indexOpts.subject, "subject", "", "Specify a subject tag or digest (this manifest must already exist in the repo)") indexCreateCmd.Flags().StringVar(&indexOpts.subject, "subject", "", "Specify a subject tag or digest (this manifest must already exist in the repo)")
indexCreateCmd.Flags().StringArrayVar(&indexOpts.refs, "ref", []string{}, "References to include in new index") indexCreateCmd.Flags().StringArrayVar(&indexOpts.refs, "ref", []string{}, "References to include in new index")
indexCreateCmd.Flags().StringArrayVar(&indexOpts.platforms, "platform", []string{}, "Platforms to include from ref") indexCreateCmd.Flags().StringArrayVar(&indexOpts.platforms, "platform", []string{}, "Platforms to include from ref")
@ -153,7 +155,7 @@ func (indexOpts *indexCmd) runIndexAdd(cmd *cobra.Command, args []string) error
} }
mi, ok := m.(manifest.Indexer) mi, ok := m.(manifest.Indexer)
if !ok { if !ok {
return fmt.Errorf("current manifest is not an index/manifest list, \"%s\": %w", m.GetDescriptor().MediaType, types.ErrUnsupportedMediaType) return fmt.Errorf("current manifest is not an index/manifest list, \"%s\": %w", m.GetDescriptor().MediaType, errs.ErrUnsupportedMediaType)
} }
curDesc, err := mi.GetManifestList() curDesc, err := mi.GetManifestList()
if err != nil { if err != nil {
@ -199,8 +201,8 @@ func (indexOpts *indexCmd) runIndexCreate(cmd *cobra.Command, args []string) err
ctx := cmd.Context() ctx := cmd.Context()
// validate media type // validate media type
if indexOpts.mediaType != types.MediaTypeOCI1ManifestList && indexOpts.mediaType != types.MediaTypeDocker2ManifestList { if indexOpts.mediaType != mediatype.OCI1ManifestList && indexOpts.mediaType != mediatype.Docker2ManifestList {
return fmt.Errorf("unsupported manifest media type: %s%.0w", indexOpts.mediaType, types.ErrUnsupportedMediaType) return fmt.Errorf("unsupported manifest media type: %s%.0w", indexOpts.mediaType, errs.ErrUnsupportedMediaType)
} }
// parse ref // parse ref
@ -231,8 +233,8 @@ func (indexOpts *indexCmd) runIndexCreate(cmd *cobra.Command, args []string) err
} }
descList = indexDescListRmDup(descList) descList = indexDescListRmDup(descList)
var subj *types.Descriptor var subj *descriptor.Descriptor
if indexOpts.subject != "" && indexOpts.mediaType == types.MediaTypeOCI1ManifestList { if indexOpts.subject != "" && indexOpts.mediaType == mediatype.OCI1ManifestList {
var rSubj ref.Ref var rSubj ref.Ref
dig, err := digest.Parse(indexOpts.subject) dig, err := digest.Parse(indexOpts.subject)
if err == nil { if err == nil {
@ -252,10 +254,10 @@ func (indexOpts *indexCmd) runIndexCreate(cmd *cobra.Command, args []string) err
// build the index // build the index
mOpts := []manifest.Opts{} mOpts := []manifest.Opts{}
switch indexOpts.mediaType { switch indexOpts.mediaType {
case types.MediaTypeOCI1ManifestList: case mediatype.OCI1ManifestList:
m := v1.Index{ m := v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
ArtifactType: indexOpts.artifactType, ArtifactType: indexOpts.artifactType,
Manifests: descList, Manifests: descList,
Subject: subj, Subject: subj,
@ -264,7 +266,7 @@ func (indexOpts *indexCmd) runIndexCreate(cmd *cobra.Command, args []string) err
m.Annotations = annotations m.Annotations = annotations
} }
mOpts = append(mOpts, manifest.WithOrig(m)) mOpts = append(mOpts, manifest.WithOrig(m))
case types.MediaTypeDocker2ManifestList: case mediatype.Docker2ManifestList:
m := schema2.ManifestList{ m := schema2.ManifestList{
Versioned: schema2.ManifestListSchemaVersion, Versioned: schema2.ManifestListSchemaVersion,
Manifests: descList, Manifests: descList,
@ -321,7 +323,7 @@ func (indexOpts *indexCmd) runIndexDelete(cmd *cobra.Command, args []string) err
} }
mi, ok := m.(manifest.Indexer) mi, ok := m.(manifest.Indexer)
if !ok { if !ok {
return fmt.Errorf("current manifest is not an index/manifest list, \"%s\": %w", m.GetDescriptor().MediaType, types.ErrUnsupportedMediaType) return fmt.Errorf("current manifest is not an index/manifest list, \"%s\": %w", m.GetDescriptor().MediaType, errs.ErrUnsupportedMediaType)
} }
curDesc, err := mi.GetManifestList() curDesc, err := mi.GetManifestList()
if err != nil { if err != nil {
@ -387,7 +389,7 @@ func (indexOpts *indexCmd) runIndexDelete(cmd *cobra.Command, args []string) err
return template.Writer(cmd.OutOrStdout(), indexOpts.format, result) return template.Writer(cmd.OutOrStdout(), indexOpts.format, result)
} }
func (indexOpts *indexCmd) indexBuildDescList(ctx context.Context, rc *regclient.RegClient, r ref.Ref) ([]types.Descriptor, error) { func (indexOpts *indexCmd) indexBuildDescList(ctx context.Context, rc *regclient.RegClient, r ref.Ref) ([]descriptor.Descriptor, error) {
imgCopyOpts := []regclient.ImageOpts{ imgCopyOpts := []regclient.ImageOpts{
regclient.ImageWithChild(), regclient.ImageWithChild(),
} }
@ -467,7 +469,7 @@ func (indexOpts *indexCmd) indexBuildDescList(ctx context.Context, rc *regclient
} }
// parse each digest, pull manifest, get config, append to list of descriptors // parse each digest, pull manifest, get config, append to list of descriptors
descList := []types.Descriptor{} descList := []descriptor.Descriptor{}
for _, dig := range indexOpts.digests { for _, dig := range indexOpts.digests {
rDig := r.SetDigest(dig) rDig := r.SetDigest(dig)
mDig, err := rc.ManifestHead(ctx, rDig, regclient.WithManifestRequireDigest()) mDig, err := rc.ManifestHead(ctx, rDig, regclient.WithManifestRequireDigest())
@ -526,7 +528,7 @@ func indexGetPlatform(ctx context.Context, rc *regclient.RegClient, r ref.Ref, m
return nil, nil return nil, nil
} }
func indexDescListRmDup(dl []types.Descriptor) []types.Descriptor { func indexDescListRmDup(dl []descriptor.Descriptor) []descriptor.Descriptor {
i := 0 i := 0
for i < len(dl)-1 { for i < len(dl)-1 {
j := len(dl) - 1 j := len(dl) - 1

View File

@ -14,7 +14,7 @@ import (
"github.com/regclient/regclient" "github.com/regclient/regclient"
"github.com/regclient/regclient/internal/diff" "github.com/regclient/regclient/internal/diff"
"github.com/regclient/regclient/pkg/template" "github.com/regclient/regclient/pkg/template"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -374,7 +374,7 @@ func (manifestOpts *manifestCmd) runManifestPut(cmd *cobra.Command, args []strin
manifest.WithRaw(raw), manifest.WithRaw(raw),
} }
if manifestOpts.contentType != "" { if manifestOpts.contentType != "" {
opts = append(opts, manifest.WithDesc(types.Descriptor{ opts = append(opts, manifest.WithDesc(descriptor.Descriptor{
MediaType: manifestOpts.contentType, MediaType: manifestOpts.contentType,
})) }))
} }
@ -432,8 +432,8 @@ func getManifest(ctx context.Context, rc *regclient.RegClient, r ref.Ref, pStr s
return m, nil return m, nil
} }
func getPlatformDesc(ctx context.Context, rc *regclient.RegClient, m manifest.Manifest, pStr string) (*types.Descriptor, error) { func getPlatformDesc(ctx context.Context, rc *regclient.RegClient, m manifest.Manifest, pStr string) (*descriptor.Descriptor, error) {
var desc *types.Descriptor var desc *descriptor.Descriptor
var err error var err error
if !m.IsList() { if !m.IsList() {
return desc, fmt.Errorf("%w: manifest is not a list", ErrInvalidInput) return desc, fmt.Errorf("%w: manifest is not a list", ErrInvalidInput)

View File

@ -6,7 +6,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
func TestManifestHead(t *testing.T) { func TestManifestHead(t *testing.T) {
@ -25,12 +25,12 @@ func TestManifestHead(t *testing.T) {
{ {
name: "Invalid ref", name: "Invalid ref",
args: []string{"manifest", "head", "invalid*ref"}, args: []string{"manifest", "head", "invalid*ref"},
expectErr: types.ErrInvalidReference, expectErr: errs.ErrInvalidReference,
}, },
{ {
name: "Missing manifest", name: "Missing manifest",
args: []string{"manifest", "head", "ocidir://../../testdata/testrepo:missing"}, args: []string{"manifest", "head", "ocidir://../../testdata/testrepo:missing"},
expectErr: types.ErrNotFound, expectErr: errs.ErrNotFound,
}, },
{ {
name: "Digest", name: "Digest",

View File

@ -7,7 +7,7 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
func TestTagList(t *testing.T) { func TestTagList(t *testing.T) {
@ -26,7 +26,7 @@ func TestTagList(t *testing.T) {
{ {
name: "Invalid ref", name: "Invalid ref",
args: []string{"tag", "ls", "invalid*ref"}, args: []string{"tag", "ls", "invalid*ref"},
expectErr: types.ErrInvalidReference, expectErr: errs.ErrInvalidReference,
}, },
{ {
name: "Missing repo", name: "Missing repo",

View File

@ -10,16 +10,16 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/pkg/template" "github.com/regclient/regclient/pkg/template"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/mediatype"
) )
// delay checking for at least 5 minutes when rate limit is exceeded // delay checking for at least 5 minutes when rate limit is exceeded
var rateLimitRetryMin = time.Minute * 5 var rateLimitRetryMin = time.Minute * 5
var defaultMediaTypes = []string{ var defaultMediaTypes = []string{
types.MediaTypeDocker2Manifest, mediatype.Docker2Manifest,
types.MediaTypeDocker2ManifestList, mediatype.Docker2ManifestList,
types.MediaTypeOCI1Manifest, mediatype.OCI1Manifest,
types.MediaTypeOCI1ManifestList, mediatype.OCI1ManifestList,
} }
// Config is parsed configuration file for regsync // Config is parsed configuration file for regsync

View File

@ -12,7 +12,8 @@ import (
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/internal/throttle" "github.com/regclient/regclient/internal/throttle"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -98,12 +99,12 @@ func TestProcess(t *testing.T) {
t.Fatalf("failed to get platform ") t.Fatalf("failed to get platform ")
} }
d2AMD := desc2AMD.Digest d2AMD := desc2AMD.Digest
desc2SBOM, err := rc.ReferrerList(ctx, r2, scheme.WithReferrerMatchOpt(types.MatchOpt{ArtifactType: "application/example.sbom"})) desc2SBOM, err := rc.ReferrerList(ctx, r2, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{ArtifactType: "application/example.sbom"}))
if err != nil || len(desc2SBOM.Descriptors) == 0 { if err != nil || len(desc2SBOM.Descriptors) == 0 {
t.Fatalf("failed to get SBOM for v2: %v", err) t.Fatalf("failed to get SBOM for v2: %v", err)
} }
d2SBOM := desc2SBOM.Descriptors[0].Digest d2SBOM := desc2SBOM.Descriptors[0].Digest
desc2Sig, err := rc.ReferrerList(ctx, r2, scheme.WithReferrerMatchOpt(types.MatchOpt{ArtifactType: "application/example.signature"})) desc2Sig, err := rc.ReferrerList(ctx, r2, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{ArtifactType: "application/example.signature"}))
if err != nil || len(desc2Sig.Descriptors) == 0 { if err != nil || len(desc2Sig.Descriptors) == 0 {
t.Fatalf("failed to get signature for v2: %v", err) t.Fatalf("failed to get signature for v2: %v", err)
} }
@ -580,7 +581,7 @@ func TestProcess(t *testing.T) {
}, },
action: actionCopy, action: actionCopy,
desired: []string{}, desired: []string{},
expErr: types.ErrInvalidReference, expErr: errs.ErrInvalidReference,
}, },
{ {
name: "InvalidTargetImage", name: "InvalidTargetImage",
@ -591,7 +592,7 @@ func TestProcess(t *testing.T) {
}, },
action: actionCopy, action: actionCopy,
desired: []string{}, desired: []string{},
expErr: types.ErrInvalidReference, expErr: errs.ErrInvalidReference,
}, },
{ {
name: "InvalidSourceRepository", name: "InvalidSourceRepository",
@ -602,7 +603,7 @@ func TestProcess(t *testing.T) {
}, },
action: actionCopy, action: actionCopy,
desired: []string{}, desired: []string{},
expErr: types.ErrInvalidReference, expErr: errs.ErrInvalidReference,
}, },
{ {
name: "InvalidTargetRepository", name: "InvalidTargetRepository",
@ -613,7 +614,7 @@ func TestProcess(t *testing.T) {
}, },
action: actionCopy, action: actionCopy,
desired: []string{}, desired: []string{},
expErr: types.ErrInvalidReference, expErr: errs.ErrInvalidReference,
}, },
{ {
name: "InvalidType", name: "InvalidType",
@ -701,7 +702,7 @@ func TestProcessRef(t *testing.T) {
}{ }{
{ {
name: "empty", name: "empty",
expErr: types.ErrNotFound, expErr: errs.ErrNotFound,
}, },
{ {
name: "check v1", name: "check v1",

View File

@ -26,7 +26,8 @@ import (
"github.com/regclient/regclient/pkg/template" "github.com/regclient/regclient/pkg/template"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/scheme/reg" "github.com/regclient/regclient/scheme/reg"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -611,7 +612,7 @@ func (rootOpts *rootCmd) processImage(ctx context.Context, s ConfigSync, src, tg
// process a sync step // process a sync step
func (rootOpts *rootCmd) processRef(ctx context.Context, s ConfigSync, src, tgt ref.Ref, action actionType) error { func (rootOpts *rootCmd) processRef(ctx context.Context, s ConfigSync, src, tgt ref.Ref, action actionType) error {
mSrc, err := rc.ManifestHead(ctx, src, regclient.WithManifestRequireDigest()) mSrc, err := rc.ManifestHead(ctx, src, regclient.WithManifestRequireDigest())
if err != nil && errors.Is(err, types.ErrUnsupportedAPI) { if err != nil && errors.Is(err, errs.ErrUnsupportedAPI) {
mSrc, err = rc.ManifestGet(ctx, src) mSrc, err = rc.ManifestGet(ctx, src)
} }
if err != nil { if err != nil {
@ -831,10 +832,10 @@ func (rootOpts *rootCmd) processRef(ctx context.Context, s ConfigSync, src, tgt
for _, filter := range s.ReferrerFilters { for _, filter := range s.ReferrerFilters {
rOpts := []scheme.ReferrerOpts{} rOpts := []scheme.ReferrerOpts{}
if filter.ArtifactType != "" { if filter.ArtifactType != "" {
rOpts = append(rOpts, scheme.WithReferrerMatchOpt(types.MatchOpt{ArtifactType: filter.ArtifactType})) rOpts = append(rOpts, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{ArtifactType: filter.ArtifactType}))
} }
if filter.Annotations != nil { if filter.Annotations != nil {
rOpts = append(rOpts, scheme.WithReferrerMatchOpt(types.MatchOpt{Annotations: filter.Annotations})) rOpts = append(rOpts, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{Annotations: filter.Annotations}))
} }
opts = append(opts, regclient.ImageWithReferrers(rOpts...)) opts = append(opts, regclient.ImageWithReferrers(rOpts...))
} }

119
image.go
View File

@ -24,8 +24,11 @@ import (
"github.com/regclient/regclient/pkg/archive" "github.com/regclient/regclient/pkg/archive"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -46,8 +49,8 @@ type dockerTarManifest struct {
Config string Config string
RepoTags []string RepoTags []string
Layers []string Layers []string
Parent digest.Digest `json:",omitempty"` Parent digest.Digest `json:",omitempty"`
LayerSources map[digest.Digest]types.Descriptor `json:",omitempty"` LayerSources map[digest.Digest]descriptor.Descriptor `json:",omitempty"`
} }
type tarFileHandler func(header *tar.Header, trd *tarReadData) error type tarFileHandler func(header *tar.Header, trd *tarReadData) error
@ -222,7 +225,7 @@ func ImageWithReferrers(rOpts ...scheme.ReferrerOpts) ImageOpts {
} }
// ImageCheckBase returns nil if the base image is unchanged. // ImageCheckBase returns nil if the base image is unchanged.
// A base image mismatch returns an error that wraps types.ErrMismatch. // A base image mismatch returns an error that wraps errs.ErrMismatch.
func (rc *RegClient) ImageCheckBase(ctx context.Context, r ref.Ref, opts ...ImageOpts) error { func (rc *RegClient) ImageCheckBase(ctx context.Context, r ref.Ref, opts ...ImageOpts) error {
var opt imageOpt var opt imageOpt
for _, optFn := range opts { for _, optFn := range opts {
@ -239,7 +242,7 @@ func (rc *RegClient) ImageCheckBase(ctx context.Context, r ref.Ref, opts ...Imag
} }
ma, ok := m.(manifest.Annotator) ma, ok := m.(manifest.Annotator)
if !ok { if !ok {
return fmt.Errorf("image does not support annotations, base image must be provided%.0w", types.ErrMissingAnnotation) return fmt.Errorf("image does not support annotations, base image must be provided%.0w", errs.ErrMissingAnnotation)
} }
annot, err := ma.GetAnnotations() annot, err := ma.GetAnnotations()
if err != nil { if err != nil {
@ -248,7 +251,7 @@ func (rc *RegClient) ImageCheckBase(ctx context.Context, r ref.Ref, opts ...Imag
if baseName, ok := annot[types.AnnotationBaseImageName]; ok { if baseName, ok := annot[types.AnnotationBaseImageName]; ok {
opt.checkBaseRef = baseName opt.checkBaseRef = baseName
} else { } else {
return fmt.Errorf("image does not have a base annotation, base image must be provided%.0w", types.ErrMissingAnnotation) return fmt.Errorf("image does not have a base annotation, base image must be provided%.0w", errs.ErrMissingAnnotation)
} }
if baseDig, ok := annot[types.AnnotationBaseImageDigest]; ok { if baseDig, ok := annot[types.AnnotationBaseImageDigest]; ok {
opt.checkBaseDigest = baseDig opt.checkBaseDigest = baseDig
@ -283,7 +286,7 @@ func (rc *RegClient) ImageCheckBase(ctx context.Context, r ref.Ref, opts ...Imag
"expected": expectDig.String(), "expected": expectDig.String(),
}).Debug("base image digest changed") }).Debug("base image digest changed")
return fmt.Errorf("base digest changed, %s, expected %s, received %s%.0w", return fmt.Errorf("base digest changed, %s, expected %s, received %s%.0w",
baseR.CommonName(), expectDig.String(), baseMH.GetDescriptor().Digest.String(), types.ErrMismatch) baseR.CommonName(), expectDig.String(), baseMH.GetDescriptor().Digest.String(), errs.ErrMismatch)
} }
} }
@ -381,7 +384,7 @@ func (rc *RegClient) ImageCheckBase(ctx context.Context, r ref.Ref, opts ...Imag
"digest": baseLayers[i].Digest.String(), "digest": baseLayers[i].Digest.String(),
}).Debug("image layer changed") }).Debug("image layer changed")
return fmt.Errorf("base layer changed, %s[%d], expected %s, received %s%.0w", return fmt.Errorf("base layer changed, %s[%d], expected %s, received %s%.0w",
baseR.CommonName(), i, layers[i].Digest.String(), baseLayers[i].Digest.String(), types.ErrMismatch) baseR.CommonName(), i, layers[i].Digest.String(), baseLayers[i].Digest.String(), errs.ErrMismatch)
} }
} }
@ -423,7 +426,7 @@ func (rc *RegClient) ImageCheckBase(ctx context.Context, r ref.Ref, opts ...Imag
"history": baseConfOCI.History[i], "history": baseConfOCI.History[i],
}).Debug("image history changed") }).Debug("image history changed")
return fmt.Errorf("base history changed, %s[%d], expected %v, received %v%.0w", return fmt.Errorf("base history changed, %s[%d], expected %v, received %v%.0w",
baseR.CommonName(), i, confOCI.History[i], baseConfOCI.History[i], types.ErrMismatch) baseR.CommonName(), i, confOCI.History[i], baseConfOCI.History[i], errs.ErrMismatch)
} }
} }
@ -460,7 +463,7 @@ func (rc *RegClient) ImageCopy(ctx context.Context, refSrc ref.Ref, refTgt ref.R
defer tgtGCLocker.GCUnlock(refTgt) defer tgtGCLocker.GCUnlock(refTgt)
} }
// run the copy of manifests and blobs recursively // run the copy of manifests and blobs recursively
err = rc.imageCopyOpt(ctx, refSrc, refTgt, types.Descriptor{}, opt.child, []digest.Digest{}, &opt) err = rc.imageCopyOpt(ctx, refSrc, refTgt, descriptor.Descriptor{}, opt.child, []digest.Digest{}, &opt)
if err != nil { if err != nil {
return err return err
} }
@ -475,7 +478,7 @@ func (rc *RegClient) ImageCopy(ctx context.Context, refSrc ref.Ref, refTgt ref.R
} }
// imageCopyOpt is a thread safe copy of a manifest and nested content. // imageCopyOpt is a thread safe copy of a manifest and nested content.
func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d types.Descriptor, child bool, parents []digest.Digest, opt *imageOpt) (err error) { func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d descriptor.Descriptor, child bool, parents []digest.Digest, opt *imageOpt) (err error) {
var mSrc, mTgt manifest.Manifest var mSrc, mTgt manifest.Manifest
var sDig digest.Digest var sDig digest.Digest
seenCB := func(error) {} seenCB := func(error) {}
@ -595,14 +598,14 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
entrySrc := refSrc.SetDigest(dEntry.Digest.String()) entrySrc := refSrc.SetDigest(dEntry.Digest.String())
entryTgt := refTgt.SetDigest(dEntry.Digest.String()) entryTgt := refTgt.SetDigest(dEntry.Digest.String())
switch dEntry.MediaType { switch dEntry.MediaType {
case types.MediaTypeDocker1Manifest, types.MediaTypeDocker1ManifestSigned, case mediatype.Docker1Manifest, mediatype.Docker1ManifestSigned,
types.MediaTypeDocker2Manifest, types.MediaTypeDocker2ManifestList, mediatype.Docker2Manifest, mediatype.Docker2ManifestList,
types.MediaTypeOCI1Manifest, types.MediaTypeOCI1ManifestList: mediatype.OCI1Manifest, mediatype.OCI1ManifestList:
// known manifest media type // known manifest media type
err = rc.imageCopyOpt(ctx, entrySrc, entryTgt, dEntry, true, parentsNew, opt) err = rc.imageCopyOpt(ctx, entrySrc, entryTgt, dEntry, true, parentsNew, opt)
case types.MediaTypeDocker2ImageConfig, types.MediaTypeOCI1ImageConfig, case mediatype.Docker2ImageConfig, mediatype.OCI1ImageConfig,
types.MediaTypeDocker2LayerGzip, types.MediaTypeOCI1Layer, types.MediaTypeOCI1LayerGzip, mediatype.Docker2LayerGzip, mediatype.OCI1Layer, mediatype.OCI1LayerGzip,
types.MediaTypeBuildkitCacheConfig: mediatype.BuildkitCacheConfig:
// known blob media type // known blob media type
err = rc.imageCopyBlob(ctx, entrySrc, entryTgt, dEntry, opt, bOpt...) err = rc.imageCopyBlob(ctx, entrySrc, entryTgt, dEntry, opt, bOpt...)
default: default:
@ -626,7 +629,7 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
return err return err
} }
referrerTags = append(referrerTags, rl.Tags...) referrerTags = append(referrerTags, rl.Tags...)
descList := []types.Descriptor{} descList := []descriptor.Descriptor{}
if len(opt.referrerConfs) == 0 { if len(opt.referrerConfs) == 0 {
descList = rl.Descriptors descList = rl.Descriptors
} else { } else {
@ -648,7 +651,7 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
waitCount++ waitCount++
go func() { go func() {
err := rc.imageCopyOpt(ctx, referrerSrc, referrerTgt, rDesc, true, parentsNew, opt) err := rc.imageCopyOpt(ctx, referrerSrc, referrerTgt, rDesc, true, parentsNew, opt)
if errors.Is(err, types.ErrLoopDetected) { if errors.Is(err, errs.ErrLoopDetected) {
// if a loop is detected, push the referrers copy to the end // if a loop is detected, push the referrers copy to the end
opt.mu.Lock() opt.mu.Lock()
opt.finalFn = append(opt.finalFn, func(ctx context.Context) error { opt.finalFn = append(opt.finalFn, func(ctx context.Context) error {
@ -718,12 +721,12 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
tag := tag tag := tag
waitCount++ waitCount++
go func() { go func() {
err := rc.imageCopyOpt(ctx, refTagSrc, refTagTgt, types.Descriptor{}, false, parentsNew, opt) err := rc.imageCopyOpt(ctx, refTagSrc, refTagTgt, descriptor.Descriptor{}, false, parentsNew, opt)
if errors.Is(err, types.ErrLoopDetected) { if errors.Is(err, errs.ErrLoopDetected) {
// if a loop is detected, push the digest tag copy back to the end // if a loop is detected, push the digest tag copy back to the end
opt.mu.Lock() opt.mu.Lock()
opt.finalFn = append(opt.finalFn, func(ctx context.Context) error { opt.finalFn = append(opt.finalFn, func(ctx context.Context) error {
return rc.imageCopyOpt(ctx, refTagSrc, refTagTgt, types.Descriptor{}, false, []digest.Digest{}, opt) return rc.imageCopyOpt(ctx, refTagSrc, refTagTgt, descriptor.Descriptor{}, false, []digest.Digest{}, opt)
}) })
opt.mu.Unlock() opt.mu.Unlock()
waitCh <- nil waitCh <- nil
@ -781,7 +784,7 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
cd, err := mSrcImg.GetConfig() cd, err := mSrcImg.GetConfig()
if err != nil { if err != nil {
// docker schema v1 does not have a config object, ignore if it's missing // docker schema v1 does not have a config object, ignore if it's missing
if !errors.Is(err, types.ErrUnsupportedMediaType) { if !errors.Is(err, errs.ErrUnsupportedMediaType) {
rc.log.WithFields(logrus.Fields{ rc.log.WithFields(logrus.Fields{
"ref": refSrc.Reference, "ref": refSrc.Reference,
"err": err, "err": err,
@ -897,7 +900,7 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
return nil return nil
} }
func (rc *RegClient) imageCopyBlob(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d types.Descriptor, opt *imageOpt, bOpt ...BlobOpts) error { func (rc *RegClient) imageCopyBlob(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d descriptor.Descriptor, opt *imageOpt, bOpt ...BlobOpts) error {
seenCB, err := imageSeenOrWait(ctx, opt, "", d.Digest, []digest.Digest{}) seenCB, err := imageSeenOrWait(ctx, opt, "", d.Digest, []digest.Digest{})
if seenCB == nil { if seenCB == nil {
return err return err
@ -931,7 +934,7 @@ func imageSeenOrWait(ctx context.Context, opt *imageOpt, tag string, dig digest.
// look for loops in parents // look for loops in parents
for _, p := range parents { for _, p := range parents {
if key == tag+":"+p.String() { if key == tag+":"+p.String() {
return nil, types.ErrLoopDetected return nil, errs.ErrLoopDetected
} }
} }
// wait for copy to finish or context to cancel // wait for copy to finish or context to cancel
@ -971,7 +974,7 @@ func imageSeenOrWait(ctx context.Context, opt *imageOpt, tag string, dig digest.
// [OCI Layout]: https://github.com/opencontainers/image-spec/blob/master/image-layout.md // [OCI Layout]: https://github.com/opencontainers/image-spec/blob/master/image-layout.md
func (rc *RegClient) ImageExport(ctx context.Context, r ref.Ref, outStream io.Writer, opts ...ImageOpts) error { func (rc *RegClient) ImageExport(ctx context.Context, r ref.Ref, outStream io.Writer, opts ...ImageOpts) error {
if !r.IsSet() { if !r.IsSet() {
return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
var ociIndex v1.Index var ociIndex v1.Index
@ -1026,7 +1029,7 @@ func (rc *RegClient) ImageExport(ctx context.Context, r ref.Ref, outStream io.Wr
// generate/write an OCI index // generate/write an OCI index
ociIndex.Versioned = v1.IndexSchemaVersion ociIndex.Versioned = v1.IndexSchemaVersion
ociIndex.Manifests = []types.Descriptor{mDesc} // initialize with the descriptor to the manifest list ociIndex.Manifests = []descriptor.Descriptor{mDesc} // initialize with the descriptor to the manifest list
err = twd.tarWriteFileJSON(ociIndexFilename, ociIndex) err = twd.tarWriteFileJSON(ociIndexFilename, ociIndex)
if err != nil { if err != nil {
return err return err
@ -1049,7 +1052,7 @@ func (rc *RegClient) ImageExport(ctx context.Context, r ref.Ref, outStream io.Wr
RepoTags: []string{refTag.CommonName()}, RepoTags: []string{refTag.CommonName()},
Config: tarOCILayoutDescPath(conf), Config: tarOCILayoutDescPath(conf),
Layers: []string{}, Layers: []string{},
LayerSources: map[digest.Digest]types.Descriptor{}, LayerSources: map[digest.Digest]descriptor.Descriptor{},
} }
dl, err := mi.GetLayers() dl, err := mi.GetLayers()
if err != nil { if err != nil {
@ -1077,14 +1080,14 @@ func (rc *RegClient) ImageExport(ctx context.Context, r ref.Ref, outStream io.Wr
} }
// imageExportDescriptor pulls a manifest or blob, outputs to a tar file, and recursively processes any nested manifests or blobs // imageExportDescriptor pulls a manifest or blob, outputs to a tar file, and recursively processes any nested manifests or blobs
func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc types.Descriptor, twd *tarWriteData) error { func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc descriptor.Descriptor, twd *tarWriteData) error {
tarFilename := tarOCILayoutDescPath(desc) tarFilename := tarOCILayoutDescPath(desc)
if twd.files[tarFilename] { if twd.files[tarFilename] {
// blob has already been imported into tar, skip // blob has already been imported into tar, skip
return nil return nil
} }
switch desc.MediaType { switch desc.MediaType {
case types.MediaTypeDocker1Manifest, types.MediaTypeDocker1ManifestSigned, types.MediaTypeDocker2Manifest, types.MediaTypeOCI1Manifest: case mediatype.Docker1Manifest, mediatype.Docker1ManifestSigned, mediatype.Docker2Manifest, mediatype.OCI1Manifest:
// Handle single platform manifests // Handle single platform manifests
// retrieve manifest // retrieve manifest
m, err := rc.ManifestGet(ctx, r, WithManifestDesc(desc)) m, err := rc.ManifestGet(ctx, r, WithManifestDesc(desc))
@ -1093,7 +1096,7 @@ func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc
} }
mi, ok := m.(manifest.Imager) mi, ok := m.(manifest.Imager)
if !ok { if !ok {
return fmt.Errorf("manifest doesn't support image methods%.0w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest doesn't support image methods%.0w", errs.ErrUnsupportedMediaType)
} }
// write manifest body by digest // write manifest body by digest
mBody, err := m.RawBody() mBody, err := m.RawBody()
@ -1112,7 +1115,7 @@ func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc
// add config // add config
confD, err := mi.GetConfig() confD, err := mi.GetConfig()
// ignore unsupported media type errors // ignore unsupported media type errors
if err != nil && !errors.Is(err, types.ErrUnsupportedMediaType) { if err != nil && !errors.Is(err, errs.ErrUnsupportedMediaType) {
return err return err
} }
if err == nil { if err == nil {
@ -1125,7 +1128,7 @@ func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc
// loop over layers // loop over layers
layerDL, err := mi.GetLayers() layerDL, err := mi.GetLayers()
// ignore unsupported media type errors // ignore unsupported media type errors
if err != nil && !errors.Is(err, types.ErrUnsupportedMediaType) { if err != nil && !errors.Is(err, errs.ErrUnsupportedMediaType) {
return err return err
} }
if err == nil { if err == nil {
@ -1137,7 +1140,7 @@ func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc
} }
} }
case types.MediaTypeDocker2ManifestList, types.MediaTypeOCI1ManifestList: case mediatype.Docker2ManifestList, mediatype.OCI1ManifestList:
// handle OCI index and Docker manifest list // handle OCI index and Docker manifest list
// retrieve manifest // retrieve manifest
m, err := rc.ManifestGet(ctx, r, WithManifestDesc(desc)) m, err := rc.ManifestGet(ctx, r, WithManifestDesc(desc))
@ -1146,7 +1149,7 @@ func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc
} }
mi, ok := m.(manifest.Indexer) mi, ok := m.(manifest.Indexer)
if !ok { if !ok {
return fmt.Errorf("manifest doesn't support index methods%.0w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest doesn't support index methods%.0w", errs.ErrUnsupportedMediaType)
} }
// write manifest body by digest // write manifest body by digest
mBody, err := m.RawBody() mBody, err := m.RawBody()
@ -1200,7 +1203,7 @@ func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc
// ImageImport pushes an image from a tar file (ImageExport) to a registry. // ImageImport pushes an image from a tar file (ImageExport) to a registry.
func (rc *RegClient) ImageImport(ctx context.Context, r ref.Ref, rs io.ReadSeeker, opts ...ImageOpts) error { func (rc *RegClient) ImageImport(ctx context.Context, r ref.Ref, rs io.ReadSeeker, opts ...ImageOpts) error {
if !r.IsSetRepo() { if !r.IsSetRepo() {
return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
var opt imageOpt var opt imageOpt
for _, optFn := range opts { for _, optFn := range opts {
@ -1223,7 +1226,7 @@ func (rc *RegClient) ImageImport(ctx context.Context, r ref.Ref, rs io.ReadSeeke
// process tar file looking for oci-layout and index.json, load manifests/blobs on success // process tar file looking for oci-layout and index.json, load manifests/blobs on success
err := trd.tarReadAll(rs) err := trd.tarReadAll(rs)
if err != nil && errors.Is(err, types.ErrNotFound) && trd.dockerManifestFound { if err != nil && errors.Is(err, errs.ErrNotFound) && trd.dockerManifestFound {
// import failed but manifest.json found, fall back to manifest.json processing // import failed but manifest.json found, fall back to manifest.json processing
// add handlers for the docker manifest layers // add handlers for the docker manifest layers
rc.imageImportDockerAddLayerHandlers(ctx, r, trd) rc.imageImportDockerAddLayerHandlers(ctx, r, trd)
@ -1254,7 +1257,7 @@ func (rc *RegClient) ImageImport(ctx context.Context, r ref.Ref, rs io.ReadSeeke
return nil return nil
} }
func (rc *RegClient) imageImportBlob(ctx context.Context, r ref.Ref, desc types.Descriptor, trd *tarReadData) error { func (rc *RegClient) imageImportBlob(ctx context.Context, r ref.Ref, desc descriptor.Descriptor, trd *tarReadData) error {
// skip if blob already exists // skip if blob already exists
_, err := rc.BlobHead(ctx, r, desc) _, err := rc.BlobHead(ctx, r, desc)
if err == nil { if err == nil {
@ -1314,13 +1317,13 @@ func (rc *RegClient) imageImportDockerAddLayerHandlers(ctx context.Context, r re
// make a docker v2 manifest from first json array entry (can only tag one image) // make a docker v2 manifest from first json array entry (can only tag one image)
trd.dockerManifest.SchemaVersion = 2 trd.dockerManifest.SchemaVersion = 2
trd.dockerManifest.MediaType = types.MediaTypeDocker2Manifest trd.dockerManifest.MediaType = mediatype.Docker2Manifest
trd.dockerManifest.Layers = make([]types.Descriptor, len(trd.dockerManifestList[index].Layers)) trd.dockerManifest.Layers = make([]descriptor.Descriptor, len(trd.dockerManifestList[index].Layers))
// add handler for config // add handler for config
trd.handlers[filepath.Clean(trd.dockerManifestList[index].Config)] = func(header *tar.Header, trd *tarReadData) error { trd.handlers[filepath.Clean(trd.dockerManifestList[index].Config)] = func(header *tar.Header, trd *tarReadData) error {
// upload blob, digest is unknown // upload blob, digest is unknown
d, err := rc.BlobPut(ctx, r, types.Descriptor{Size: header.Size}, trd.tr) d, err := rc.BlobPut(ctx, r, descriptor.Descriptor{Size: header.Size}, trd.tr)
if err != nil { if err != nil {
return err return err
} }
@ -1328,7 +1331,7 @@ func (rc *RegClient) imageImportDockerAddLayerHandlers(ctx context.Context, r re
if od, ok := trd.dockerManifestList[index].LayerSources[d.Digest]; ok { if od, ok := trd.dockerManifestList[index].LayerSources[d.Digest]; ok {
trd.dockerManifest.Config = od trd.dockerManifest.Config = od
} else { } else {
d.MediaType = types.MediaTypeDocker2ImageConfig d.MediaType = mediatype.Docker2ImageConfig
trd.dockerManifest.Config = d trd.dockerManifest.Config = d
} }
return nil return nil
@ -1343,7 +1346,7 @@ func (rc *RegClient) imageImportDockerAddLayerHandlers(ctx context.Context, r re
return err return err
} }
// upload blob, digest and size is unknown // upload blob, digest and size is unknown
d, err := rc.BlobPut(ctx, r, types.Descriptor{}, gzipR) d, err := rc.BlobPut(ctx, r, descriptor.Descriptor{}, gzipR)
if err != nil { if err != nil {
return err return err
} }
@ -1351,7 +1354,7 @@ func (rc *RegClient) imageImportDockerAddLayerHandlers(ctx context.Context, r re
if od, ok := trd.dockerManifestList[index].LayerSources[d.Digest]; ok { if od, ok := trd.dockerManifestList[index].LayerSources[d.Digest]; ok {
trd.dockerManifest.Layers[i] = od trd.dockerManifest.Layers[i] = od
} else { } else {
d.MediaType = types.MediaTypeDocker2LayerGzip d.MediaType = mediatype.Docker2LayerGzip
trd.dockerManifest.Layers[i] = d trd.dockerManifest.Layers[i] = d
} }
return nil return nil
@ -1427,7 +1430,7 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
// cache the manifest to avoid needing to pull again later, this is used if index.json is a wrapper around some other manifest // cache the manifest to avoid needing to pull again later, this is used if index.json is a wrapper around some other manifest
trd.manifests[m.GetDescriptor().Digest] = m trd.manifests[m.GetDescriptor().Digest] = m
handleManifest := func(d types.Descriptor, child bool) { handleManifest := func(d descriptor.Descriptor, child bool) {
filename := tarOCILayoutDescPath(d) filename := tarOCILayoutDescPath(d)
if !trd.processed[filename] && trd.handlers[filename] == nil { if !trd.processed[filename] && trd.handlers[filename] == nil {
trd.handlers[filename] = func(header *tar.Header, trd *tarReadData) error { trd.handlers[filename] = func(header *tar.Header, trd *tarReadData) error {
@ -1436,18 +1439,18 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
return err return err
} }
switch d.MediaType { switch d.MediaType {
case types.MediaTypeDocker1Manifest, types.MediaTypeDocker1ManifestSigned, case mediatype.Docker1Manifest, mediatype.Docker1ManifestSigned,
types.MediaTypeDocker2Manifest, types.MediaTypeDocker2ManifestList, mediatype.Docker2Manifest, mediatype.Docker2ManifestList,
types.MediaTypeOCI1Manifest, types.MediaTypeOCI1ManifestList: mediatype.OCI1Manifest, mediatype.OCI1ManifestList:
// known manifest media types // known manifest media types
md, err := manifest.New(manifest.WithDesc(d), manifest.WithRaw(b)) md, err := manifest.New(manifest.WithDesc(d), manifest.WithRaw(b))
if err != nil { if err != nil {
return err return err
} }
return rc.imageImportOCIHandleManifest(ctx, r, md, trd, true, child) return rc.imageImportOCIHandleManifest(ctx, r, md, trd, true, child)
case types.MediaTypeDocker2ImageConfig, types.MediaTypeOCI1ImageConfig, case mediatype.Docker2ImageConfig, mediatype.OCI1ImageConfig,
types.MediaTypeDocker2LayerGzip, types.MediaTypeOCI1Layer, types.MediaTypeOCI1LayerGzip, mediatype.Docker2LayerGzip, mediatype.OCI1Layer, mediatype.OCI1LayerGzip,
types.MediaTypeBuildkitCacheConfig: mediatype.BuildkitCacheConfig:
// known blob media types // known blob media types
return rc.imageImportBlob(ctx, r, d, trd) return rc.imageImportBlob(ctx, r, d, trd)
default: default:
@ -1465,7 +1468,7 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
if !push { if !push {
mi, ok := m.(manifest.Indexer) mi, ok := m.(manifest.Indexer)
if !ok { if !ok {
return fmt.Errorf("manifest doesn't support image methods%.0w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest doesn't support image methods%.0w", errs.ErrUnsupportedMediaType)
} }
// for root index, add handler for matching reference (or only reference) // for root index, add handler for matching reference (or only reference)
dl, err := mi.GetManifestList() dl, err := mi.GetManifestList()
@ -1473,7 +1476,7 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
return err return err
} }
// locate the digest in the index // locate the digest in the index
var d types.Descriptor var d descriptor.Descriptor
if len(dl) == 1 { if len(dl) == 1 {
d = dl[0] d = dl[0]
} else if r.Digest != "" { } else if r.Digest != "" {
@ -1516,7 +1519,7 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
// for index/manifest lists, add handlers for each embedded manifest // for index/manifest lists, add handlers for each embedded manifest
mi, ok := m.(manifest.Indexer) mi, ok := m.(manifest.Indexer)
if !ok { if !ok {
return fmt.Errorf("manifest doesn't support index methods%.0w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest doesn't support index methods%.0w", errs.ErrUnsupportedMediaType)
} }
dl, err := mi.GetManifestList() dl, err := mi.GetManifestList()
if err != nil { if err != nil {
@ -1529,14 +1532,14 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
// else if a single image/manifest // else if a single image/manifest
mi, ok := m.(manifest.Imager) mi, ok := m.(manifest.Imager)
if !ok { if !ok {
return fmt.Errorf("manifest doesn't support image methods%.0w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest doesn't support image methods%.0w", errs.ErrUnsupportedMediaType)
} }
// add handler for the config descriptor if it's defined // add handler for the config descriptor if it's defined
cd, err := mi.GetConfig() cd, err := mi.GetConfig()
if err == nil { if err == nil {
filename := tarOCILayoutDescPath(cd) filename := tarOCILayoutDescPath(cd)
if !trd.processed[filename] && trd.handlers[filename] == nil { if !trd.processed[filename] && trd.handlers[filename] == nil {
func(cd types.Descriptor) { func(cd descriptor.Descriptor) {
trd.handlers[filename] = func(header *tar.Header, trd *tarReadData) error { trd.handlers[filename] = func(header *tar.Header, trd *tarReadData) error {
return rc.imageImportBlob(ctx, r, cd, trd) return rc.imageImportBlob(ctx, r, cd, trd)
} }
@ -1551,7 +1554,7 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
for _, d := range layers { for _, d := range layers {
filename := tarOCILayoutDescPath(d) filename := tarOCILayoutDescPath(d)
if !trd.processed[filename] && trd.handlers[filename] == nil { if !trd.processed[filename] && trd.handlers[filename] == nil {
func(d types.Descriptor) { func(d descriptor.Descriptor) {
trd.handlers[filename] = func(header *tar.Header, trd *tarReadData) error { trd.handlers[filename] = func(header *tar.Header, trd *tarReadData) error {
return rc.imageImportBlob(ctx, r, d, trd) return rc.imageImportBlob(ctx, r, d, trd)
} }
@ -1700,7 +1703,7 @@ func (trd *tarReadData) tarReadAll(rs io.ReadSeeker) error {
} }
// if entire file read without adding a new handler, fail // if entire file read without adding a new handler, fail
if !trd.handleAdded { if !trd.handleAdded {
return fmt.Errorf("unable to read all files from tar: %w", types.ErrNotFound) return fmt.Errorf("unable to read all files from tar: %w", errs.ErrNotFound)
} }
} }
} }
@ -1793,6 +1796,6 @@ func (td *tarWriteData) tarWriteFileJSON(filename string, data interface{}) erro
return nil return nil
} }
func tarOCILayoutDescPath(d types.Descriptor) string { func tarOCILayoutDescPath(d descriptor.Descriptor) string {
return filepath.Clean(fmt.Sprintf("blobs/%s/%s", d.Digest.Algorithm(), d.Digest.Encoded())) return filepath.Clean(fmt.Sprintf("blobs/%s/%s", d.Digest.Algorithm(), d.Digest.Encoded()))
} }

View File

@ -17,7 +17,7 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -72,17 +72,17 @@ func TestImageCheckBase(t *testing.T) {
{ {
name: "missing annotation", name: "missing annotation",
r: r1, r: r1,
expectErr: types.ErrMissingAnnotation, expectErr: errs.ErrMissingAnnotation,
}, },
{ {
name: "annotation v2", name: "annotation v2",
r: r2, r: r2,
expectErr: types.ErrMismatch, expectErr: errs.ErrMismatch,
}, },
{ {
name: "annotation v3", name: "annotation v3",
r: r3, r: r3,
expectErr: types.ErrMismatch, expectErr: errs.ErrMismatch,
}, },
{ {
name: "manual v2, b1", name: "manual v2, b1",
@ -93,13 +93,13 @@ func TestImageCheckBase(t *testing.T) {
name: "manual v2, b2", name: "manual v2, b2",
r: r2, r: r2,
opts: []ImageOpts{ImageWithCheckBaseRef(rb2.CommonName())}, opts: []ImageOpts{ImageWithCheckBaseRef(rb2.CommonName())},
expectErr: types.ErrMismatch, expectErr: errs.ErrMismatch,
}, },
{ {
name: "manual v2, b3", name: "manual v2, b3",
r: r2, r: r2,
opts: []ImageOpts{ImageWithCheckBaseRef(rb3.CommonName())}, opts: []ImageOpts{ImageWithCheckBaseRef(rb3.CommonName())},
expectErr: types.ErrMismatch, expectErr: errs.ErrMismatch,
}, },
{ {
name: "manual v3, b1", name: "manual v3, b1",
@ -203,7 +203,7 @@ func TestCopy(t *testing.T) {
name: "ocidir to read-only registry", name: "ocidir to read-only registry",
src: "ocidir://./testdata/testrepo:v1", src: "ocidir://./testdata/testrepo:v1",
tgt: tsROHost + "/dest-ocidir:v1", tgt: tsROHost + "/dest-ocidir:v1",
expectErr: types.ErrHTTPStatus, expectErr: errs.ErrHTTPStatus,
}, },
{ {
name: "ocidir to ocidir", name: "ocidir to ocidir",

View File

@ -16,7 +16,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
type charLU byte type charLU byte
@ -490,7 +490,7 @@ func (b *BasicHandler) ProcessChallenge(c Challenge) error {
func (b *BasicHandler) GenerateAuth() (string, error) { func (b *BasicHandler) GenerateAuth() (string, error) {
cred := b.credsFn(b.host) cred := b.credsFn(b.host)
if cred.User == "" || cred.Password == "" { if cred.User == "" || cred.Password == "" {
return "", fmt.Errorf("no credentials available: %w", types.ErrHTTPUnauthorized) return "", fmt.Errorf("no credentials available: %w", errs.ErrHTTPUnauthorized)
} }
auth := base64.StdEncoding.EncodeToString([]byte(cred.User + ":" + cred.Password)) auth := base64.StdEncoding.EncodeToString([]byte(cred.User + ":" + cred.Password))
return fmt.Sprintf("Basic %s", auth), nil return fmt.Sprintf("Basic %s", auth), nil
@ -608,14 +608,14 @@ func (b *BearerHandler) GenerateAuth() (string, error) {
if err := b.tryPost(); err == nil { if err := b.tryPost(); err == nil {
return fmt.Sprintf("Bearer %s", b.token.Token), nil return fmt.Sprintf("Bearer %s", b.token.Token), nil
} else if err != ErrUnauthorized { } else if err != ErrUnauthorized {
return "", fmt.Errorf("failed to request auth token (post): %w%.0w", err, types.ErrHTTPUnauthorized) return "", fmt.Errorf("failed to request auth token (post): %w%.0w", err, errs.ErrHTTPUnauthorized)
} }
// attempt a get (with basic auth if user/pass available) // attempt a get (with basic auth if user/pass available)
if err := b.tryGet(); err == nil { if err := b.tryGet(); err == nil {
return fmt.Sprintf("Bearer %s", b.token.Token), nil return fmt.Sprintf("Bearer %s", b.token.Token), nil
} else if err != ErrUnauthorized { } else if err != ErrUnauthorized {
return "", fmt.Errorf("failed to request auth token (get): %w%.0w", err, types.ErrHTTPUnauthorized) return "", fmt.Errorf("failed to request auth token (get): %w%.0w", err, errs.ErrHTTPUnauthorized)
} }
return "", ErrUnauthorized return "", ErrUnauthorized

View File

@ -1,24 +1,40 @@
package auth package auth
import ( import (
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
var ( var (
// ErrEmptyChallenge indicates an issue with the received challenge in the WWW-Authenticate header // ErrEmptyChallenge indicates an issue with the received challenge in the WWW-Authenticate header
ErrEmptyChallenge = types.ErrEmptyChallenge //
// Deprecated: replace with [errs.ErrEmptyChallenge].
ErrEmptyChallenge = errs.ErrEmptyChallenge
// ErrInvalidChallenge indicates an issue with the received challenge in the WWW-Authenticate header // ErrInvalidChallenge indicates an issue with the received challenge in the WWW-Authenticate header
ErrInvalidChallenge = types.ErrInvalidChallenge //
// Deprecated: replace with [errs.ErrInvalidChallenge].
ErrInvalidChallenge = errs.ErrInvalidChallenge
// ErrNoNewChallenge indicates a challenge update did not result in any change // ErrNoNewChallenge indicates a challenge update did not result in any change
ErrNoNewChallenge = types.ErrNoNewChallenge //
// Deprecated: replace with [errs.ErrNoNewChallenge].
ErrNoNewChallenge = errs.ErrNoNewChallenge
// ErrNotFound indicates no credentials found for basic auth // ErrNotFound indicates no credentials found for basic auth
ErrNotFound = types.ErrNotFound //
// Deprecated: replace with [errs.ErrNotFound].
ErrNotFound = errs.ErrNotFound
// ErrNotImplemented returned when method has not been implemented yet // ErrNotImplemented returned when method has not been implemented yet
ErrNotImplemented = types.ErrNotImplemented //
// Deprecated: replace with [errs.ErrNotImplemented].
ErrNotImplemented = errs.ErrNotImplemented
// ErrParseFailure indicates the WWW-Authenticate header could not be parsed // ErrParseFailure indicates the WWW-Authenticate header could not be parsed
ErrParseFailure = types.ErrParsingFailed //
// Deprecated: replace with [errs.ErrParseFailure].
ErrParseFailure = errs.ErrParsingFailed
// ErrUnauthorized request was not authorized // ErrUnauthorized request was not authorized
ErrUnauthorized = types.ErrHTTPUnauthorized //
// Deprecated: replace with [errs.ErrUnauthorized].
ErrUnauthorized = errs.ErrHTTPUnauthorized
// ErrUnsupported indicates the request was unsupported // ErrUnsupported indicates the request was unsupported
ErrUnsupported = types.ErrUnsupported //
// Deprecated: replace with [errs.ErrUnsupported].
ErrUnsupported = errs.ErrUnsupported
) )

View File

@ -10,7 +10,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
type Cache[k comparable, v any] struct { type Cache[k comparable, v any] struct {
@ -105,7 +105,7 @@ func (c *Cache[k, v]) Set(key k, val v) {
func (c *Cache[k, v]) Get(key k) (v, error) { func (c *Cache[k, v]) Get(key k) (v, error) {
if c == nil { if c == nil {
var val v var val v
return val, types.ErrNotFound return val, errs.ErrNotFound
} }
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
@ -119,7 +119,7 @@ func (c *Cache[k, v]) Get(key k) (v, error) {
} }
} }
var val v var val v
return val, types.ErrNotFound return val, errs.ErrNotFound
} }
func (c *Cache[k, v]) prune() { func (c *Cache[k, v]) prune() {

View File

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"strings" "strings"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
type Links []Link type Links []Link
@ -75,7 +75,7 @@ func Parse(headers []string) (Links, error) {
// noop // noop
} else { } else {
// unknown character // unknown character
return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, types.ErrParsingFailed) return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, errs.ErrParsingFailed)
} }
case "uri": case "uri":
// parse tokens until space or comma // parse tokens until space or comma
@ -90,7 +90,7 @@ func Parse(headers []string) (Links, error) {
endLink() endLink()
} else { } else {
// unknown character // unknown character
return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, types.ErrParsingFailed) return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, errs.ErrParsingFailed)
} }
case "uriQuoted": case "uriQuoted":
// parse tokens until quote // parse tokens until quote
@ -109,7 +109,7 @@ func Parse(headers []string) (Links, error) {
// noop // noop
} else { } else {
// unknown character // unknown character
return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, types.ErrParsingFailed) return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, errs.ErrParsingFailed)
} }
case "parmName": case "parmName":
if len(pnb) > 0 && b == '=' { if len(pnb) > 0 && b == '=' {
@ -122,14 +122,14 @@ func Parse(headers []string) (Links, error) {
// noop // noop
} else { } else {
// unknown character // unknown character
return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, types.ErrParsingFailed) return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, errs.ErrParsingFailed)
} }
case "parmNameStar": case "parmNameStar":
if b == '=' { if b == '=' {
state = "parmValue" state = "parmValue"
} else { } else {
// unknown character // unknown character
return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, types.ErrParsingFailed) return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, errs.ErrParsingFailed)
} }
case "parmValue": case "parmValue":
if len(pvb) == 0 { if len(pvb) == 0 {
@ -139,7 +139,7 @@ func Parse(headers []string) (Links, error) {
state = "parmValueQuoted" state = "parmValueQuoted"
} else { } else {
// unknown character // unknown character
return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, types.ErrParsingFailed) return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, errs.ErrParsingFailed)
} }
} else { } else {
if charLUs[b]&isToken != 0 { if charLUs[b]&isToken != 0 {
@ -156,7 +156,7 @@ func Parse(headers []string) (Links, error) {
endLink() endLink()
} else { } else {
// unknown character // unknown character
return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, types.ErrParsingFailed) return nil, fmt.Errorf("unknown character in position %d of %s: %w", i, h, errs.ErrParsingFailed)
} }
} }
case "parmValueQuoted": case "parmValueQuoted":
@ -178,7 +178,7 @@ func Parse(headers []string) (Links, error) {
case "init": case "init":
// noop // noop
default: default:
return nil, fmt.Errorf("unexpected end state %s for header %s: %w", state, h, types.ErrParsingFailed) return nil, fmt.Errorf("unexpected end state %s for header %s: %w", state, h, errs.ErrParsingFailed)
} }
} }
@ -192,5 +192,5 @@ func (links Links) Get(parm, val string) (Link, error) {
return link, nil return link, nil
} }
} }
return Link{}, types.ErrNotFound return Link{}, errs.ErrNotFound
} }

View File

@ -4,7 +4,7 @@ import (
"errors" "errors"
"testing" "testing"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
func TestParseErr(t *testing.T) { func TestParseErr(t *testing.T) {
@ -122,7 +122,7 @@ func TestParseGet(t *testing.T) {
} }
link, err := links.Get(tt.parm, tt.val) link, err := links.Get(tt.parm, tt.val)
if tt.expectMissing { if tt.expectMissing {
if err == nil || !errors.Is(err, types.ErrNotFound) { if err == nil || !errors.Is(err, errs.ErrNotFound) {
t.Errorf("did not find missing error: %v, %v", link, err) t.Errorf("did not find missing error: %v, %v", link, err)
} }
return return

View File

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"io" "io"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
type LimitRead struct { type LimitRead struct {
@ -15,7 +15,7 @@ type LimitRead struct {
func (lr *LimitRead) Read(p []byte) (int, error) { func (lr *LimitRead) Read(p []byte) (int, error) {
if lr.Limit < 0 { if lr.Limit < 0 {
return 0, fmt.Errorf("read limit exceeded%.0w", types.ErrSizeLimitExceeded) return 0, fmt.Errorf("read limit exceeded%.0w", errs.ErrSizeLimitExceeded)
} }
if int64(len(p)) > lr.Limit+1 { if int64(len(p)) > lr.Limit+1 {
p = p[0 : lr.Limit+1] p = p[0 : lr.Limit+1]
@ -23,7 +23,7 @@ func (lr *LimitRead) Read(p []byte) (int, error) {
n, err := lr.Reader.Read(p) n, err := lr.Reader.Read(p)
lr.Limit -= int64(n) lr.Limit -= int64(n)
if lr.Limit < 0 { if lr.Limit < 0 {
return n, fmt.Errorf("read limit exceeded%.0w", types.ErrSizeLimitExceeded) return n, fmt.Errorf("read limit exceeded%.0w", errs.ErrSizeLimitExceeded)
} }
return n, err return n, err
} }

View File

@ -6,7 +6,7 @@ import (
"io" "io"
"testing" "testing"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
func TestLimitRead(t *testing.T) { func TestLimitRead(t *testing.T) {
@ -64,7 +64,7 @@ func TestLimitRead(t *testing.T) {
limit: 9, limit: 9,
src: byte10, src: byte10,
try: 10, try: 10,
expectErr: types.ErrSizeLimitExceeded, expectErr: errs.ErrSizeLimitExceeded,
}, },
} }
for _, tc := range tt { for _, tc := range tt {

View File

@ -31,7 +31,7 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/auth" "github.com/regclient/regclient/internal/auth"
"github.com/regclient/regclient/internal/throttle" "github.com/regclient/regclient/internal/throttle"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/warning" "github.com/regclient/regclient/types/warning"
) )
@ -266,7 +266,7 @@ func (resp *clientResp) Next() error {
if err != nil { if err != nil {
return err return err
} }
return types.ErrAllRequestsFailed return errs.ErrAllRequestsFailed
} }
if curHost >= len(hosts) { if curHost >= len(hosts) {
curHost = 0 curHost = 0
@ -295,14 +295,14 @@ func (resp *clientResp) Next() error {
var err error var err error
if !okAPI { if !okAPI {
dropHost = true dropHost = true
return fmt.Errorf("failed looking up api \"%s\" for host \"%s\": %w", h.config.API, h.config.Name, types.ErrAPINotFound) return fmt.Errorf("failed looking up api \"%s\" for host \"%s\": %w", h.config.API, h.config.Name, errs.ErrAPINotFound)
} }
if api.Method == "HEAD" && h.config.APIOpts != nil { if api.Method == "HEAD" && h.config.APIOpts != nil {
var disableHead bool var disableHead bool
disableHead, err = strconv.ParseBool(h.config.APIOpts["disableHead"]) disableHead, err = strconv.ParseBool(h.config.APIOpts["disableHead"])
if err == nil && disableHead { if err == nil && disableHead {
dropHost = true dropHost = true
return fmt.Errorf("head requests disabled for host \"%s\": %w", h.config.Name, types.ErrUnsupportedAPI) return fmt.Errorf("head requests disabled for host \"%s\": %w", h.config.Name, errs.ErrUnsupportedAPI)
} }
} }
@ -349,7 +349,7 @@ func (resp *clientResp) Next() error {
}).Warn("Sleeping for backoff") }).Warn("Sleeping for backoff")
select { select {
case <-resp.ctx.Done(): case <-resp.ctx.Done():
return types.ErrCanceled return errs.ErrCanceled
case <-time.After(sleepTime): case <-time.After(sleepTime):
} }
} }
@ -402,7 +402,7 @@ func (resp *clientResp) Next() error {
// add auth headers // add auth headers
err = hAuth.UpdateRequest(httpReq) err = hAuth.UpdateRequest(httpReq)
if err != nil { if err != nil {
if errors.Is(err, types.ErrHTTPUnauthorized) { if errors.Is(err, errs.ErrHTTPUnauthorized) {
dropHost = true dropHost = true
} else { } else {
backoff = true backoff = true
@ -453,7 +453,7 @@ func (resp *clientResp) Next() error {
err = fmt.Errorf("authentication handler unavailable") err = fmt.Errorf("authentication handler unavailable")
} }
if err != nil { if err != nil {
if errors.Is(err, types.ErrEmptyChallenge) || errors.Is(err, types.ErrNoNewChallenge) || errors.Is(err, types.ErrHTTPUnauthorized) { if errors.Is(err, errs.ErrEmptyChallenge) || errors.Is(err, errs.ErrNoNewChallenge) || errors.Is(err, errs.ErrHTTPUnauthorized) {
c.log.WithFields(logrus.Fields{ c.log.WithFields(logrus.Fields{
"URL": u.String(), "URL": u.String(),
"Err": err, "Err": err,
@ -535,7 +535,7 @@ func (resp *clientResp) Next() error {
} }
} }
// when error does not allow retries, abort with the last known err value // when error does not allow retries, abort with the last known err value
if err != nil && errors.Is(loopErr, types.ErrNotRetryable) { if err != nil && errors.Is(loopErr, errs.ErrNotRetryable) {
return err return err
} }
err = loopErr err = loopErr
@ -556,7 +556,7 @@ func (resp *clientResp) Read(b []byte) (int, error) {
return 0, io.EOF return 0, io.EOF
} }
if resp.resp == nil { if resp.resp == nil {
return 0, types.ErrNotFound return 0, errs.ErrNotFound
} }
// perform the read // perform the read
i, err := resp.reader.Read(b) i, err := resp.reader.Read(b)
@ -595,7 +595,7 @@ func (resp *clientResp) Read(b []byte) (int, error) {
}).Warn("Digest mismatch") }).Warn("Digest mismatch")
_ = resp.backoffSet() _ = resp.backoffSet()
resp.done = true resp.done = true
return i, fmt.Errorf("%w, expected %s, computed %s", types.ErrDigestMismatch, return i, fmt.Errorf("%w, expected %s, computed %s", errs.ErrDigestMismatch,
resp.digest.String(), resp.digester.Digest().String()) resp.digest.String(), resp.digester.Digest().String())
} }
} }
@ -612,7 +612,7 @@ func (resp *clientResp) Close() error {
resp.throttle = nil resp.throttle = nil
} }
if resp.resp == nil { if resp.resp == nil {
return types.ErrNotFound return errs.ErrNotFound
} }
if !resp.done { if !resp.done {
resp.backoffClear() resp.backoffClear()
@ -695,7 +695,7 @@ func (resp *clientResp) backoffSet() error {
ch.backoffUntil = time.Now().Add(sleepTime) ch.backoffUntil = time.Now().Add(sleepTime)
if ch.backoffCur >= c.retryLimit { if ch.backoffCur >= c.retryLimit {
return fmt.Errorf("%w: backoffs %d", types.ErrBackoffLimit, ch.backoffCur) return fmt.Errorf("%w: backoffs %d", errs.ErrBackoffLimit, ch.backoffCur)
} }
return nil return nil
@ -831,15 +831,15 @@ func (ch *clientHost) AuthCreds() func(h string) auth.Cred {
func HTTPError(statusCode int) error { func HTTPError(statusCode int) error {
switch statusCode { switch statusCode {
case 401: case 401:
return fmt.Errorf("%w [http %d]", types.ErrHTTPUnauthorized, statusCode) return fmt.Errorf("%w [http %d]", errs.ErrHTTPUnauthorized, statusCode)
case 403: case 403:
return fmt.Errorf("%w [http %d]", types.ErrHTTPUnauthorized, statusCode) return fmt.Errorf("%w [http %d]", errs.ErrHTTPUnauthorized, statusCode)
case 404: case 404:
return fmt.Errorf("%w [http %d]", types.ErrNotFound, statusCode) return fmt.Errorf("%w [http %d]", errs.ErrNotFound, statusCode)
case 429: case 429:
return fmt.Errorf("%w [http %d]", types.ErrHTTPRateLimit, statusCode) return fmt.Errorf("%w [http %d]", errs.ErrHTTPRateLimit, statusCode)
default: default:
return fmt.Errorf("%w: %s [http %d]", types.ErrHTTPStatus, http.StatusText(statusCode), statusCode) return fmt.Errorf("%w: %s [http %d]", errs.ErrHTTPStatus, http.StatusText(statusCode), statusCode)
} }
} }

View File

@ -19,7 +19,7 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/auth" "github.com/regclient/regclient/internal/auth"
"github.com/regclient/regclient/internal/reqresp" "github.com/regclient/regclient/internal/reqresp"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/warning" "github.com/regclient/regclient/types/warning"
) )
@ -893,7 +893,7 @@ func TestRegHttp(t *testing.T) {
body, err := io.ReadAll(resp) body, err := io.ReadAll(resp)
if err == nil { if err == nil {
t.Errorf("body read unexpectedly succeeded: %s", body) t.Errorf("body read unexpectedly succeeded: %s", body)
} else if !errors.Is(err, types.ErrDigestMismatch) { } else if !errors.Is(err, errs.ErrDigestMismatch) {
t.Errorf("unexpected error from digest mismatch: %v", err) t.Errorf("unexpected error from digest mismatch: %v", err)
} }
err = resp.Close() err = resp.Close()
@ -926,7 +926,7 @@ func TestRegHttp(t *testing.T) {
body, err := io.ReadAll(resp) body, err := io.ReadAll(resp)
if err == nil { if err == nil {
t.Errorf("body read unexpectedly succeeded: %s", body) t.Errorf("body read unexpectedly succeeded: %s", body)
} else if !errors.Is(err, types.ErrDigestMismatch) { } else if !errors.Is(err, errs.ErrDigestMismatch) {
t.Errorf("unexpected error from digest mismatch: %v", err) t.Errorf("unexpected error from digest mismatch: %v", err)
} }
err = resp.Close() err = resp.Close()
@ -1064,8 +1064,8 @@ func TestRegHttp(t *testing.T) {
if err == nil { if err == nil {
resp.Close() resp.Close()
t.Fatalf("unexpected success with bad password") t.Fatalf("unexpected success with bad password")
} else if !errors.Is(err, auth.ErrUnauthorized) { } else if !errors.Is(err, errs.ErrHTTPUnauthorized) {
t.Errorf("expected error %v, received error %v", auth.ErrUnauthorized, err) t.Errorf("expected error %v, received error %v", errs.ErrHTTPUnauthorized, err)
} }
}) })
t.Run("Bad auth", func(t *testing.T) { t.Run("Bad auth", func(t *testing.T) {
@ -1086,8 +1086,8 @@ func TestRegHttp(t *testing.T) {
if err == nil { if err == nil {
resp.Close() resp.Close()
t.Fatalf("unexpected success with bad auth header") t.Fatalf("unexpected success with bad auth header")
} else if !errors.Is(err, types.ErrParsingFailed) { } else if !errors.Is(err, errs.ErrParsingFailed) {
t.Errorf("expected error %v, received error %v", types.ErrParsingFailed, err) t.Errorf("expected error %v, received error %v", errs.ErrParsingFailed, err)
} }
}) })
t.Run("Missing auth", func(t *testing.T) { t.Run("Missing auth", func(t *testing.T) {
@ -1108,8 +1108,8 @@ func TestRegHttp(t *testing.T) {
if err == nil { if err == nil {
resp.Close() resp.Close()
t.Fatalf("unexpected success with missing auth header") t.Fatalf("unexpected success with missing auth header")
} else if !errors.Is(err, types.ErrEmptyChallenge) { } else if !errors.Is(err, errs.ErrEmptyChallenge) {
t.Errorf("expected error %v, received error %v", types.ErrEmptyChallenge, err) t.Errorf("expected error %v, received error %v", errs.ErrEmptyChallenge, err)
} }
}) })
// test repoauth // test repoauth
@ -1408,8 +1408,8 @@ func TestRegHttp(t *testing.T) {
if err == nil { if err == nil {
resp.Close() resp.Close()
t.Fatalf("unexpected success on get for missing manifest") t.Fatalf("unexpected success on get for missing manifest")
} else if !errors.Is(err, types.ErrNotFound) { } else if !errors.Is(err, errs.ErrNotFound) {
t.Errorf("unexpected error, expected %v, received %v", types.ErrNotFound, err) t.Errorf("unexpected error, expected %v, received %v", errs.ErrNotFound, err)
} }
}) })
t.Run("Forbidden", func(t *testing.T) { t.Run("Forbidden", func(t *testing.T) {
@ -1430,8 +1430,8 @@ func TestRegHttp(t *testing.T) {
if err == nil { if err == nil {
resp.Close() resp.Close()
t.Fatalf("unexpected success on get for missing manifest") t.Fatalf("unexpected success on get for missing manifest")
} else if !errors.Is(err, types.ErrHTTPUnauthorized) { } else if !errors.Is(err, errs.ErrHTTPUnauthorized) {
t.Errorf("unexpected error, expected %v, received %v", types.ErrHTTPUnauthorized, err) t.Errorf("unexpected error, expected %v, received %v", errs.ErrHTTPUnauthorized, err)
} }
}) })
t.Run("Bad GW", func(t *testing.T) { t.Run("Bad GW", func(t *testing.T) {
@ -1452,8 +1452,8 @@ func TestRegHttp(t *testing.T) {
if err == nil { if err == nil {
resp.Close() resp.Close()
t.Fatalf("unexpected success on get for missing manifest") t.Fatalf("unexpected success on get for missing manifest")
} else if !errors.Is(err, types.ErrHTTPStatus) { } else if !errors.Is(err, errs.ErrHTTPStatus) {
t.Errorf("unexpected error, expected %v, received %v", types.ErrHTTPStatus, err) t.Errorf("unexpected error, expected %v, received %v", errs.ErrHTTPStatus, err)
} }
}) })
t.Run("GW Timeout", func(t *testing.T) { t.Run("GW Timeout", func(t *testing.T) {
@ -1474,8 +1474,8 @@ func TestRegHttp(t *testing.T) {
if err == nil { if err == nil {
resp.Close() resp.Close()
t.Fatalf("unexpected success on get for missing manifest") t.Fatalf("unexpected success on get for missing manifest")
} else if !errors.Is(err, types.ErrHTTPStatus) { } else if !errors.Is(err, errs.ErrHTTPStatus) {
t.Errorf("unexpected error, expected %v, received %v", types.ErrHTTPStatus, err) t.Errorf("unexpected error, expected %v, received %v", errs.ErrHTTPStatus, err)
} }
}) })
t.Run("Server error", func(t *testing.T) { t.Run("Server error", func(t *testing.T) {
@ -1496,8 +1496,8 @@ func TestRegHttp(t *testing.T) {
if err == nil { if err == nil {
resp.Close() resp.Close()
t.Fatalf("unexpected success on get for missing manifest") t.Fatalf("unexpected success on get for missing manifest")
} else if !errors.Is(err, types.ErrHTTPStatus) { } else if !errors.Is(err, errs.ErrHTTPStatus) {
t.Errorf("unexpected error, expected %v, received %v", types.ErrHTTPStatus, err) t.Errorf("unexpected error, expected %v, received %v", errs.ErrHTTPStatus, err)
} }
}) })
// test context expire during retries // test context expire during retries

View File

@ -4,7 +4,7 @@ package strparse
import ( import (
"fmt" "fmt"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
// SplitCSKV splits a comma separated key=value list into a map // SplitCSKV splits a comma separated key=value list into a map
@ -85,7 +85,7 @@ func SplitCSKV(s string) (map[string]string, error) {
case "val", "key": case "val", "key":
procKV() procKV()
default: default:
return nil, fmt.Errorf("string parsing failed, end state: %s%.0w", state, types.ErrParsingFailed) return nil, fmt.Errorf("string parsing failed, end state: %s%.0w", state, errs.ErrParsingFailed)
} }
return result, nil return result, nil
} }

View File

@ -4,7 +4,7 @@ import (
"errors" "errors"
"testing" "testing"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
func TestSplitCSKV(t *testing.T) { func TestSplitCSKV(t *testing.T) {
@ -60,22 +60,22 @@ func TestSplitCSKV(t *testing.T) {
{ {
name: "errEscapeKey", name: "errEscapeKey",
str: "a\\", str: "a\\",
err: types.ErrParsingFailed, err: errs.ErrParsingFailed,
}, },
{ {
name: "errEscapeVal", name: "errEscapeVal",
str: "a=x\\", str: "a=x\\",
err: types.ErrParsingFailed, err: errs.ErrParsingFailed,
}, },
{ {
name: "errQuoteKey", name: "errQuoteKey",
str: "a\"", str: "a\"",
err: types.ErrParsingFailed, err: errs.ErrParsingFailed,
}, },
{ {
name: "errQuoteVal", name: "errQuoteVal",
str: "a=b\"", str: "a=b\"",
err: types.ErrParsingFailed, err: errs.ErrParsingFailed,
}, },
} }
for _, tc := range tt { for _, tc := range tt {

View File

@ -5,13 +5,14 @@ import (
"fmt" "fmt"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
type manifestOpt struct { type manifestOpt struct {
d types.Descriptor d descriptor.Descriptor
schemeOpts []scheme.ManifestOpts schemeOpts []scheme.ManifestOpts
requireDigest bool requireDigest bool
} }
@ -44,7 +45,7 @@ func WithManifestChild() ManifestOpts {
// WithManifestDesc includes the descriptor for ManifestGet. // WithManifestDesc includes the descriptor for ManifestGet.
// This is used to automatically extract a Data field if available. // This is used to automatically extract a Data field if available.
func WithManifestDesc(d types.Descriptor) ManifestOpts { func WithManifestDesc(d descriptor.Descriptor) ManifestOpts {
return func(opts *manifestOpt) { return func(opts *manifestOpt) {
opts.d = d opts.d = d
} }
@ -62,7 +63,7 @@ func WithManifestRequireDigest() ManifestOpts {
// All tags pointing to the manifest will be deleted. // All tags pointing to the manifest will be deleted.
func (rc *RegClient) ManifestDelete(ctx context.Context, r ref.Ref, opts ...ManifestOpts) error { func (rc *RegClient) ManifestDelete(ctx context.Context, r ref.Ref, opts ...ManifestOpts) error {
if !r.IsSet() { if !r.IsSet() {
return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
opt := manifestOpt{schemeOpts: []scheme.ManifestOpts{}} opt := manifestOpt{schemeOpts: []scheme.ManifestOpts{}}
for _, fn := range opts { for _, fn := range opts {
@ -78,7 +79,7 @@ func (rc *RegClient) ManifestDelete(ctx context.Context, r ref.Ref, opts ...Mani
// ManifestGet retrieves a manifest. // ManifestGet retrieves a manifest.
func (rc *RegClient) ManifestGet(ctx context.Context, r ref.Ref, opts ...ManifestOpts) (manifest.Manifest, error) { func (rc *RegClient) ManifestGet(ctx context.Context, r ref.Ref, opts ...ManifestOpts) (manifest.Manifest, error) {
if !r.IsSet() { if !r.IsSet() {
return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
opt := manifestOpt{schemeOpts: []scheme.ManifestOpts{}} opt := manifestOpt{schemeOpts: []scheme.ManifestOpts{}}
for _, fn := range opts { for _, fn := range opts {
@ -105,7 +106,7 @@ func (rc *RegClient) ManifestGet(ctx context.Context, r ref.Ref, opts ...Manifes
// ManifestHead queries for the existence of a manifest and returns metadata (digest, media-type, size). // ManifestHead queries for the existence of a manifest and returns metadata (digest, media-type, size).
func (rc *RegClient) ManifestHead(ctx context.Context, r ref.Ref, opts ...ManifestOpts) (manifest.Manifest, error) { func (rc *RegClient) ManifestHead(ctx context.Context, r ref.Ref, opts ...ManifestOpts) (manifest.Manifest, error) {
if !r.IsSet() { if !r.IsSet() {
return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
opt := manifestOpt{schemeOpts: []scheme.ManifestOpts{}} opt := manifestOpt{schemeOpts: []scheme.ManifestOpts{}}
for _, fn := range opts { for _, fn := range opts {
@ -129,7 +130,7 @@ func (rc *RegClient) ManifestHead(ctx context.Context, r ref.Ref, opts ...Manife
// Any descriptors referenced by the manifest typically need to be pushed first. // Any descriptors referenced by the manifest typically need to be pushed first.
func (rc *RegClient) ManifestPut(ctx context.Context, r ref.Ref, m manifest.Manifest, opts ...ManifestOpts) error { func (rc *RegClient) ManifestPut(ctx context.Context, r ref.Ref, m manifest.Manifest, opts ...ManifestOpts) error {
if !r.IsSetRepo() { if !r.IsSetRepo() {
return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
opt := manifestOpt{schemeOpts: []scheme.ManifestOpts{}} opt := manifestOpt{schemeOpts: []scheme.ManifestOpts{}}
for _, fn := range opts { for _, fn := range opts {

View File

@ -18,9 +18,11 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/reqresp" "github.com/regclient/regclient/internal/reqresp"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -35,14 +37,14 @@ func TestManifest(t *testing.T) {
digest1 := digest.FromString("example1") digest1 := digest.FromString("example1")
digest2 := digest.FromString("example2") digest2 := digest.FromString("example2")
m := schema2.Manifest{ m := schema2.Manifest{
Config: types.Descriptor{ Config: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2ImageConfig, MediaType: mediatype.Docker2ImageConfig,
Size: 8, Size: 8,
Digest: digest1, Digest: digest1,
}, },
Layers: []types.Descriptor{ Layers: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeDocker2LayerGzip, MediaType: mediatype.Docker2LayerGzip,
Size: 8, Size: 8,
Digest: digest2, Digest: digest2,
}, },
@ -67,7 +69,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -83,7 +85,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -99,7 +101,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
}, },
@ -114,7 +116,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -130,7 +132,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
}, },
}, },
}, },
@ -144,7 +146,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -223,7 +225,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestGet: %v", err) t.Fatalf("Failed running ManifestGet: %v", err)
} }
if manifest.GetMediaType(mGet) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mGet) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mGet)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mGet))
} }
if mGet.GetDescriptor().Digest != mDigest { if mGet.GetDescriptor().Digest != mDigest {
@ -239,7 +241,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestHead: %v", err) t.Fatalf("Failed running ManifestHead: %v", err)
} }
if manifest.GetMediaType(mHead) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mHead) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mHead)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mHead))
} }
if mHead.GetDescriptor().Digest != mDigest { if mHead.GetDescriptor().Digest != mDigest {
@ -255,7 +257,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestHead: %v", err) t.Fatalf("Failed running ManifestHead: %v", err)
} }
if manifest.GetMediaType(mHead) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mHead) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mHead)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mHead))
} }
if mHead.GetDescriptor().Digest != mDigest { if mHead.GetDescriptor().Digest != mDigest {
@ -270,8 +272,8 @@ func TestManifest(t *testing.T) {
mNohead, err := rc.ManifestHead(ctx, noheadRef) mNohead, err := rc.ManifestHead(ctx, noheadRef)
if err == nil { if err == nil {
t.Errorf("Unexpected successful head on \"no head\" registry: %v", mNohead) t.Errorf("Unexpected successful head on \"no head\" registry: %v", mNohead)
} else if !errors.Is(err, types.ErrUnsupportedAPI) { } else if !errors.Is(err, errs.ErrUnsupportedAPI) {
t.Errorf("Expected error, expected %v, received %v", types.ErrUnsupportedAPI, err) t.Errorf("Expected error, expected %v, received %v", errs.ErrUnsupportedAPI, err)
} }
}) })
t.Run("Get No Head", func(t *testing.T) { t.Run("Get No Head", func(t *testing.T) {
@ -283,7 +285,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestGet: %v", err) t.Fatalf("Failed running ManifestGet: %v", err)
} }
if manifest.GetMediaType(mNohead) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mNohead) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mNohead)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mNohead))
} }
if mNohead.GetDescriptor().Digest != mDigest { if mNohead.GetDescriptor().Digest != mDigest {
@ -306,8 +308,8 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed creating getRef: %v", err) t.Errorf("Failed creating getRef: %v", err)
} }
d := types.Descriptor{ d := descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(mLen), Size: int64(mLen),
Digest: mDigest, Digest: mDigest,
Data: mBody, Data: mBody,
@ -329,8 +331,8 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating getRef: %v", err) t.Fatalf("Failed creating getRef: %v", err)
} }
d := types.Descriptor{ d := descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(mLen), Size: int64(mLen),
Digest: mDigest, Digest: mDigest,
Data: []byte("invalid data"), Data: []byte("invalid data"),
@ -346,8 +348,8 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating missingRef: %v", err) t.Fatalf("Failed creating missingRef: %v", err)
} }
d := types.Descriptor{ d := descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(mLen), Size: int64(mLen),
Digest: mDigest, Digest: mDigest,
Data: []byte("invalid data"), Data: []byte("invalid data"),
@ -363,8 +365,8 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating missingRef: %v", err) t.Fatalf("Failed creating missingRef: %v", err)
} }
d := types.Descriptor{ d := descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(mLen), Size: int64(mLen),
Digest: missingDigest, Digest: missingDigest,
Data: []byte("invalid data"), Data: []byte("invalid data"),
@ -381,11 +383,11 @@ func TestManifest(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
_, err = rc.ManifestGet(ctx, r) _, err = rc.ManifestGet(ctx, r)
if !errors.Is(err, types.ErrInvalidReference) { if !errors.Is(err, errs.ErrInvalidReference) {
t.Errorf("ManifestGet did not respond with invalid ref: %v", err) t.Errorf("ManifestGet did not respond with invalid ref: %v", err)
} }
_, err = rc.ManifestHead(ctx, r) _, err = rc.ManifestHead(ctx, r)
if !errors.Is(err, types.ErrInvalidReference) { if !errors.Is(err, errs.ErrInvalidReference) {
t.Errorf("ManifestGet did not respond with invalid ref: %v", err) t.Errorf("ManifestGet did not respond with invalid ref: %v", err)
} }
}) })

View File

@ -9,7 +9,7 @@ import (
"time" "time"
"github.com/regclient/regclient" "github.com/regclient/regclient"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -97,7 +97,7 @@ func WithConfigTimestamp(optTime OptTime) Opts {
} }
// offset startHistory from base image history // offset startHistory from base image history
if !optTime.BaseRef.IsZero() { if !optTime.BaseRef.IsZero() {
var d types.Descriptor var d descriptor.Descriptor
for { for {
mOpts := []regclient.ManifestOpts{} mOpts := []regclient.ManifestOpts{}
if d.Digest != "" { if d.Digest != "" {

View File

@ -11,8 +11,9 @@ import (
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient" "github.com/regclient/regclient"
"github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/blob" "github.com/regclient/regclient/types/blob"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -39,8 +40,8 @@ type dagConfig struct {
type dagManifest struct { type dagManifest struct {
mod changes mod changes
top bool // indicates the top level manifest (needed for manifest lists) top bool // indicates the top level manifest (needed for manifest lists)
origDesc types.Descriptor origDesc descriptor.Descriptor
newDesc types.Descriptor newDesc descriptor.Descriptor
m manifest.Manifest m manifest.Manifest
config *dagOCIConfig config *dagOCIConfig
layers []*dagLayer layers []*dagLayer
@ -50,19 +51,19 @@ type dagManifest struct {
type dagOCIConfig struct { type dagOCIConfig struct {
modified bool modified bool
newDesc types.Descriptor newDesc descriptor.Descriptor
oc blob.OCIConfig oc blob.OCIConfig
} }
type dagLayer struct { type dagLayer struct {
mod changes mod changes
newDesc types.Descriptor newDesc descriptor.Descriptor
ucDigest digest.Digest // uncompressed descriptor ucDigest digest.Digest // uncompressed descriptor
desc types.Descriptor desc descriptor.Descriptor
rSrc ref.Ref rSrc ref.Ref
} }
func dagGet(ctx context.Context, rc *regclient.RegClient, rSrc ref.Ref, d types.Descriptor) (*dagManifest, error) { func dagGet(ctx context.Context, rc *regclient.RegClient, rSrc ref.Ref, d descriptor.Descriptor) (*dagManifest, error) {
var err error var err error
getOpts := []regclient.ManifestOpts{} getOpts := []regclient.ManifestOpts{}
if d.Digest != "" { if d.Digest != "" {
@ -92,7 +93,7 @@ func dagGet(ctx context.Context, rc *regclient.RegClient, rSrc ref.Ref, d types.
// pull config // pull config
doc := dagOCIConfig{} doc := dagOCIConfig{}
cd, err := mi.GetConfig() cd, err := mi.GetConfig()
if err != nil && !errors.Is(err, types.ErrUnsupportedMediaType) { if err != nil && !errors.Is(err, errs.ErrUnsupportedMediaType) {
return nil, err return nil, err
} else if err == nil && inListStr(cd.MediaType, mtWLConfig) { } else if err == nil && inListStr(cd.MediaType, mtWLConfig) {
oc, err := rc.BlobGetOCIConfig(ctx, rSrc, cd) oc, err := rc.BlobGetOCIConfig(ctx, rSrc, cd)

View File

@ -10,7 +10,9 @@ import (
"github.com/regclient/regclient" "github.com/regclient/regclient"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -180,7 +182,7 @@ func WithAnnotationPromoteCommon() Opts {
} }
mAnnot, ok := child.m.(manifest.Annotator) mAnnot, ok := child.m.(manifest.Annotator)
if !ok { if !ok {
return fmt.Errorf("manifest does not support annotations: %s%.0w", child.m.GetDescriptor().Digest.String(), types.ErrUnsupportedMediaType) return fmt.Errorf("manifest does not support annotations: %s%.0w", child.m.GetDescriptor().Digest.String(), errs.ErrUnsupportedMediaType)
} }
cur, err := mAnnot.GetAnnotations() cur, err := mAnnot.GetAnnotations()
if err != nil { if err != nil {
@ -289,7 +291,7 @@ func WithManifestToDocker() Opts {
changed := false changed := false
om := dm.m.GetOrig() om := dm.m.GetOrig()
if dm.m.IsList() { if dm.m.IsList() {
if dm.m.GetDescriptor().MediaType != types.MediaTypeDocker2ManifestList { if dm.m.GetDescriptor().MediaType != mediatype.Docker2ManifestList {
ociM, err := manifest.OCIIndexFromAny(om) ociM, err := manifest.OCIIndexFromAny(om)
if err != nil { if err != nil {
return err return err
@ -307,22 +309,22 @@ func WithManifestToDocker() Opts {
if err != nil { if err != nil {
return err return err
} }
if dm.m.GetDescriptor().MediaType != types.MediaTypeDocker2Manifest { if dm.m.GetDescriptor().MediaType != mediatype.Docker2Manifest {
changed = true changed = true
} }
if ociM.ArtifactType != "" { if ociM.ArtifactType != "" {
return fmt.Errorf("unable to convert artifactType to docker manifest, ref %s%.0w", rSrc.CommonName(), types.ErrUnsupportedMediaType) return fmt.Errorf("unable to convert artifactType to docker manifest, ref %s%.0w", rSrc.CommonName(), errs.ErrUnsupportedMediaType)
} }
if ociM.Config.MediaType == types.MediaTypeOCI1ImageConfig { if ociM.Config.MediaType == mediatype.OCI1ImageConfig {
ociM.Config.MediaType = types.MediaTypeDocker2ImageConfig ociM.Config.MediaType = mediatype.Docker2ImageConfig
changed = true changed = true
} }
for i, l := range ociM.Layers { for i, l := range ociM.Layers {
if l.MediaType == types.MediaTypeOCI1LayerGzip { if l.MediaType == mediatype.OCI1LayerGzip {
ociM.Layers[i].MediaType = types.MediaTypeDocker2LayerGzip ociM.Layers[i].MediaType = mediatype.Docker2LayerGzip
changed = true changed = true
} else if l.MediaType == types.MediaTypeOCI1ForeignLayerGzip { } else if l.MediaType == mediatype.OCI1ForeignLayerGzip {
ociM.Layers[i].MediaType = types.MediaTypeDocker2ForeignLayer ociM.Layers[i].MediaType = mediatype.Docker2ForeignLayer
changed = true changed = true
} }
} }
@ -365,7 +367,7 @@ func WithManifestToOCI() Opts {
if err != nil { if err != nil {
return err return err
} }
if dm.m.GetDescriptor().MediaType != types.MediaTypeOCI1ManifestList { if dm.m.GetDescriptor().MediaType != mediatype.OCI1ManifestList {
changed = true changed = true
om = ociM om = ociM
} }
@ -374,19 +376,19 @@ func WithManifestToOCI() Opts {
if err != nil { if err != nil {
return err return err
} }
if dm.m.GetDescriptor().MediaType != types.MediaTypeOCI1Manifest { if dm.m.GetDescriptor().MediaType != mediatype.OCI1Manifest {
changed = true changed = true
} }
if ociM.Config.MediaType == types.MediaTypeDocker2ImageConfig { if ociM.Config.MediaType == mediatype.Docker2ImageConfig {
ociM.Config.MediaType = types.MediaTypeOCI1ImageConfig ociM.Config.MediaType = mediatype.OCI1ImageConfig
changed = true changed = true
} }
for i, l := range ociM.Layers { for i, l := range ociM.Layers {
if l.MediaType == types.MediaTypeDocker2LayerGzip { if l.MediaType == mediatype.Docker2LayerGzip {
ociM.Layers[i].MediaType = types.MediaTypeOCI1LayerGzip ociM.Layers[i].MediaType = mediatype.OCI1LayerGzip
changed = true changed = true
} else if l.MediaType == types.MediaTypeDocker2ForeignLayer { } else if l.MediaType == mediatype.Docker2ForeignLayer {
ociM.Layers[i].MediaType = types.MediaTypeOCI1ForeignLayerGzip ociM.Layers[i].MediaType = mediatype.OCI1ForeignLayerGzip
changed = true changed = true
} }
} }
@ -514,14 +516,14 @@ func WithExternalURLsRm() Opts {
ociOM.Layers[i].URLs = []string{} ociOM.Layers[i].URLs = []string{}
mt := ociOM.Layers[i].MediaType mt := ociOM.Layers[i].MediaType
switch mt { switch mt {
case types.MediaTypeDocker2ForeignLayer: case mediatype.Docker2ForeignLayer:
mt = types.MediaTypeDocker2LayerGzip mt = mediatype.Docker2LayerGzip
case types.MediaTypeOCI1ForeignLayer: case mediatype.OCI1ForeignLayer:
mt = types.MediaTypeOCI1Layer mt = mediatype.OCI1Layer
case types.MediaTypeOCI1ForeignLayerGzip: case mediatype.OCI1ForeignLayerGzip:
mt = types.MediaTypeOCI1LayerGzip mt = mediatype.OCI1LayerGzip
case types.MediaTypeOCI1ForeignLayerZstd: case mediatype.OCI1ForeignLayerZstd:
mt = types.MediaTypeOCI1LayerZstd mt = mediatype.OCI1LayerZstd
} }
ociOM.Layers[i].MediaType = mt ociOM.Layers[i].MediaType = mt
changed = true changed = true
@ -572,11 +574,11 @@ func WithRebase() Opts {
} }
baseName, ok := annot[types.AnnotationBaseImageName] baseName, ok := annot[types.AnnotationBaseImageName]
if !ok { if !ok {
return fmt.Errorf("annotation for base image is missing (%s or %s)%.0w", types.AnnotationBaseImageName, types.AnnotationBaseImageDigest, types.ErrMissingAnnotation) return fmt.Errorf("annotation for base image is missing (%s or %s)%.0w", types.AnnotationBaseImageName, types.AnnotationBaseImageDigest, errs.ErrMissingAnnotation)
} }
baseDigest, ok := annot[types.AnnotationBaseImageDigest] baseDigest, ok := annot[types.AnnotationBaseImageDigest]
if !ok { if !ok {
return fmt.Errorf("annotation for base image is missing (%s or %s)%.0w", types.AnnotationBaseImageName, types.AnnotationBaseImageDigest, types.ErrMissingAnnotation) return fmt.Errorf("annotation for base image is missing (%s or %s)%.0w", types.AnnotationBaseImageName, types.AnnotationBaseImageDigest, errs.ErrMissingAnnotation)
} }
rNew, err := ref.New(baseName) rNew, err := ref.New(baseName)
if err != nil { if err != nil {
@ -712,15 +714,15 @@ func rebaseAddStep(dc *dagConfig, rBaseOld, rBaseNew ref.Ref) error {
// validate current base // validate current base
if len(layersOld) > len(layers) { if len(layersOld) > len(layers) {
return fmt.Errorf("base image has more layers than modified image%.0w", types.ErrMismatch) return fmt.Errorf("base image has more layers than modified image%.0w", errs.ErrMismatch)
} }
for i := range layersOld { for i := range layersOld {
if !layers[i].Same(layersOld[i]) { if !layers[i].Same(layersOld[i]) {
return fmt.Errorf("old base image does not match image layers, layer %d, base %v, image %v%.0w", i, layersOld[i], layers[i], types.ErrMismatch) return fmt.Errorf("old base image does not match image layers, layer %d, base %v, image %v%.0w", i, layersOld[i], layers[i], errs.ErrMismatch)
} }
} }
if len(confOCIOld.History) > len(confOCI.History) { if len(confOCIOld.History) > len(confOCI.History) {
return fmt.Errorf("base image has more history entries than modified image%.0w", types.ErrMismatch) return fmt.Errorf("base image has more history entries than modified image%.0w", errs.ErrMismatch)
} }
historyLayers := 0 historyLayers := 0
for i := range confOCIOld.History { for i := range confOCIOld.History {
@ -729,21 +731,21 @@ func rebaseAddStep(dc *dagConfig, rBaseOld, rBaseNew ref.Ref) error {
!confOCI.History[i].Created.Equal(*confOCIOld.History[i].Created) || !confOCI.History[i].Created.Equal(*confOCIOld.History[i].Created) ||
confOCI.History[i].CreatedBy != confOCIOld.History[i].CreatedBy || confOCI.History[i].CreatedBy != confOCIOld.History[i].CreatedBy ||
confOCI.History[i].EmptyLayer != confOCIOld.History[i].EmptyLayer { confOCI.History[i].EmptyLayer != confOCIOld.History[i].EmptyLayer {
return fmt.Errorf("old base image does not match image history, entry %d, base %v, image %v%.0w", i, confOCIOld.History[i], confOCI.History[i], types.ErrMismatch) return fmt.Errorf("old base image does not match image history, entry %d, base %v, image %v%.0w", i, confOCIOld.History[i], confOCI.History[i], errs.ErrMismatch)
} }
if !confOCIOld.History[i].EmptyLayer { if !confOCIOld.History[i].EmptyLayer {
historyLayers++ historyLayers++
} }
} }
if len(layersOld) != historyLayers || len(layersOld) != len(confOCIOld.RootFS.DiffIDs) { if len(layersOld) != historyLayers || len(layersOld) != len(confOCIOld.RootFS.DiffIDs) {
return fmt.Errorf("old base image layer count doesn't match history%.0w", types.ErrMismatch) return fmt.Errorf("old base image layer count doesn't match history%.0w", errs.ErrMismatch)
} }
if len(confOCIOld.RootFS.DiffIDs) > len(confOCI.RootFS.DiffIDs) { if len(confOCIOld.RootFS.DiffIDs) > len(confOCI.RootFS.DiffIDs) {
return fmt.Errorf("base image has more rootfs entries than modified image%.0w", types.ErrMismatch) return fmt.Errorf("base image has more rootfs entries than modified image%.0w", errs.ErrMismatch)
} }
for i := range confOCIOld.RootFS.DiffIDs { for i := range confOCIOld.RootFS.DiffIDs {
if confOCI.RootFS.DiffIDs[i] != confOCIOld.RootFS.DiffIDs[i] { if confOCI.RootFS.DiffIDs[i] != confOCIOld.RootFS.DiffIDs[i] {
return fmt.Errorf("old base image does not match image rootfs, entry %d, base %s, image %s%.0w", i, confOCIOld.RootFS.DiffIDs[i].String(), confOCI.RootFS.DiffIDs[i].String(), types.ErrMismatch) return fmt.Errorf("old base image does not match image rootfs, entry %d, base %s, image %s%.0w", i, confOCIOld.RootFS.DiffIDs[i].String(), confOCI.RootFS.DiffIDs[i].String(), errs.ErrMismatch)
} }
} }
// validate new base // validate new base

View File

@ -14,7 +14,8 @@ import (
"github.com/regclient/regclient" "github.com/regclient/regclient"
"github.com/regclient/regclient/pkg/archive" "github.com/regclient/regclient/pkg/archive"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -33,14 +34,14 @@ type OptTime struct {
var ( var (
// whitelist of tar media types // whitelist of tar media types
mtWLTar = []string{ mtWLTar = []string{
types.MediaTypeDocker2LayerGzip, mediatype.Docker2LayerGzip,
types.MediaTypeOCI1Layer, mediatype.OCI1Layer,
types.MediaTypeOCI1LayerGzip, mediatype.OCI1LayerGzip,
types.MediaTypeOCI1LayerZstd, mediatype.OCI1LayerZstd,
} }
mtWLConfig = []string{ mtWLConfig = []string{
types.MediaTypeDocker2ImageConfig, mediatype.Docker2ImageConfig,
types.MediaTypeOCI1ImageConfig, mediatype.OCI1ImageConfig,
} }
) )
@ -54,7 +55,7 @@ func Apply(ctx context.Context, rc *regclient.RegClient, rSrc ref.Ref, opts ...O
// do I need to store a DAG in memory with pointers back to parents and modified bool, so change to digest can be rippled up and modified objects are pushed? // do I need to store a DAG in memory with pointers back to parents and modified bool, so change to digest can be rippled up and modified objects are pushed?
// pull the image metadata into a DAG // pull the image metadata into a DAG
dm, err := dagGet(ctx, rc, rSrc, types.Descriptor{}) dm, err := dagGet(ctx, rc, rSrc, descriptor.Descriptor{})
if err != nil { if err != nil {
return rSrc, err return rSrc, err
} }
@ -143,7 +144,7 @@ func Apply(ctx context.Context, rc *regclient.RegClient, rSrc ref.Ref, opts ...O
var gw *gzip.Writer var gw *gzip.Writer
digRaw := digest.Canonical.Digester() // raw/compressed digest digRaw := digest.Canonical.Digester() // raw/compressed digest
digUC := digest.Canonical.Digester() // uncompressed digest digUC := digest.Canonical.Digester() // uncompressed digest
if dl.desc.MediaType == types.MediaTypeDocker2LayerGzip || dl.desc.MediaType == types.MediaTypeOCI1LayerGzip { if dl.desc.MediaType == mediatype.Docker2LayerGzip || dl.desc.MediaType == mediatype.OCI1LayerGzip {
cw := io.MultiWriter(fh, digRaw.Hash()) cw := io.MultiWriter(fh, digRaw.Hash())
gw = gzip.NewWriter(cw) gw = gzip.NewWriter(cw)
defer gw.Close() defer gw.Close()

View File

@ -18,8 +18,9 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/scheme/reg" "github.com/regclient/regclient/scheme/reg"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -739,7 +740,7 @@ func TestMod(t *testing.T) {
WithRebase(), WithRebase(),
}, },
ref: "ocidir://testrepo:v1", ref: "ocidir://testrepo:v1",
wantErr: types.ErrMissingAnnotation, wantErr: errs.ErrMissingAnnotation,
}, },
{ {
name: "Rebase refs", name: "Rebase refs",
@ -755,7 +756,7 @@ func TestMod(t *testing.T) {
WithRebaseRefs(rb2, rb3), WithRebaseRefs(rb2, rb3),
}, },
ref: "ocidir://testrepo:v3", ref: "ocidir://testrepo:v3",
wantErr: types.ErrMismatch, wantErr: errs.ErrMismatch,
}, },
{ {
name: "Rebase mismatch", name: "Rebase mismatch",
@ -763,7 +764,7 @@ func TestMod(t *testing.T) {
WithRebaseRefs(rb3, rb2), WithRebaseRefs(rb3, rb2),
}, },
ref: "ocidir://testrepo:v3", ref: "ocidir://testrepo:v3",
wantErr: types.ErrMismatch, wantErr: errs.ErrMismatch,
}, },
{ {
name: "Rebase and backdate", name: "Rebase and backdate",
@ -852,12 +853,12 @@ func TestMod(t *testing.T) {
func TestInList(t *testing.T) { func TestInList(t *testing.T) {
t.Parallel() t.Parallel()
t.Run("match", func(t *testing.T) { t.Run("match", func(t *testing.T) {
if !inListStr(types.MediaTypeDocker2LayerGzip, mtWLTar) { if !inListStr(mediatype.Docker2LayerGzip, mtWLTar) {
t.Errorf("did not find docker layer in tar whitelist") t.Errorf("did not find docker layer in tar whitelist")
} }
}) })
t.Run("mismatch", func(t *testing.T) { t.Run("mismatch", func(t *testing.T) {
if inListStr(types.MediaTypeDocker2LayerGzip, mtWLConfig) { if inListStr(mediatype.Docker2LayerGzip, mtWLConfig) {
t.Errorf("found docker layer in config whitelist") t.Errorf("found docker layer in config whitelist")
} }
}) })

View File

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
"github.com/regclient/regclient/types/referrer" "github.com/regclient/regclient/types/referrer"
) )
@ -14,7 +14,7 @@ import (
// The descriptor list should contain manifests that each have a subject field matching the requested ref. // The descriptor list should contain manifests that each have a subject field matching the requested ref.
func (rc *RegClient) ReferrerList(ctx context.Context, r ref.Ref, opts ...scheme.ReferrerOpts) (referrer.ReferrerList, error) { func (rc *RegClient) ReferrerList(ctx context.Context, r ref.Ref, opts ...scheme.ReferrerOpts) (referrer.ReferrerList, error) {
if !r.IsSet() { if !r.IsSet() {
return referrer.ReferrerList{}, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return referrer.ReferrerList{}, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
schemeAPI, err := rc.schemeGet(r.Scheme) schemeAPI, err := rc.schemeGet(r.Scheme)
if err != nil { if err != nil {

View File

@ -8,12 +8,32 @@ import (
topBlob "github.com/regclient/regclient/types/blob" topBlob "github.com/regclient/regclient/types/blob"
) )
type Blob = topBlob.Blob type (
type OCIConfig = topBlob.OCIConfig // Blob specifies a generic blob.
type Common = topBlob.Common //
type Reader = topBlob.Reader // Deprecated: replace with [blob.Blob].
Blob = topBlob.Blob
// OCIConfig is an interface for an OCI Config.
//
// Deprecated: replace with [blob.OCIConfig].
OCIConfig = topBlob.OCIConfig
// Common is an interface of common methods for blobs.
//
// Deprecated: replace with [blob.Common].
Common = topBlob.Common
// Reader is an interface for blob reader methods.
//
// Deprecated: replace with [blob.Reader].
Reader = topBlob.Reader
)
var ( var (
// NewOCIConfig
//
// Deprecated: replace with [blob.NewOCIConfig].
NewOCIConfig = topBlob.NewOCIConfig NewOCIConfig = topBlob.NewOCIConfig
NewReader = topBlob.NewReader // NewReader
//
// Deprecated: replace with [blob.NewReader].
NewReader = topBlob.NewReader
) )

View File

@ -9,14 +9,39 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
) )
type ConfigHost = config.Host type (
type TLSConf = config.TLSConf // ConfigHost defines settings for connecting to a registry.
//
// Deprecated: replace with [config.Host].
ConfigHost = config.Host
// TLSConf specifies whether TLS is enabled and verified for a host.
//
// Deprecated: replace with [config.TLSConf].
TLSConf = config.TLSConf
)
var ConfigHostNewName = config.HostNewName var (
// ConfigHostNewName
//
// Deprecated: replace with [config.ConfigHostNewName].
ConfigHostNewName = config.HostNewName
)
const ( const (
// TLSUndefined
//
// Deprecated: replace with [config.TLSUndefined].
TLSUndefined = config.TLSUndefined TLSUndefined = config.TLSUndefined
TLSEnabled = config.TLSEnabled // TLSEnabled
TLSInsecure = config.TLSInsecure //
TLSDisabled = config.TLSDisabled // Deprecated: replace with [config.TLSEnabled].
TLSEnabled = config.TLSEnabled
// TLSInsecure
//
// Deprecated: replace with [config.TLSInsecure].
TLSInsecure = config.TLSInsecure
// TLSDisabled
//
// Deprecated: replace with [config.TLSDisabled].
TLSDisabled = config.TLSDisabled
) )

View File

@ -8,18 +8,55 @@ import (
topConfig "github.com/regclient/regclient/config" topConfig "github.com/regclient/regclient/config"
) )
type TLSConf = topConfig.TLSConf type (
type Host = topConfig.Host // TLSConf defines the TLS enumerated values.
//
const ( // Deprecated: replace with [config.TLSConf].
TLSUndefined = topConfig.TLSUndefined TLSConf = topConfig.TLSConf
TLSEnabled = topConfig.TLSEnabled // Host defines a registry configuration.
TLSInsecure = topConfig.TLSInsecure //
TLSDisabled = topConfig.TLSDisabled // Deprecated: replace with [config.Host].
DockerRegistry = topConfig.DockerRegistry Host = topConfig.Host
DockerRegistryAuth = topConfig.DockerRegistryAuth
DockerRegistryDNS = topConfig.DockerRegistryDNS
) )
var HostNew = topConfig.HostNew const (
var HostNewName = topConfig.HostNewName // TLSUndefined
//
// Deprecated: replace with [config.TLSUndefined].
TLSUndefined = topConfig.TLSUndefined
// TLSEnabled
//
// Deprecated: replace with [config.TLSEnabled].
TLSEnabled = topConfig.TLSEnabled
// TLSInsecure
//
// Deprecated: replace with [config.TLSInsecure].
TLSInsecure = topConfig.TLSInsecure
// TLSDisabled
//
// Deprecated: replace with [config.TLSDisabled].
TLSDisabled = topConfig.TLSDisabled
// DockerRegistry
//
// Deprecated: replace with [config.DockerRegistry].
DockerRegistry = topConfig.DockerRegistry
// DockerRegistryAuth
//
// Deprecated: replace with [config.DockerRegistryAuth].
DockerRegistryAuth = topConfig.DockerRegistryAuth
// DockerRegistryDNS
//
// Deprecated: replace with [config.DockerRegistryDNS].
DockerRegistryDNS = topConfig.DockerRegistryDNS
)
var (
// HostNew
//
// Deprecated: replace with [config.HostNew].
HostNew = topConfig.HostNew
// HostNewName
//
// Deprecated: replace with [config.HostNewName].
HostNewName = topConfig.HostNewName
)

View File

@ -6,27 +6,81 @@
package regclient package regclient
import ( import (
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
var ( var (
ErrAPINotFound = types.ErrAPINotFound // ErrAPINotFound
ErrCanceled = types.ErrCanceled //
// Deprecated: replace with [errs.ErrAPINotFound].
ErrAPINotFound = errs.ErrAPINotFound
// ErrCanceled
//
// Deprecated: replace with [errs.ErrCanceled].
ErrCanceled = errs.ErrCanceled
//lint:ignore ST1003 exported field cannot be changed for legacy reasons //lint:ignore ST1003 exported field cannot be changed for legacy reasons
ErrHttpStatus = types.ErrHTTPStatus // ErrHttpStatus
ErrMissingDigest = types.ErrMissingDigest //
ErrMissingLocation = types.ErrMissingLocation // Deprecated: replace with [errs.ErrHttpStatus].
ErrMissingName = types.ErrMissingName ErrHttpStatus = errs.ErrHTTPStatus
ErrMissingTag = types.ErrMissingTag // ErrMissingDigest
ErrMissingTagOrDigest = types.ErrMissingTagOrDigest //
ErrMountReturnedLocation = types.ErrMountReturnedLocation // Deprecated: replace with [errs.ErrMissingDigest].
ErrNotFound = types.ErrNotFound ErrMissingDigest = errs.ErrMissingDigest
ErrNotImplemented = types.ErrNotImplemented // ErrMissingLocation
ErrParsingFailed = types.ErrParsingFailed //
ErrRateLimit = types.ErrHTTPRateLimit // Deprecated: replace with [errs.ErrMissingLocation].
ErrUnavailable = types.ErrUnavailable ErrMissingLocation = errs.ErrMissingLocation
ErrUnauthorized = types.ErrHTTPUnauthorized // ErrMissingName
ErrUnsupportedAPI = types.ErrUnsupportedAPI //
ErrUnsupportedConfigVersion = types.ErrUnsupportedConfigVersion // Deprecated: replace with [errs.ErrMissingName].
ErrUnsupportedMediaType = types.ErrUnsupportedMediaType ErrMissingName = errs.ErrMissingName
// ErrMissingTag
//
// Deprecated: replace with [errs.ErrMissingTag].
ErrMissingTag = errs.ErrMissingTag
// ErrMissingTagOrDigest
//
// Deprecated: replace with [errs.ErrMissingTagOrDigest].
ErrMissingTagOrDigest = errs.ErrMissingTagOrDigest
// ErrMountReturnedLocation
//
// Deprecated: replace with [errs.ErrMountReturnedLocation].
ErrMountReturnedLocation = errs.ErrMountReturnedLocation
// ErrNotFound
//
// Deprecated: replace with [errs.ErrNotFound].
ErrNotFound = errs.ErrNotFound
// ErrNotImplemented
//
// Deprecated: replace with [errs.ErrNotImplemented].
ErrNotImplemented = errs.ErrNotImplemented
// ErrParsingFailed
//
// Deprecated: replace with [errs.ErrParsingFailed].
ErrParsingFailed = errs.ErrParsingFailed
// ErrRateLimit
//
// Deprecated: replace with [errs.ErrRateLimit].
ErrRateLimit = errs.ErrHTTPRateLimit
// ErrUnavailable
//
// Deprecated: replace with [errs.ErrUnavailable].
ErrUnavailable = errs.ErrUnavailable
// ErrUnauthorized
//
// Deprecated: replace with [errs.ErrUnauthorized].
ErrUnauthorized = errs.ErrHTTPUnauthorized
// ErrUnsupportedAPI
//
// Deprecated: replace with [errs.ErrUnsupportedAPI].
ErrUnsupportedAPI = errs.ErrUnsupportedAPI
// ErrUnsupportedConfigVersion
//
// Deprecated: replace with [errs.ErrUnsupportedConfigVersion].
ErrUnsupportedConfigVersion = errs.ErrUnsupportedConfigVersion
// ErrUnsupportedMediaType
//
// Deprecated: replace with [errs.ErrUnsupportedMediaType].
ErrUnsupportedMediaType = errs.ErrUnsupportedMediaType
) )

View File

@ -8,34 +8,93 @@ import (
"net/http" "net/http"
topTypes "github.com/regclient/regclient/types" topTypes "github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/errs"
topManifest "github.com/regclient/regclient/types/manifest" topManifest "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
const ( const (
MediaTypeDocker1Manifest = topTypes.MediaTypeDocker1Manifest // MediaTypeDocker1Manifest
MediaTypeDocker1ManifestSigned = topTypes.MediaTypeDocker1ManifestSigned //
MediaTypeDocker2Manifest = topTypes.MediaTypeDocker2Manifest // Deprecated: replace with [mediatype.Docker1Manifest].
MediaTypeDocker2ManifestList = topTypes.MediaTypeDocker2ManifestList MediaTypeDocker1Manifest = mediatype.Docker1Manifest
MediaTypeDocker2ImageConfig = topTypes.MediaTypeDocker2ImageConfig // MediaTypeDocker1ManifestSigned
MediaTypeOCI1Manifest = topTypes.MediaTypeOCI1Manifest //
MediaTypeOCI1ManifestList = topTypes.MediaTypeOCI1ManifestList // Deprecated: replace with [mediatype.Docker1ManifestSigned].
MediaTypeOCI1ImageConfig = topTypes.MediaTypeOCI1ImageConfig MediaTypeDocker1ManifestSigned = mediatype.Docker1ManifestSigned
MediaTypeDocker2Layer = topTypes.MediaTypeDocker2LayerGzip // MediaTypeDocker2Manifest
MediaTypeOCI1Layer = topTypes.MediaTypeOCI1Layer //
MediaTypeOCI1LayerGzip = topTypes.MediaTypeOCI1LayerGzip // Deprecated: replace with [mediatype.Docker2Manifest].
MediaTypeBuildkitCacheConfig = topTypes.MediaTypeBuildkitCacheConfig MediaTypeDocker2Manifest = mediatype.Docker2Manifest
// MediaTypeDocker2ManifestList
//
// Deprecated: replace with [mediatype.Docker2ManifestList].
MediaTypeDocker2ManifestList = mediatype.Docker2ManifestList
// MediaTypeDocker2ImageConfig
//
// Deprecated: replace with [mediatype.Docker2ImageConfig].
MediaTypeDocker2ImageConfig = mediatype.Docker2ImageConfig
// MediaTypeOCI1Manifest
//
// Deprecated: replace with [mediatype.OCI1Manifest].
MediaTypeOCI1Manifest = mediatype.OCI1Manifest
// MediaTypeOCI1ManifestList
//
// Deprecated: replace with [mediatype.OCI1ManifestList].
MediaTypeOCI1ManifestList = mediatype.OCI1ManifestList
// MediaTypeOCI1ImageConfig
//
// Deprecated: replace with [mediatype.OCI1ImageConfig].
MediaTypeOCI1ImageConfig = mediatype.OCI1ImageConfig
// MediaTypeDocker2Layer
//
// Deprecated: replace with [mediatype.Docker2Layer].
MediaTypeDocker2Layer = mediatype.Docker2LayerGzip
// MediaTypeOCI1Layer
//
// Deprecated: replace with [mediatype.OCI1Layer].
MediaTypeOCI1Layer = mediatype.OCI1Layer
// MediaTypeOCI1LayerGzip
//
// Deprecated: replace with [mediatype.OCI1LayerGzip].
MediaTypeOCI1LayerGzip = mediatype.OCI1LayerGzip
// MediaTypeBuildkitCacheConfig
//
// Deprecated: replace with [mediatype.BuildkitCacheConfig].
MediaTypeBuildkitCacheConfig = mediatype.BuildkitCacheConfig
) )
type Manifest = topManifest.Manifest type (
// Manifest interface is implemented by all supported manifests but
// many calls are only supported by certain underlying media types.
//
// Deprecated: replace with [manifest.Manifest].
Manifest = topManifest.Manifest
)
var ( var (
ErrNotFound = topTypes.ErrNotFound // ErrNotFound
ErrNotImplemented = topTypes.ErrNotImplemented //
ErrUnavailable = topTypes.ErrUnavailable // Deprecated: replace with [errs.ErrNotFound].
ErrUnsupportedMediaType = topTypes.ErrUnsupported ErrNotFound = errs.ErrNotFound
// ErrNotImplemented
//
// Deprecated: replace with [errs.ErrNotImplemented].
ErrNotImplemented = errs.ErrNotImplemented
// ErrUnavailable
//
// Deprecated: replace with [errs.ErrUnavailable].
ErrUnavailable = errs.ErrUnavailable
// ErrUnsupportedMediaType
//
// Deprecated: replace with [errs.ErrUnsupportedMediaType].
ErrUnsupportedMediaType = errs.ErrUnsupported
) )
// New creates a new manifest.
//
// Deprecated: replace with [manifest.New].
func New(mediaType string, raw []byte, r ref.Ref, header http.Header) (Manifest, error) { func New(mediaType string, raw []byte, r ref.Ref, header http.Header) (Manifest, error) {
return topManifest.New( return topManifest.New(
topManifest.WithDesc(topTypes.Descriptor{ topManifest.WithDesc(topTypes.Descriptor{
@ -47,6 +106,9 @@ func New(mediaType string, raw []byte, r ref.Ref, header http.Header) (Manifest,
) )
} }
// FromDescriptor creates a manifest from a descriptor.
//
// Deprecated: replace with [manifest.New].
func FromDescriptor(desc topTypes.Descriptor, mBytes []byte) (Manifest, error) { func FromDescriptor(desc topTypes.Descriptor, mBytes []byte) (Manifest, error) {
return topManifest.New( return topManifest.New(
topManifest.WithDesc(desc), topManifest.WithDesc(desc),
@ -54,6 +116,9 @@ func FromDescriptor(desc topTypes.Descriptor, mBytes []byte) (Manifest, error) {
) )
} }
// FromOrig creates a manifest from an underlying manifest struct.
//
// Deprecated: replace with [manifest.New].
func FromOrig(orig interface{}) (Manifest, error) { func FromOrig(orig interface{}) (Manifest, error) {
return topManifest.New(topManifest.WithOrig(orig)) return topManifest.New(topManifest.WithOrig(orig))
} }

View File

@ -5,19 +5,55 @@
package regclient package regclient
import "github.com/regclient/regclient/types" import "github.com/regclient/regclient/types/mediatype"
var ( var (
MediaTypeDocker1Manifest = types.MediaTypeDocker1Manifest // MediaTypeDocker1Manifest
MediaTypeDocker1ManifestSigned = types.MediaTypeDocker1ManifestSigned //
MediaTypeDocker2Manifest = types.MediaTypeDocker2Manifest // Deprecated: replace with [mediatype.Docker1Manifest].
MediaTypeDocker2ManifestList = types.MediaTypeDocker2ManifestList MediaTypeDocker1Manifest = mediatype.Docker1Manifest
MediaTypeDocker2ImageConfig = types.MediaTypeDocker2ImageConfig // MediaTypeDocker1ManifestSigned
MediaTypeOCI1Manifest = types.MediaTypeOCI1Manifest //
MediaTypeOCI1ManifestList = types.MediaTypeOCI1ManifestList // Deprecated: replace with [mediatype.Docker1ManifestSigned]
MediaTypeOCI1ImageConfig = types.MediaTypeOCI1ImageConfig MediaTypeDocker1ManifestSigned = mediatype.Docker1ManifestSigned
MediaTypeDocker2Layer = types.MediaTypeDocker2LayerGzip // MediaTypeDocker2Manifest
MediaTypeOCI1Layer = types.MediaTypeOCI1Layer //
MediaTypeOCI1LayerGzip = types.MediaTypeOCI1LayerGzip // Deprecated: replace with [mediatype.Docker2Manifest].
MediaTypeBuildkitCacheConfig = types.MediaTypeBuildkitCacheConfig MediaTypeDocker2Manifest = mediatype.Docker2Manifest
// MediaTypeDocker2ManifestList
//
// Deprecated: replace with [mediatype.Docker2ManifestList].
MediaTypeDocker2ManifestList = mediatype.Docker2ManifestList
// MediaTypeDocker2ImageConfig
//
// Deprecated: replace with [mediatype.Docker2ImageConfig].
MediaTypeDocker2ImageConfig = mediatype.Docker2ImageConfig
// MediaTypeOCI1Manifest
//
// Deprecated: replace with [mediatype.OCI1Manifest].
MediaTypeOCI1Manifest = mediatype.OCI1Manifest
// MediaTypeOCI1ManifestList
//
// Deprecated: replace with [mediatype.OCI1ManifestList].
MediaTypeOCI1ManifestList = mediatype.OCI1ManifestList
// MediaTypeOCI1ImageConfig
//
// Deprecated: replace with [mediatype.OCI1ImageConfig].
MediaTypeOCI1ImageConfig = mediatype.OCI1ImageConfig
// MediaTypeDocker2Layer
//
// Deprecated: replace with [mediatype.Docker2Layer].
MediaTypeDocker2Layer = mediatype.Docker2LayerGzip
// MediaTypeOCI1Layer
//
// Deprecated: replace with [mediatype.OCI1Layer].
MediaTypeOCI1Layer = mediatype.OCI1Layer
// MediaTypeOCI1LayerGzip
//
// Deprecated: replace with [mediatype.OCI1LayerGzip].
MediaTypeOCI1LayerGzip = mediatype.OCI1LayerGzip
// MediaTypeBuildkitCacheConfig
//
// Deprecated: replace with [mediatype.BuildkitCacheConfig].
MediaTypeBuildkitCacheConfig = mediatype.BuildkitCacheConfig
) )

View File

@ -28,37 +28,125 @@ const (
var ( var (
// VCSRef is injected from a build flag, used to version the UserAgent header // VCSRef is injected from a build flag, used to version the UserAgent header
//
// Deprecated: this should now be set using github.com/regclient/regclient/internal/version.vcsTag.
VCSRef = "unknown" VCSRef = "unknown"
) )
type RegClient = *rcTop.RegClient type (
type Client = *rcTop.RegClient // RegClient is used to access OCI distribution-spec registries.
type Opt = rcTop.Opt //
type ImageOpts = rcTop.ImageOpts // Deprecated: replace with [regclient.RegClient]
type RepoList = *repo.RepoList RegClient = *rcTop.RegClient
type RepoDockerList = repo.RepoRegistryList // Client is used to access OCI distribution-spec registries.
type RepoOpts = scheme.RepoOpts // RepoOpts is a breaking change (struct to func opts) //
type TagList = *tag.List // Deprecated: replace with [regclient.RegClient]
type TagDockerList = tag.DockerList Client = *rcTop.RegClient
type TagOpts = scheme.TagOpts // Opt functions are used by [New] to create a [*RegClient].
//
// Deprecated: replace with [regclient.Opt]
Opt = rcTop.Opt
// ImageOpts functions are used by image methods.
//
// Deprecated: replace with [regclient.ImageOpts]
ImageOpts = rcTop.ImageOpts
// RepoList is the response for a registry listing.
//
// Deprecated: replace with [repo.RepoList]
RepoList = *repo.RepoList
// RepoDockerList is a list of repositories from the _catalog API
//
// Deprecated: replace with [repo.RepoRegistryList
RepoDockerList = repo.RepoRegistryList
// RepoOpts is a breaking change (struct to func opts)
//
// Deprecated: replace with [regclient.RepoOpts]
RepoOpts = scheme.RepoOpts
// TagList contains a tag list.
//
// Deprecated: replace with [tag.List]
TagList = *tag.List
// TagDockerList is returned from registry/2.0 API's
//
// Deprecated: replace with [tag.DockerList]
TagDockerList = tag.DockerList
// TagOpts is used to set options on tag APIs.
//
// Deprecated: replace with [scheme.TagOpts]
TagOpts = scheme.TagOpts
)
var ( var (
NewRegClient = rcTop.New // NewRegClient creates a new regclient instance.
WithCertDir = rcTop.WithCertDir //
WithDockerCerts = rcTop.WithDockerCerts // Deprecated: replace with [regclient.New].
WithDockerCreds = rcTop.WithDockerCreds NewRegClient = rcTop.New
WithConfigHosts = rcTop.WithConfigHosts // WithCertDir adds a path of certificates to trust similar to Docker's /etc/docker/certs.d.
WithConfigHost = rcTop.WithConfigHost //
WithBlobSize = rcTop.WithBlobSize // Deprecated: replace with [regclient.WithCertDir].
WithLog = rcTop.WithLog WithCertDir = rcTop.WithCertDir
WithRetryDelay = rcTop.WithRetryDelay // WithDockerCerts adds certificates trusted by docker in /etc/docker/certs.d.
WithRetryLimit = rcTop.WithRetryLimit //
WithUserAgent = rcTop.WithUserAgent // Deprecated: replace with [regclient.WithDockerCerts].
WithDockerCerts = rcTop.WithDockerCerts
// WithDockerCreds adds configuration from users docker config with registry logins.
//
// Deprecated: replace with [regclient.WithDockerCreds].
WithDockerCreds = rcTop.WithDockerCreds
// WithConfigHosts adds a list of config host settings.
//
// Deprecated: replace with [regclient.WithConfigHosts].
WithConfigHosts = rcTop.WithConfigHosts
// WithConfigHost adds a list of config host settings.
//
// Deprecated: replace with [regclient.WithConfigHost].
WithConfigHost = rcTop.WithConfigHost
// WithBlobSize overrides default blob sizes.
//
// Deprecated: replace with [regclient.WithBlobSize].
WithBlobSize = rcTop.WithBlobSize
// WithLog overrides default logrus Logger.
//
// Deprecated: replace with [regclient.WithLog].
WithLog = rcTop.WithLog
// WithRetryDelay specifies the time permitted for retry delays.
//
// Deprecated: replace with [regclient.WithRetryDelay].
WithRetryDelay = rcTop.WithRetryDelay
// WithRetryLimit specifies the number of retries for non-fatal errors.
//
// Deprecated: replace with [regclient.WithRetryLimit].
WithRetryLimit = rcTop.WithRetryLimit
// WithUserAgent specifies the User-Agent http header.
//
// Deprecated: replace with [regclient.WithUserAgent].
WithUserAgent = rcTop.WithUserAgent
// ImageWithForceRecursive attempts to copy every manifest and blob even if parent manifests already exist in ImageCopy.
//
// Deprecated: replace with [regclient.ImageWithForceRecursive].
ImageWithForceRecursive = rcTop.ImageWithForceRecursive ImageWithForceRecursive = rcTop.ImageWithForceRecursive
ImageWithDigestTags = rcTop.ImageWithDigestTags // ImageWithDigestTags looks for "sha-<digest>.*" tags in the repo to copy with any manifest in ImageCopy.
ImageWithPlatforms = rcTop.ImageWithPlatforms //
WithRepoLast = scheme.WithRepoLast // Deprecated: replace with [regclient.ImageWithDigestTags].
WithRepoLimit = scheme.WithRepoLimit ImageWithDigestTags = rcTop.ImageWithDigestTags
TagOptLast = scheme.WithTagLast // ImageWithPlatform requests specific platforms from a manifest list in ImageCheckBase.
TagOptLimit = scheme.WithTagLimit //
// Deprecated: replace with [regclient.ImageWithPlatforms].
ImageWithPlatforms = rcTop.ImageWithPlatforms
// WithRepoLast passes the last received repository for requesting the next batch of repositories.
//
// Deprecated: replace with [scheme.WithRepoLast].
WithRepoLast = scheme.WithRepoLast
// WithRepoLimit passes a maximum number of repositories to return to the repository list API.
//
// Deprecated: replace with [scheme.WithRepoLimit].
WithRepoLimit = scheme.WithRepoLimit
// TagOptLast passes the last received tag for requesting the next batch of tags.
//
// Deprecated: replace with [scheme.WithTagLast].
TagOptLast = scheme.WithTagLast
// TagOptLimit passes a maximum number of tags to return to the tag list API.
//
// Deprecated: replace with [scheme.WithTagLimit].
TagOptLimit = scheme.WithTagLimit
) )

View File

@ -9,4 +9,7 @@ import (
gotemplate "text/template" gotemplate "text/template"
) )
// TemplateFuncs adds functions to a template.
//
// Deprecated: replace with [gotemplate.FuncMap].
var TemplateFuncs = gotemplate.FuncMap{} var TemplateFuncs = gotemplate.FuncMap{}

View File

@ -6,35 +6,113 @@
package types package types
import ( import (
topTypes "github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
var ( var (
ErrAllRequestsFailed = topTypes.ErrAllRequestsFailed // ErrAllRequestsFailed
ErrAPINotFound = topTypes.ErrAPINotFound //
ErrBackoffLimit = topTypes.ErrBackoffLimit // Deprecated: replace with [errs.ErrAllRequestsFailed].
ErrCanceled = topTypes.ErrCanceled ErrAllRequestsFailed = errs.ErrAllRequestsFailed
ErrDigestMismatch = topTypes.ErrDigestMismatch // ErrAPINotFound
ErrEmptyChallenge = topTypes.ErrEmptyChallenge //
// Deprecated: replace with [errs.ErrAPINotFound].
ErrAPINotFound = errs.ErrAPINotFound
// ErrBackoffLimit
//
// Deprecated: replace with [errs.ErrBackoffLimit].
ErrBackoffLimit = errs.ErrBackoffLimit
// ErrCanceled
//
// Deprecated: replace with [errs.ErrCanceled].
ErrCanceled = errs.ErrCanceled
// ErrDigestMismatch
//
// Deprecated: replace with [errs.ErrDigestMismatch].
ErrDigestMismatch = errs.ErrDigestMismatch
// ErrEmptyChallenge
//
// Deprecated: replace with [errs.ErrEmptyChallenge].
ErrEmptyChallenge = errs.ErrEmptyChallenge
//lint:ignore ST1003 exported field cannot be changed for legacy reasons //lint:ignore ST1003 exported field cannot be changed for legacy reasons
ErrHttpStatus = topTypes.ErrHTTPStatus // ErrHttpStatus
ErrInvalidChallenge = topTypes.ErrInvalidChallenge //
ErrMissingDigest = topTypes.ErrMissingDigest // Deprecated: replace with [errs.ErrHttpStatus].
ErrMissingLocation = topTypes.ErrMissingLocation ErrHttpStatus = errs.ErrHTTPStatus
ErrMissingName = topTypes.ErrMissingName // ErrInvalidChallenge
ErrMissingTag = topTypes.ErrMissingTag //
ErrMissingTagOrDigest = topTypes.ErrMissingTagOrDigest // Deprecated: replace with [errs.ErrInvalidChallenge].
ErrMountReturnedLocation = topTypes.ErrMountReturnedLocation ErrInvalidChallenge = errs.ErrInvalidChallenge
ErrNoNewChallenge = topTypes.ErrNoNewChallenge // ErrMissingDigest
ErrNotFound = topTypes.ErrNotFound //
ErrNotImplemented = topTypes.ErrNotImplemented // Deprecated: replace with [errs.ErrMissingDigest].
ErrParsingFailed = topTypes.ErrParsingFailed ErrMissingDigest = errs.ErrMissingDigest
ErrRateLimit = topTypes.ErrHTTPRateLimit // ErrMissingLocation
ErrRetryNeeded = topTypes.ErrRetryNeeded //
ErrUnavailable = topTypes.ErrUnavailable // Deprecated: replace with [errs.ErrMissingLocation].
ErrUnauthorized = topTypes.ErrHTTPUnauthorized ErrMissingLocation = errs.ErrMissingLocation
ErrUnsupported = topTypes.ErrUnsupported // ErrMissingName
ErrUnsupportedAPI = topTypes.ErrUnsupportedAPI //
ErrUnsupportedConfigVersion = topTypes.ErrUnsupportedConfigVersion // Deprecated: replace with [errs.ErrMissingName].
ErrUnsupportedMediaType = topTypes.ErrUnsupportedMediaType ErrMissingName = errs.ErrMissingName
// ErrMissingTag
//
// Deprecated: replace with [errs.ErrMissingTag].
ErrMissingTag = errs.ErrMissingTag
// ErrMissingTagOrDigest
//
// Deprecated: replace with [errs.ErrMissingTagOrDigest].
ErrMissingTagOrDigest = errs.ErrMissingTagOrDigest
// ErrMountReturnedLocation
//
// Deprecated: replace with [errs.ErrMountReturnedLocation].
ErrMountReturnedLocation = errs.ErrMountReturnedLocation
// ErrNoNewChallenge
//
// Deprecated: replace with [errs.ErrNoNewChallenge].
ErrNoNewChallenge = errs.ErrNoNewChallenge
// ErrNotFound
//
// Deprecated: replace with [errs.ErrNotFound].
ErrNotFound = errs.ErrNotFound
// ErrNotImplemented
//
// Deprecated: replace with [errs.ErrNotImplemented].
ErrNotImplemented = errs.ErrNotImplemented
// ErrParsingFailed
//
// Deprecated: replace with [errs.ErrParsingFailed].
ErrParsingFailed = errs.ErrParsingFailed
// ErrRateLimit
//
// Deprecated: replace with [errs.ErrRateLimit].
ErrRateLimit = errs.ErrHTTPRateLimit
// ErrRetryNeeded
//
// Deprecated: replace with [errs.ErrRetryNeeded].
ErrRetryNeeded = errs.ErrRetryNeeded
// ErrUnavailable
//
// Deprecated: replace with [errs.ErrUnavailable].
ErrUnavailable = errs.ErrUnavailable
// ErrUnauthorized
//
// Deprecated: replace with [errs.ErrUnauthorized].
ErrUnauthorized = errs.ErrHTTPUnauthorized
// ErrUnsupported
//
// Deprecated: replace with [errs.ErrUnsupported].
ErrUnsupported = errs.ErrUnsupported
// ErrUnsupportedAPI
//
// Deprecated: replace with [errs.ErrUnsupportedAPI].
ErrUnsupportedAPI = errs.ErrUnsupportedAPI
// ErrUnsupportedConfigVersion
//
// Deprecated: replace with [errs.ErrUnsupportedConfigVersion].
ErrUnsupportedConfigVersion = errs.ErrUnsupportedConfigVersion
// ErrUnsupportedMediaType
//
// Deprecated: replace with [errs.ErrUnsupportedMediaType].
ErrUnsupportedMediaType = errs.ErrUnsupportedMediaType
) )

View File

@ -6,20 +6,56 @@
package types package types
import ( import (
topTypes "github.com/regclient/regclient/types" "github.com/regclient/regclient/types/mediatype"
) )
const ( const (
MediaTypeDocker1Manifest = topTypes.MediaTypeDocker1Manifest // MediaTypeDocker1Manifest
MediaTypeDocker1ManifestSigned = topTypes.MediaTypeDocker1ManifestSigned //
MediaTypeDocker2Manifest = topTypes.MediaTypeDocker2Manifest // Deprecated: replaced by [mediatype.Docker1Manifest].
MediaTypeDocker2ManifestList = topTypes.MediaTypeDocker2ManifestList MediaTypeDocker1Manifest = mediatype.Docker1Manifest
MediaTypeDocker2ImageConfig = topTypes.MediaTypeDocker2ImageConfig // MediaTypeDocker1ManifestSigned
MediaTypeOCI1Manifest = topTypes.MediaTypeOCI1Manifest //
MediaTypeOCI1ManifestList = topTypes.MediaTypeOCI1ManifestList // Deprecated: replaced by [mediatype.Docker1ManifestSigned]
MediaTypeOCI1ImageConfig = topTypes.MediaTypeOCI1ImageConfig MediaTypeDocker1ManifestSigned = mediatype.Docker1ManifestSigned
MediaTypeDocker2Layer = topTypes.MediaTypeDocker2LayerGzip // MediaTypeDocker2Manifest
MediaTypeOCI1Layer = topTypes.MediaTypeOCI1Layer //
MediaTypeOCI1LayerGzip = topTypes.MediaTypeOCI1LayerGzip // Deprecated: replaced by [mediatype.Docker2Manifest].
MediaTypeBuildkitCacheConfig = topTypes.MediaTypeBuildkitCacheConfig MediaTypeDocker2Manifest = mediatype.Docker2Manifest
// MediaTypeDocker2ManifestList
//
// Deprecated: replaced by [mediatype.Docker2ManifestList].
MediaTypeDocker2ManifestList = mediatype.Docker2ManifestList
// MediaTypeDocker2ImageConfig
//
// Deprecated: replaced by [mediatype.Docker2ImageConfig].
MediaTypeDocker2ImageConfig = mediatype.Docker2ImageConfig
// MediaTypeOCI1Manifest
//
// Deprecated: replaced by [mediatype.OCI1Manifest].
MediaTypeOCI1Manifest = mediatype.OCI1Manifest
// MediaTypeOCI1ManifestList
//
// Deprecated: replaced by [mediatype.OCI1ManifestList].
MediaTypeOCI1ManifestList = mediatype.OCI1ManifestList
// MediaTypeOCI1ImageConfig
//
// Deprecated: replaced by [mediatype.OCI1ImageConfig].
MediaTypeOCI1ImageConfig = mediatype.OCI1ImageConfig
// MediaTypeDocker2Layer
//
// Deprecated: replaced by [mediatype.Docker2Layer].
MediaTypeDocker2Layer = mediatype.Docker2LayerGzip
// MediaTypeOCI1Layer
//
// Deprecated: replaced by [mediatype.OCI1Layer].
MediaTypeOCI1Layer = mediatype.OCI1Layer
// MediaTypeOCI1LayerGzip
//
// Deprecated: replaced by [mediatype.OCI1LayerGzip].
MediaTypeOCI1LayerGzip = mediatype.OCI1LayerGzip
// MediaTypeBuildkitCacheConfig
//
// Deprecated: replaced by [mediatype.BuildkitCacheConfig].
MediaTypeBuildkitCacheConfig = mediatype.BuildkitCacheConfig
) )

View File

@ -10,4 +10,6 @@ import (
) )
// RateLimit is returned from some http requests // RateLimit is returned from some http requests
//
// Deprecated: replace with [types.RateLimit].
type RateLimit = topTypes.RateLimit type RateLimit = topTypes.RateLimit

View File

@ -9,6 +9,12 @@ import (
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
// Ref is used for a reference to an image or repository.
//
// Deprecated: replace with [ref.Ref].
type Ref = ref.Ref type Ref = ref.Ref
// NewRef create a new [Ref].
//
// Deprecated: replace with [ref.New].
var NewRef = ref.New var NewRef = ref.New

View File

@ -6,7 +6,7 @@ import (
"strings" "strings"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/repo" "github.com/regclient/regclient/types/repo"
) )
@ -19,7 +19,7 @@ type repoLister interface {
func (rc *RegClient) RepoList(ctx context.Context, hostname string, opts ...scheme.RepoOpts) (*repo.RepoList, error) { func (rc *RegClient) RepoList(ctx context.Context, hostname string, opts ...scheme.RepoOpts) (*repo.RepoList, error) {
i := strings.Index(hostname, "/") i := strings.Index(hostname, "/")
if i > 0 { if i > 0 {
return nil, fmt.Errorf("invalid hostname: %s%.0w", hostname, types.ErrParsingFailed) return nil, fmt.Errorf("invalid hostname: %s%.0w", hostname, errs.ErrParsingFailed)
} }
schemeAPI, err := rc.schemeGet("reg") schemeAPI, err := rc.schemeGet("reg")
if err != nil { if err != nil {
@ -27,7 +27,7 @@ func (rc *RegClient) RepoList(ctx context.Context, hostname string, opts ...sche
} }
rl, ok := schemeAPI.(repoLister) rl, ok := schemeAPI.(repoLister)
if !ok { if !ok {
return nil, types.ErrNotImplemented return nil, errs.ErrNotImplemented
} }
return rl.RepoList(ctx, hostname, opts...) return rl.RepoList(ctx, hostname, opts...)
} }

View File

@ -9,7 +9,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
func TestRepoList(t *testing.T) { func TestRepoList(t *testing.T) {
@ -27,7 +27,7 @@ func TestRepoList(t *testing.T) {
WithRetryDelay(delayInit, delayMax), WithRetryDelay(delayInit, delayMax),
) )
_, err := rc.RepoList(ctx, "registry.example.com/path") _, err := rc.RepoList(ctx, "registry.example.com/path")
if !errors.Is(err, types.ErrParsingFailed) { if !errors.Is(err, errs.ErrParsingFailed) {
t.Errorf("RepoList unexpected error on hostname with a path: expected %v, received %v", types.ErrParsingFailed, err) t.Errorf("RepoList unexpected error on hostname with a path: expected %v, received %v", errs.ErrParsingFailed, err)
} }
} }

View File

@ -5,14 +5,14 @@ import (
"fmt" "fmt"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
func (rc *RegClient) schemeGet(scheme string) (scheme.API, error) { func (rc *RegClient) schemeGet(scheme string) (scheme.API, error) {
s, ok := rc.schemes[scheme] s, ok := rc.schemes[scheme]
if !ok { if !ok {
return nil, fmt.Errorf("%w: unknown scheme \"%s\"", types.ErrNotImplemented, scheme) return nil, fmt.Errorf("%w: unknown scheme \"%s\"", errs.ErrNotImplemented, scheme)
} }
return s, nil return s, nil
} }

View File

@ -16,21 +16,22 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/blob" "github.com/regclient/regclient/types/blob"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
// BlobDelete removes a blob from the repository. // BlobDelete removes a blob from the repository.
// This method does not verify that blobs are unused. // This method does not verify that blobs are unused.
// Calling the [OCIDir.Close] method to trigger the garbage collection is preferred. // Calling the [OCIDir.Close] method to trigger the garbage collection is preferred.
func (o *OCIDir) BlobDelete(ctx context.Context, r ref.Ref, d types.Descriptor) error { func (o *OCIDir) BlobDelete(ctx context.Context, r ref.Ref, d descriptor.Descriptor) error {
file := path.Join(r.Path, "blobs", d.Digest.Algorithm().String(), d.Digest.Encoded()) file := path.Join(r.Path, "blobs", d.Digest.Algorithm().String(), d.Digest.Encoded())
return o.fs.Remove(file) return o.fs.Remove(file)
} }
// BlobGet retrieves a blob, returning a reader // BlobGet retrieves a blob, returning a reader
func (o *OCIDir) BlobGet(ctx context.Context, r ref.Ref, d types.Descriptor) (blob.Reader, error) { func (o *OCIDir) BlobGet(ctx context.Context, r ref.Ref, d descriptor.Descriptor) (blob.Reader, error) {
file := path.Join(r.Path, "blobs", d.Digest.Algorithm().String(), d.Digest.Encoded()) file := path.Join(r.Path, "blobs", d.Digest.Algorithm().String(), d.Digest.Encoded())
fd, err := o.fs.Open(file) fd, err := o.fs.Open(file)
if err != nil { if err != nil {
@ -57,7 +58,7 @@ func (o *OCIDir) BlobGet(ctx context.Context, r ref.Ref, d types.Descriptor) (bl
} }
// BlobHead verifies the existence of a blob, the reader contains the headers but no body to read // BlobHead verifies the existence of a blob, the reader contains the headers but no body to read
func (o *OCIDir) BlobHead(ctx context.Context, r ref.Ref, d types.Descriptor) (blob.Reader, error) { func (o *OCIDir) BlobHead(ctx context.Context, r ref.Ref, d descriptor.Descriptor) (blob.Reader, error) {
file := path.Join(r.Path, "blobs", d.Digest.Algorithm().String(), d.Digest.Encoded()) file := path.Join(r.Path, "blobs", d.Digest.Algorithm().String(), d.Digest.Encoded())
fd, err := o.fs.Open(file) fd, err := o.fs.Open(file)
if err != nil { if err != nil {
@ -79,12 +80,12 @@ func (o *OCIDir) BlobHead(ctx context.Context, r ref.Ref, d types.Descriptor) (b
} }
// BlobMount attempts to perform a server side copy of the blob // BlobMount attempts to perform a server side copy of the blob
func (o *OCIDir) BlobMount(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d types.Descriptor) error { func (o *OCIDir) BlobMount(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d descriptor.Descriptor) error {
return types.ErrUnsupported return errs.ErrUnsupported
} }
// BlobPut sends a blob to the repository, returns the digest and size when successful // BlobPut sends a blob to the repository, returns the digest and size when successful
func (o *OCIDir) BlobPut(ctx context.Context, r ref.Ref, d types.Descriptor, rdr io.Reader) (types.Descriptor, error) { func (o *OCIDir) BlobPut(ctx context.Context, r ref.Ref, d descriptor.Descriptor, rdr io.Reader) (descriptor.Descriptor, error) {
t := o.throttleGet(r, false) t := o.throttleGet(r, false)
err := t.Acquire(ctx) err := t.Acquire(ctx)
if err != nil { if err != nil {

View File

@ -10,7 +10,7 @@ import (
"testing" "testing"
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -151,7 +151,7 @@ func TestBlob(t *testing.T) {
go func() { go func() {
defer wg.Done() defer wg.Done()
bRdr := bytes.NewReader(bBytes) bRdr := bytes.NewReader(bBytes)
bpd, err := om.BlobPut(ctx, rPut, types.Descriptor{}, bRdr) bpd, err := om.BlobPut(ctx, rPut, descriptor.Descriptor{}, bRdr)
if err != nil { if err != nil {
t.Errorf("blob put: %v", err) t.Errorf("blob put: %v", err)
return return

View File

@ -18,8 +18,9 @@ import (
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -29,7 +30,7 @@ func (o *OCIDir) ManifestDelete(ctx context.Context, r ref.Ref, opts ...scheme.M
defer o.mu.Unlock() defer o.mu.Unlock()
if r.Digest == "" { if r.Digest == "" {
return fmt.Errorf("digest required to delete manifest, reference %s%.0w", r.CommonName(), types.ErrMissingDigest) return fmt.Errorf("digest required to delete manifest, reference %s%.0w", r.CommonName(), errs.ErrMissingDigest)
} }
mc := scheme.ManifestConfig{} mc := scheme.ManifestConfig{}
@ -51,7 +52,7 @@ func (o *OCIDir) ManifestDelete(ctx context.Context, r ref.Ref, opts ...scheme.M
if err == nil && sDesc != nil && sDesc.MediaType != "" && sDesc.Size > 0 { if err == nil && sDesc != nil && sDesc.MediaType != "" && sDesc.Size > 0 {
// attempt to delete the referrer, but ignore if the referrer entry wasn't found // attempt to delete the referrer, but ignore if the referrer entry wasn't found
err = o.referrerDelete(ctx, r, mc.Manifest) err = o.referrerDelete(ctx, r, mc.Manifest)
if err != nil && !errors.Is(err, types.ErrNotFound) && !errors.Is(err, fs.ErrNotExist) { if err != nil && !errors.Is(err, errs.ErrNotFound) && !errors.Is(err, fs.ErrNotExist) {
return err return err
} }
} }
@ -114,7 +115,7 @@ func (o *OCIDir) manifestGet(ctx context.Context, r ref.Ref) (manifest.Manifest,
} }
} }
if desc.Digest == "" { if desc.Digest == "" {
return nil, types.ErrNotFound return nil, errs.ErrNotFound
} }
file := path.Join(r.Path, "blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded()) file := path.Join(r.Path, "blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded())
fd, err := o.fs.Open(file) fd, err := o.fs.Open(file)
@ -158,13 +159,13 @@ func (o *OCIDir) ManifestHead(ctx context.Context, r ref.Ref) (manifest.Manifest
} }
} }
if desc.Digest == "" { if desc.Digest == "" {
return nil, types.ErrNotFound return nil, errs.ErrNotFound
} }
// verify underlying file exists // verify underlying file exists
file := path.Join(r.Path, "blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded()) file := path.Join(r.Path, "blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded())
fi, err := rwfs.Stat(o.fs, file) fi, err := rwfs.Stat(o.fs, file)
if err != nil || fi.IsDir() { if err != nil || fi.IsDir() {
return nil, types.ErrNotFound return nil, errs.ErrNotFound
} }
// if missing, set media type on desc // if missing, set media type on desc
if desc.MediaType == "" { if desc.MediaType == "" {
@ -185,9 +186,9 @@ func (o *OCIDir) ManifestHead(ctx context.Context, r ref.Ref) (manifest.Manifest
desc.MediaType = mt.MediaType desc.MediaType = mt.MediaType
desc.Size = int64(len(raw)) desc.Size = int64(len(raw))
} else if mt.SchemaVersion == 1 && len(mt.Signatures) > 0 { } else if mt.SchemaVersion == 1 && len(mt.Signatures) > 0 {
desc.MediaType = types.MediaTypeDocker1ManifestSigned desc.MediaType = mediatype.Docker1ManifestSigned
} else if mt.SchemaVersion == 1 { } else if mt.SchemaVersion == 1 {
desc.MediaType = types.MediaTypeDocker1Manifest desc.MediaType = mediatype.Docker1Manifest
desc.Size = int64(len(raw)) desc.Size = int64(len(raw))
} }
} }

View File

@ -12,8 +12,8 @@ import (
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -44,8 +44,8 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("manifest get: %v", err) t.Fatalf("manifest get: %v", err)
} }
if manifest.GetMediaType(ml) != types.MediaTypeOCI1ManifestList { if manifest.GetMediaType(ml) != mediatype.OCI1ManifestList {
t.Errorf("manifest mt, expected %s, received %s", types.MediaTypeOCI1ManifestList, manifest.GetMediaType(ml)) t.Errorf("manifest mt, expected %s, received %s", mediatype.OCI1ManifestList, manifest.GetMediaType(ml))
} }
if !ml.IsList() { if !ml.IsList() {
t.Errorf("expected manifest list") t.Errorf("expected manifest list")

View File

@ -15,7 +15,9 @@ import (
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/internal/throttle" "github.com/regclient/regclient/internal/throttle"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -210,7 +212,7 @@ func (o *OCIDir) readIndex(r ref.Ref, locked bool) (v1.Index, error) {
return index, nil return index, nil
} }
func (o *OCIDir) updateIndex(r ref.Ref, d types.Descriptor, child bool, locked bool) error { func (o *OCIDir) updateIndex(r ref.Ref, d descriptor.Descriptor, child bool, locked bool) error {
if !locked { if !locked {
o.mu.Lock() o.mu.Lock()
defer o.mu.Unlock() defer o.mu.Unlock()
@ -331,14 +333,14 @@ func (o *OCIDir) refMod(r ref.Ref) {
func indexCreate() v1.Index { func indexCreate() v1.Index {
i := v1.Index{ i := v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Manifests: []types.Descriptor{}, Manifests: []descriptor.Descriptor{},
Annotations: map[string]string{}, Annotations: map[string]string{},
} }
return i return i
} }
func indexGet(index v1.Index, r ref.Ref) (types.Descriptor, error) { func indexGet(index v1.Index, r ref.Ref) (descriptor.Descriptor, error) {
if r.Digest == "" && r.Tag == "" { if r.Digest == "" && r.Tag == "" {
r.Tag = "latest" r.Tag = "latest"
} }
@ -361,10 +363,10 @@ func indexGet(index v1.Index, r ref.Ref) (types.Descriptor, error) {
} }
} }
} }
return types.Descriptor{}, types.ErrNotFound return descriptor.Descriptor{}, errs.ErrNotFound
} }
func indexSet(index *v1.Index, r ref.Ref, d types.Descriptor) error { func indexSet(index *v1.Index, r ref.Ref, d descriptor.Descriptor) error {
if index == nil { if index == nil {
return fmt.Errorf("index is nil") return fmt.Errorf("index is nil")
} }
@ -375,7 +377,7 @@ func indexSet(index *v1.Index, r ref.Ref, d types.Descriptor) error {
d.Annotations[aOCIRefName] = r.Tag d.Annotations[aOCIRefName] = r.Tag
} }
if index.Manifests == nil { if index.Manifests == nil {
index.Manifests = []types.Descriptor{} index.Manifests = []descriptor.Descriptor{}
} }
pos := -1 pos := -1
// search for existing // search for existing

View File

@ -8,7 +8,9 @@ import (
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -61,29 +63,29 @@ func TestIndex(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("failed to generate ref: %v", err) t.Errorf("failed to generate ref: %v", err)
} }
descNoTag := types.Descriptor{ descNoTag := descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: dig1, Digest: dig1,
} }
descA := types.Descriptor{ descA := descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: dig2, Digest: dig2,
Annotations: map[string]string{ Annotations: map[string]string{
aOCIRefName: "tag-a", aOCIRefName: "tag-a",
}, },
} }
descB := types.Descriptor{ descB := descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: dig2, Digest: dig2,
Annotations: map[string]string{ Annotations: map[string]string{
aOCIRefName: "tag-b", aOCIRefName: "tag-b",
}, },
} }
descC := types.Descriptor{ descC := descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: dig3, Digest: dig3,
Annotations: map[string]string{ Annotations: map[string]string{
@ -94,23 +96,23 @@ func TestIndex(t *testing.T) {
name string name string
index v1.Index index v1.Index
get ref.Ref get ref.Ref
expectGet types.Descriptor expectGet descriptor.Descriptor
expectGetErr error expectGetErr error
set ref.Ref set ref.Ref
setDesc types.Descriptor setDesc descriptor.Descriptor
expectLen int expectLen int
}{ }{
{ {
name: "empty", name: "empty",
get: rA, get: rA,
expectGetErr: types.ErrNotFound, expectGetErr: errs.ErrNotFound,
}, },
{ {
name: "no tag", name: "no tag",
index: v1.Index{ index: v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Manifests: []types.Descriptor{ Manifests: []descriptor.Descriptor{
descNoTag, descNoTag,
}, },
}, },
@ -124,8 +126,8 @@ func TestIndex(t *testing.T) {
name: "tag a", name: "tag a",
index: v1.Index{ index: v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Manifests: []types.Descriptor{ Manifests: []descriptor.Descriptor{
descNoTag, descNoTag,
descA, descA,
}, },
@ -140,8 +142,8 @@ func TestIndex(t *testing.T) {
name: "tag b", name: "tag b",
index: v1.Index{ index: v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Manifests: []types.Descriptor{ Manifests: []descriptor.Descriptor{
descNoTag, descNoTag,
descB, descB,
}, },
@ -156,8 +158,8 @@ func TestIndex(t *testing.T) {
name: "tag c", name: "tag c",
index: v1.Index{ index: v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Manifests: []types.Descriptor{ Manifests: []descriptor.Descriptor{
descA, descA,
descC, descC,
}, },

View File

@ -6,8 +6,9 @@ import (
"fmt" "fmt"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -66,11 +67,11 @@ func (o *OCIDir) referrerList(ctx context.Context, r ref.Ref, opts ...scheme.Ref
} }
m, err := o.manifestGet(ctx, rlTag) m, err := o.manifestGet(ctx, rlTag)
if err != nil { if err != nil {
if errors.Is(err, types.ErrNotFound) { if errors.Is(err, errs.ErrNotFound) {
// empty list, initialize a new manifest // empty list, initialize a new manifest
rl.Manifest, err = manifest.New(manifest.WithOrig(v1.Index{ rl.Manifest, err = manifest.New(manifest.WithOrig(v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
})) }))
if err != nil { if err != nil {
return rl, err return rl, err
@ -98,7 +99,7 @@ func (o *OCIDir) referrerDelete(ctx context.Context, r ref.Ref, m manifest.Manif
// get refers field // get refers field
mSubject, ok := m.(manifest.Subjecter) mSubject, ok := m.(manifest.Subjecter)
if !ok { if !ok {
return fmt.Errorf("manifest does not support subject: %w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest does not support subject: %w", errs.ErrUnsupportedMediaType)
} }
subject, err := mSubject.GetSubject() subject, err := mSubject.GetSubject()
if err != nil { if err != nil {
@ -106,7 +107,7 @@ func (o *OCIDir) referrerDelete(ctx context.Context, r ref.Ref, m manifest.Manif
} }
// validate/set subject descriptor // validate/set subject descriptor
if subject == nil || subject.MediaType == "" || subject.Digest == "" || subject.Size <= 0 { if subject == nil || subject.MediaType == "" || subject.Digest == "" || subject.Size <= 0 {
return fmt.Errorf("subject is not set%.0w", types.ErrNotFound) return fmt.Errorf("subject is not set%.0w", errs.ErrNotFound)
} }
// get descriptor for subject // get descriptor for subject
@ -142,7 +143,7 @@ func (o *OCIDir) referrerPut(ctx context.Context, r ref.Ref, m manifest.Manifest
// get subject field // get subject field
mSubject, ok := m.(manifest.Subjecter) mSubject, ok := m.(manifest.Subjecter)
if !ok { if !ok {
return fmt.Errorf("manifest does not support subject: %w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest does not support subject: %w", errs.ErrUnsupportedMediaType)
} }
subject, err := mSubject.GetSubject() subject, err := mSubject.GetSubject()
if err != nil { if err != nil {
@ -150,7 +151,7 @@ func (o *OCIDir) referrerPut(ctx context.Context, r ref.Ref, m manifest.Manifest
} }
// validate/set subject descriptor // validate/set subject descriptor
if subject == nil || subject.MediaType == "" || subject.Digest == "" || subject.Size <= 0 { if subject == nil || subject.MediaType == "" || subject.Digest == "" || subject.Size <= 0 {
return fmt.Errorf("subject is not set%.0w", types.ErrNotFound) return fmt.Errorf("subject is not set%.0w", errs.ErrNotFound)
} }
// get descriptor for subject // get descriptor for subject

View File

@ -11,8 +11,9 @@ import (
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -75,15 +76,15 @@ func TestReferrer(t *testing.T) {
} }
artifactA := v1.Manifest{ artifactA := v1.Manifest{
Versioned: v1.ManifestSchemaVersion, Versioned: v1.ManifestSchemaVersion,
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Config: types.Descriptor{ Config: descriptor.Descriptor{
MediaType: aType, MediaType: aType,
Size: 8, Size: 8,
Digest: digest1, Digest: digest1,
}, },
Layers: []types.Descriptor{ Layers: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeOCI1LayerGzip, MediaType: mediatype.OCI1LayerGzip,
Size: 8, Size: 8,
Digest: digest2, Digest: digest2,
}, },
@ -104,11 +105,11 @@ func TestReferrer(t *testing.T) {
timeAnnot: "2021-02-03T04:05:06Z", timeAnnot: "2021-02-03T04:05:06Z",
} }
artifactB := v1.ArtifactManifest{ artifactB := v1.ArtifactManifest{
MediaType: types.MediaTypeOCI1Artifact, MediaType: mediatype.OCI1Artifact,
ArtifactType: bType, ArtifactType: bType,
Blobs: []types.Descriptor{ Blobs: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeOCI1LayerGzip, MediaType: mediatype.OCI1LayerGzip,
Size: 8, Size: 8,
Digest: digest2, Digest: digest2,
}, },
@ -125,11 +126,11 @@ func TestReferrer(t *testing.T) {
t.Fatalf("failed extracting raw body from artifact: %v", err) t.Fatalf("failed extracting raw body from artifact: %v", err)
} }
artifactC := v1.ArtifactManifest{ artifactC := v1.ArtifactManifest{
MediaType: types.MediaTypeOCI1Artifact, MediaType: mediatype.OCI1Artifact,
ArtifactType: cType, ArtifactType: cType,
Blobs: []types.Descriptor{ Blobs: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeOCI1LayerGzip, MediaType: mediatype.OCI1LayerGzip,
Size: 8, Size: 8,
Digest: digest2, Digest: digest2,
}, },
@ -182,7 +183,7 @@ func TestReferrer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating getRef: %v", err) t.Fatalf("Failed creating getRef: %v", err)
} }
rl, err := o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{SortAnnotation: timeAnnot})) rl, err := o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{SortAnnotation: timeAnnot}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }
@ -190,7 +191,7 @@ func TestReferrer(t *testing.T) {
t.Fatalf("descriptor list length, expected 2, received %d", len(rl.Descriptors)) t.Fatalf("descriptor list length, expected 2, received %d", len(rl.Descriptors))
} }
// expecting artifact A in index 0 // expecting artifact A in index 0
if rl.Descriptors[0].MediaType != types.MediaTypeOCI1Manifest || if rl.Descriptors[0].MediaType != mediatype.OCI1Manifest ||
rl.Descriptors[0].Size != int64(len(artifactABody)) || rl.Descriptors[0].Size != int64(len(artifactABody)) ||
rl.Descriptors[0].Digest != artifactAM.GetDescriptor().Digest || rl.Descriptors[0].Digest != artifactAM.GetDescriptor().Digest ||
rl.Descriptors[0].ArtifactType != aType || rl.Descriptors[0].ArtifactType != aType ||
@ -198,7 +199,7 @@ func TestReferrer(t *testing.T) {
t.Errorf("returned descriptor A mismatch: %v", rl.Descriptors[0]) t.Errorf("returned descriptor A mismatch: %v", rl.Descriptors[0])
} }
// expecting artifact B in index 1 // expecting artifact B in index 1
if rl.Descriptors[1].MediaType != types.MediaTypeOCI1Artifact || if rl.Descriptors[1].MediaType != mediatype.OCI1Artifact ||
rl.Descriptors[1].Size != int64(len(artifactBBody)) || rl.Descriptors[1].Size != int64(len(artifactBBody)) ||
rl.Descriptors[1].Digest != artifactBM.GetDescriptor().Digest || rl.Descriptors[1].Digest != artifactBM.GetDescriptor().Digest ||
rl.Descriptors[1].ArtifactType != bType || rl.Descriptors[1].ArtifactType != bType ||
@ -208,7 +209,7 @@ func TestReferrer(t *testing.T) {
if len(rl.Tags) != 1 || rl.Tags[0] != tagRef { if len(rl.Tags) != 1 || rl.Tags[0] != tagRef {
t.Errorf("tag list missing entries, received: %v", rl.Tags) t.Errorf("tag list missing entries, received: %v", rl.Tags)
} }
rl, err = o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{SortAnnotation: timeAnnot, SortDesc: true})) rl, err = o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{SortAnnotation: timeAnnot, SortDesc: true}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList reverse: %v", err) t.Fatalf("Failed running ReferrerList reverse: %v", err)
} }
@ -226,14 +227,14 @@ func TestReferrer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating getRef: %v", err) t.Fatalf("Failed creating getRef: %v", err)
} }
rl, err := o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{ArtifactType: aType})) rl, err := o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{ArtifactType: aType}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }
if len(rl.Descriptors) != 1 { if len(rl.Descriptors) != 1 {
t.Fatalf("descriptor list length, expected 1, received %d", len(rl.Descriptors)) t.Fatalf("descriptor list length, expected 1, received %d", len(rl.Descriptors))
} }
rl, err = o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{ArtifactType: "application/vnd.example.unknown"})) rl, err = o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{ArtifactType: "application/vnd.example.unknown"}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }
@ -246,21 +247,21 @@ func TestReferrer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating getRef: %v", err) t.Fatalf("Failed creating getRef: %v", err)
} }
rl, err := o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{Annotations: map[string]string{extraAnnot: extraValueB}})) rl, err := o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{Annotations: map[string]string{extraAnnot: extraValueB}}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }
if len(rl.Descriptors) != 1 { if len(rl.Descriptors) != 1 {
t.Fatalf("descriptor list length, expected 1, received %d", len(rl.Descriptors)) t.Fatalf("descriptor list length, expected 1, received %d", len(rl.Descriptors))
} }
rl, err = o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{Annotations: map[string]string{extraAnnot: "unknown value"}})) rl, err = o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{Annotations: map[string]string{extraAnnot: "unknown value"}}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }
if len(rl.Descriptors) > 0 { if len(rl.Descriptors) > 0 {
t.Fatalf("unexpected descriptors") t.Fatalf("unexpected descriptors")
} }
rl, err = o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{Annotations: map[string]string{extraAnnot: ""}})) rl, err = o.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{Annotations: map[string]string{extraAnnot: ""}}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }

View File

@ -8,7 +8,8 @@ import (
"strings" "strings"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
"github.com/regclient/regclient/types/tag" "github.com/regclient/regclient/types/tag"
) )
@ -22,7 +23,7 @@ func (o *OCIDir) TagDelete(ctx context.Context, r ref.Ref) error {
func (o *OCIDir) tagDelete(ctx context.Context, r ref.Ref) error { func (o *OCIDir) tagDelete(ctx context.Context, r ref.Ref) error {
if r.Tag == "" { if r.Tag == "" {
return types.ErrMissingTag return errs.ErrMissingTag
} }
// get index // get index
index, err := o.readIndex(r, true) index, err := o.readIndex(r, true)
@ -38,7 +39,7 @@ func (o *OCIDir) tagDelete(ctx context.Context, r ref.Ref) error {
} }
} }
if !changed { if !changed {
return fmt.Errorf("failed deleting %s: %w", r.CommonName(), types.ErrNotFound) return fmt.Errorf("failed deleting %s: %w", r.CommonName(), errs.ErrNotFound)
} }
// push manifest back out // push manifest back out
err = o.writeIndex(r, index, true) err = o.writeIndex(r, index, true)
@ -83,7 +84,7 @@ func (o *OCIDir) TagList(ctx context.Context, r ref.Ref, opts ...scheme.TagOpts)
t, err := tag.New( t, err := tag.New(
tag.WithRaw(ib), tag.WithRaw(ib),
tag.WithRef(r), tag.WithRef(r),
tag.WithMT(types.MediaTypeOCI1ManifestList), tag.WithMT(mediatype.OCI1ManifestList),
tag.WithLayoutIndex(index), tag.WithLayoutIndex(index),
tag.WithTags(tl), tag.WithTags(tl),
) )

View File

@ -6,7 +6,7 @@ import (
"testing" "testing"
"github.com/regclient/regclient/internal/rwfs" "github.com/regclient/regclient/internal/rwfs"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -50,7 +50,7 @@ func TestTag(t *testing.T) {
exTags := []string{"broken", "v0.3"} exTags := []string{"broken", "v0.3"}
rCp.Tag = "missing" rCp.Tag = "missing"
err := oMem.TagDelete(ctx, rCp) err := oMem.TagDelete(ctx, rCp)
if err == nil || !errors.Is(err, types.ErrNotFound) { if err == nil || !errors.Is(err, errs.ErrNotFound) {
t.Errorf("deleting missing tag %s: %v", rCp.CommonName(), err) t.Errorf("deleting missing tag %s: %v", rCp.CommonName(), err)
} }
rCp.Tag = "latest" rCp.Tag = "latest"

View File

@ -19,8 +19,9 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/regclient/regclient/internal/reghttp" "github.com/regclient/regclient/internal/reghttp"
"github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/blob" "github.com/regclient/regclient/types/blob"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -29,7 +30,7 @@ var (
) )
// BlobDelete removes a blob from the repository // BlobDelete removes a blob from the repository
func (reg *Reg) BlobDelete(ctx context.Context, r ref.Ref, d types.Descriptor) error { func (reg *Reg) BlobDelete(ctx context.Context, r ref.Ref, d descriptor.Descriptor) error {
req := &reghttp.Req{ req := &reghttp.Req{
Host: r.Registry, Host: r.Registry,
APIs: map[string]reghttp.ReqAPI{ APIs: map[string]reghttp.ReqAPI{
@ -51,7 +52,7 @@ func (reg *Reg) BlobDelete(ctx context.Context, r ref.Ref, d types.Descriptor) e
} }
// BlobGet retrieves a blob from the repository, returning a blob reader // BlobGet retrieves a blob from the repository, returning a blob reader
func (reg *Reg) BlobGet(ctx context.Context, r ref.Ref, d types.Descriptor) (blob.Reader, error) { func (reg *Reg) BlobGet(ctx context.Context, r ref.Ref, d descriptor.Descriptor) (blob.Reader, error) {
// build/send request // build/send request
req := &reghttp.Req{ req := &reghttp.Req{
Host: r.Registry, Host: r.Registry,
@ -99,7 +100,7 @@ func (reg *Reg) BlobGet(ctx context.Context, r ref.Ref, d types.Descriptor) (blo
b := blob.NewReader( b := blob.NewReader(
blob.WithRef(r), blob.WithRef(r),
blob.WithReader(resp), blob.WithReader(resp),
blob.WithDesc(types.Descriptor{ blob.WithDesc(descriptor.Descriptor{
Digest: d.Digest, Digest: d.Digest,
}), }),
blob.WithResp(resp.HTTPResponse()), blob.WithResp(resp.HTTPResponse()),
@ -108,7 +109,7 @@ func (reg *Reg) BlobGet(ctx context.Context, r ref.Ref, d types.Descriptor) (blo
} }
// BlobHead is used to verify if a blob exists and is accessible // BlobHead is used to verify if a blob exists and is accessible
func (reg *Reg) BlobHead(ctx context.Context, r ref.Ref, d types.Descriptor) (blob.Reader, error) { func (reg *Reg) BlobHead(ctx context.Context, r ref.Ref, d descriptor.Descriptor) (blob.Reader, error) {
// build/send request // build/send request
req := &reghttp.Req{ req := &reghttp.Req{
Host: r.Registry, Host: r.Registry,
@ -156,7 +157,7 @@ func (reg *Reg) BlobHead(ctx context.Context, r ref.Ref, d types.Descriptor) (bl
b := blob.NewReader( b := blob.NewReader(
blob.WithRef(r), blob.WithRef(r),
blob.WithDesc(types.Descriptor{ blob.WithDesc(descriptor.Descriptor{
Digest: d.Digest, Digest: d.Digest,
}), }),
blob.WithResp(resp.HTTPResponse()), blob.WithResp(resp.HTTPResponse()),
@ -165,7 +166,7 @@ func (reg *Reg) BlobHead(ctx context.Context, r ref.Ref, d types.Descriptor) (bl
} }
// BlobMount attempts to perform a server side copy/mount of the blob between repositories // BlobMount attempts to perform a server side copy/mount of the blob between repositories
func (reg *Reg) BlobMount(ctx context.Context, rSrc ref.Ref, rTgt ref.Ref, d types.Descriptor) error { func (reg *Reg) BlobMount(ctx context.Context, rSrc ref.Ref, rTgt ref.Ref, d descriptor.Descriptor) error {
putURL, _, err := reg.blobMount(ctx, rTgt, d, rSrc) putURL, _, err := reg.blobMount(ctx, rTgt, d, rSrc)
// if mount fails and returns an upload location, cancel that upload // if mount fails and returns an upload location, cancel that upload
if err != nil { if err != nil {
@ -181,7 +182,7 @@ func (reg *Reg) BlobMount(ctx context.Context, rSrc ref.Ref, rTgt ref.Ref, d typ
// This will attempt an anonymous blob mount first which some registries may support. // This will attempt an anonymous blob mount first which some registries may support.
// It will then try doing a full put of the blob without chunking (most widely supported). // It will then try doing a full put of the blob without chunking (most widely supported).
// If the full put fails, it will fall back to a chunked upload (useful for flaky networks). // If the full put fails, it will fall back to a chunked upload (useful for flaky networks).
func (reg *Reg) BlobPut(ctx context.Context, r ref.Ref, d types.Descriptor, rdr io.Reader) (types.Descriptor, error) { func (reg *Reg) BlobPut(ctx context.Context, r ref.Ref, d descriptor.Descriptor, rdr io.Reader) (descriptor.Descriptor, error) {
var putURL *url.URL var putURL *url.URL
var err error var err error
validDesc := (d.Digest != "" && d.Size > 0) || (d.Size == 0 && d.Digest == zeroDig) validDesc := (d.Digest != "" && d.Size > 0) || (d.Size == 0 && d.Digest == zeroDig)
@ -192,7 +193,7 @@ func (reg *Reg) BlobPut(ctx context.Context, r ref.Ref, d types.Descriptor, rdr
if err == nil { if err == nil {
return d, nil return d, nil
} }
if err != types.ErrMountReturnedLocation { if err != errs.ErrMountReturnedLocation {
putURL = nil putURL = nil
} }
} }
@ -289,7 +290,7 @@ func (reg *Reg) blobGetUploadURL(ctx context.Context, r ref.Ref) (*url.URL, erro
// Extract the location into a new putURL based on whether it's relative, fqdn with a scheme, or without a scheme. // Extract the location into a new putURL based on whether it's relative, fqdn with a scheme, or without a scheme.
location := resp.HTTPResponse().Header.Get("Location") location := resp.HTTPResponse().Header.Get("Location")
if location == "" { if location == "" {
return nil, fmt.Errorf("failed to send blob post, ref %s: %w", r.CommonName(), types.ErrMissingLocation) return nil, fmt.Errorf("failed to send blob post, ref %s: %w", r.CommonName(), errs.ErrMissingLocation)
} }
reg.log.WithFields(logrus.Fields{ reg.log.WithFields(logrus.Fields{
"location": location, "location": location,
@ -307,7 +308,7 @@ func (reg *Reg) blobGetUploadURL(ctx context.Context, r ref.Ref) (*url.URL, erro
return putURL, nil return putURL, nil
} }
func (reg *Reg) blobMount(ctx context.Context, rTgt ref.Ref, d types.Descriptor, rSrc ref.Ref) (*url.URL, string, error) { func (reg *Reg) blobMount(ctx context.Context, rTgt ref.Ref, d descriptor.Descriptor, rSrc ref.Ref) (*url.URL, string, error) {
// build/send request // build/send request
query := url.Values{} query := url.Values{}
query.Set("mount", d.Digest.String()) query.Set("mount", d.Digest.String())
@ -378,14 +379,14 @@ func (reg *Reg) blobMount(ctx context.Context, rTgt ref.Ref, d types.Descriptor,
"err": err, "err": err,
}).Warn("Mount location header failed to parse") }).Warn("Mount location header failed to parse")
} else { } else {
return putURL, uuid, types.ErrMountReturnedLocation return putURL, uuid, errs.ErrMountReturnedLocation
} }
} }
// all other responses unhandled // all other responses unhandled
return nil, "", fmt.Errorf("failed to mount blob, digest %s, ref %s: %w", d.Digest.String(), rTgt.CommonName(), reghttp.HTTPError(resp.HTTPResponse().StatusCode)) return nil, "", fmt.Errorf("failed to mount blob, digest %s, ref %s: %w", d.Digest.String(), rTgt.CommonName(), reghttp.HTTPError(resp.HTTPResponse().StatusCode))
} }
func (reg *Reg) blobPutUploadFull(ctx context.Context, r ref.Ref, d types.Descriptor, putURL *url.URL, rdr io.Reader) error { func (reg *Reg) blobPutUploadFull(ctx context.Context, r ref.Ref, d descriptor.Descriptor, putURL *url.URL, rdr io.Reader) error {
// append digest to request to use the monolithic upload option // append digest to request to use the monolithic upload option
if putURL.RawQuery != "" { if putURL.RawQuery != "" {
putURL.RawQuery = putURL.RawQuery + "&digest=" + url.QueryEscape(d.Digest.String()) putURL.RawQuery = putURL.RawQuery + "&digest=" + url.QueryEscape(d.Digest.String())
@ -400,11 +401,11 @@ func (reg *Reg) blobPutUploadFull(ctx context.Context, r ref.Ref, d types.Descri
if readOnce { if readOnce {
rdrSeek, ok := rdr.(io.ReadSeeker) rdrSeek, ok := rdr.(io.ReadSeeker)
if !ok { if !ok {
return nil, fmt.Errorf("blob source is not a seeker%.0w", types.ErrNotRetryable) return nil, fmt.Errorf("blob source is not a seeker%.0w", errs.ErrNotRetryable)
} }
_, err := rdrSeek.Seek(0, io.SeekStart) _, err := rdrSeek.Seek(0, io.SeekStart)
if err != nil { if err != nil {
return nil, fmt.Errorf("seek on blob source failed: %w%.0w", err, types.ErrNotRetryable) return nil, fmt.Errorf("seek on blob source failed: %w%.0w", err, errs.ErrNotRetryable)
} }
} }
readOnce = true readOnce = true
@ -445,7 +446,7 @@ func (reg *Reg) blobPutUploadFull(ctx context.Context, r ref.Ref, d types.Descri
return nil return nil
} }
func (reg *Reg) blobPutUploadChunked(ctx context.Context, r ref.Ref, d types.Descriptor, putURL *url.URL, rdr io.Reader) (types.Descriptor, error) { func (reg *Reg) blobPutUploadChunked(ctx context.Context, r ref.Ref, d descriptor.Descriptor, putURL *url.URL, rdr io.Reader) (descriptor.Descriptor, error) {
host := reg.hostGet(r.Registry) host := reg.hostGet(r.Registry)
bufSize := host.BlobChunk bufSize := host.BlobChunk
if bufSize <= 0 { if bufSize <= 0 {
@ -534,7 +535,7 @@ func (reg *Reg) blobPutUploadChunked(ctx context.Context, r ref.Ref, d types.Des
NoMirrors: true, NoMirrors: true,
} }
resp, err := reg.reghttp.Do(ctx, req) resp, err := reg.reghttp.Do(ctx, req)
if err != nil && !errors.Is(err, types.ErrHTTPStatus) && !errors.Is(err, types.ErrNotFound) { if err != nil && !errors.Is(err, errs.ErrHTTPStatus) && !errors.Is(err, errs.ErrNotFound) {
return d, fmt.Errorf("failed to send blob (chunk), ref %s: http do: %w", r.CommonName(), err) return d, fmt.Errorf("failed to send blob (chunk), ref %s: http do: %w", r.CommonName(), err)
} }
err = resp.Close() err = resp.Close()
@ -596,10 +597,10 @@ func (reg *Reg) blobPutUploadChunked(ctx context.Context, r ref.Ref, d types.Des
// compute digest // compute digest
dOut := digester.Digest() dOut := digester.Digest()
if d.Digest != "" && dOut != d.Digest { if d.Digest != "" && dOut != d.Digest {
return d, fmt.Errorf("%w, expected %s, computed %s", types.ErrDigestMismatch, d.Digest.String(), dOut.String()) return d, fmt.Errorf("%w, expected %s, computed %s", errs.ErrDigestMismatch, d.Digest.String(), dOut.String())
} }
if d.Size != 0 && chunkStart != d.Size { if d.Size != 0 && chunkStart != d.Size {
return d, fmt.Errorf("blob content size does not match descriptor, expected %d, received %d%.0w", d.Size, chunkStart, types.ErrMismatch) return d, fmt.Errorf("blob content size does not match descriptor, expected %d, received %d%.0w", d.Size, chunkStart, errs.ErrMismatch)
} }
d.Digest = dOut d.Digest = dOut
d.Size = chunkStart d.Size = chunkStart

View File

@ -19,7 +19,8 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/reqresp" "github.com/regclient/regclient/internal/reqresp"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -237,7 +238,7 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := reg.BlobGet(ctx, r, types.Descriptor{Digest: d1}) br, err := reg.BlobGet(ctx, r, descriptor.Descriptor{Digest: d1})
if err != nil { if err != nil {
t.Fatalf("Failed running BlobGet: %v", err) t.Fatalf("Failed running BlobGet: %v", err)
} }
@ -256,7 +257,7 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := reg.BlobHead(ctx, r, types.Descriptor{Digest: d1}) br, err := reg.BlobHead(ctx, r, descriptor.Descriptor{Digest: d1})
if err != nil { if err != nil {
t.Fatalf("Failed running BlobHead: %v", err) t.Fatalf("Failed running BlobHead: %v", err)
} }
@ -272,7 +273,7 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := reg.BlobGet(ctx, r, types.Descriptor{Digest: d1, URLs: []string{tsURL.Scheme + "://" + tsURL.Host + "/external/" + d1.String()}}) br, err := reg.BlobGet(ctx, r, descriptor.Descriptor{Digest: d1, URLs: []string{tsURL.Scheme + "://" + tsURL.Host + "/external/" + d1.String()}})
if err != nil { if err != nil {
t.Fatalf("Failed running external BlobGet: %v", err) t.Fatalf("Failed running external BlobGet: %v", err)
} }
@ -291,7 +292,7 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := reg.BlobHead(ctx, r, types.Descriptor{Digest: d1, URLs: []string{tsURL.Scheme + "://" + tsURL.Host + "/external/" + d1.String()}}) br, err := reg.BlobHead(ctx, r, descriptor.Descriptor{Digest: d1, URLs: []string{tsURL.Scheme + "://" + tsURL.Host + "/external/" + d1.String()}})
if err != nil { if err != nil {
t.Fatalf("Failed running external BlobHead: %v", err) t.Fatalf("Failed running external BlobHead: %v", err)
} }
@ -306,12 +307,12 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := reg.BlobGet(ctx, r, types.Descriptor{Digest: dMissing}) br, err := reg.BlobGet(ctx, r, descriptor.Descriptor{Digest: dMissing})
if err == nil { if err == nil {
defer br.Close() defer br.Close()
t.Fatalf("Unexpected success running BlobGet") t.Fatalf("Unexpected success running BlobGet")
} }
if !errors.Is(err, types.ErrNotFound) { if !errors.Is(err, errs.ErrNotFound) {
t.Errorf("Error does not match \"ErrNotFound\": %v", err) t.Errorf("Error does not match \"ErrNotFound\": %v", err)
} }
}) })
@ -321,7 +322,7 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := reg.BlobGet(ctx, r, types.Descriptor{Digest: d2}) br, err := reg.BlobGet(ctx, r, descriptor.Descriptor{Digest: d2})
if err != nil { if err != nil {
t.Fatalf("Failed running BlobGet: %v", err) t.Fatalf("Failed running BlobGet: %v", err)
} }
@ -340,12 +341,12 @@ func TestBlobGet(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br, err := reg.BlobGet(ctx, r, types.Descriptor{Digest: d1}) br, err := reg.BlobGet(ctx, r, descriptor.Descriptor{Digest: d1})
if err == nil { if err == nil {
defer br.Close() defer br.Close()
t.Fatalf("Unexpected success running BlobGet") t.Fatalf("Unexpected success running BlobGet")
} }
if !errors.Is(err, types.ErrHTTPUnauthorized) { if !errors.Is(err, errs.ErrHTTPUnauthorized) {
t.Errorf("Error does not match \"ErrUnauthorized\": %v", err) t.Errorf("Error does not match \"ErrUnauthorized\": %v", err)
} }
}) })
@ -1196,7 +1197,7 @@ func TestBlobPut(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br := bytes.NewReader(blob1) br := bytes.NewReader(blob1)
dp, err := reg.BlobPut(ctx, r, types.Descriptor{Digest: d1, Size: int64(len(blob1))}, br) dp, err := reg.BlobPut(ctx, r, descriptor.Descriptor{Digest: d1, Size: int64(len(blob1))}, br)
if err != nil { if err != nil {
t.Fatalf("Failed running BlobPut: %v", err) t.Fatalf("Failed running BlobPut: %v", err)
} }
@ -1215,7 +1216,7 @@ func TestBlobPut(t *testing.T) {
} }
br := bytes.NewReader(blob2) br := bytes.NewReader(blob2)
mt := "application/vnd.example.test" mt := "application/vnd.example.test"
dp, err := reg.BlobPut(ctx, r, types.Descriptor{MediaType: mt, Digest: d2, Size: int64(len(blob2))}, br) dp, err := reg.BlobPut(ctx, r, descriptor.Descriptor{MediaType: mt, Digest: d2, Size: int64(len(blob2))}, br)
if err != nil { if err != nil {
t.Fatalf("Failed running BlobPut: %v", err) t.Fatalf("Failed running BlobPut: %v", err)
} }
@ -1236,12 +1237,12 @@ func TestBlobPut(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br := bytes.NewReader(blob2) br := bytes.NewReader(blob2)
_, err = reg.BlobPut(ctx, r, types.Descriptor{Digest: d2, Size: int64(len(blob2))}, io.NopCloser(br)) _, err = reg.BlobPut(ctx, r, descriptor.Descriptor{Digest: d2, Size: int64(len(blob2))}, io.NopCloser(br))
if err == nil { if err == nil {
t.Fatalf("Blob put succeeded on a gateway timeout") t.Fatalf("Blob put succeeded on a gateway timeout")
} }
if !errors.Is(err, types.ErrHTTPStatus) { if !errors.Is(err, errs.ErrHTTPStatus) {
t.Errorf("unexpected err, expected %v, received %v", types.ErrHTTPStatus, err) t.Errorf("unexpected err, expected %v, received %v", errs.ErrHTTPStatus, err)
} }
}) })
@ -1252,9 +1253,9 @@ func TestBlobPut(t *testing.T) {
} }
br := bytes.NewReader(blob2) br := bytes.NewReader(blob2)
mt := "application/vnd.example.test" mt := "application/vnd.example.test"
_, err = reg.BlobPut(ctx, r, types.Descriptor{MediaType: mt, Digest: d2Bad, Size: int64(len(blob2))}, br) _, err = reg.BlobPut(ctx, r, descriptor.Descriptor{MediaType: mt, Digest: d2Bad, Size: int64(len(blob2))}, br)
if err == nil || !errors.Is(err, types.ErrDigestMismatch) { if err == nil || !errors.Is(err, errs.ErrDigestMismatch) {
t.Errorf("unexpected error, expected %v, received %v", types.ErrDigestMismatch, err) t.Errorf("unexpected error, expected %v, received %v", errs.ErrDigestMismatch, err)
} }
}) })
@ -1265,9 +1266,9 @@ func TestBlobPut(t *testing.T) {
} }
br := bytes.NewReader(blob2) br := bytes.NewReader(blob2)
mt := "application/vnd.example.test" mt := "application/vnd.example.test"
_, err = reg.BlobPut(ctx, r, types.Descriptor{MediaType: mt, Digest: d2, Size: int64(len(blob2) - 2)}, br) _, err = reg.BlobPut(ctx, r, descriptor.Descriptor{MediaType: mt, Digest: d2, Size: int64(len(blob2) - 2)}, br)
if err == nil || !errors.Is(err, types.ErrMismatch) { if err == nil || !errors.Is(err, errs.ErrMismatch) {
t.Errorf("unexpected error, expected %v, received %v", types.ErrMismatch, err) t.Errorf("unexpected error, expected %v, received %v", errs.ErrMismatch, err)
} }
}) })
@ -1277,7 +1278,7 @@ func TestBlobPut(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br := bytes.NewReader(blob3) br := bytes.NewReader(blob3)
dp, err := reg.BlobPut(ctx, r, types.Descriptor{Digest: d3, Size: int64(len(blob3))}, br) dp, err := reg.BlobPut(ctx, r, descriptor.Descriptor{Digest: d3, Size: int64(len(blob3))}, br)
if err != nil { if err != nil {
t.Fatalf("Failed running BlobPut: %v", err) t.Fatalf("Failed running BlobPut: %v", err)
} }
@ -1295,7 +1296,7 @@ func TestBlobPut(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br := bytes.NewReader(blob4) br := bytes.NewReader(blob4)
dp, err := reg.BlobPut(ctx, r, types.Descriptor{Digest: d4, Size: int64(len(blob4))}, br) dp, err := reg.BlobPut(ctx, r, descriptor.Descriptor{Digest: d4, Size: int64(len(blob4))}, br)
if err != nil { if err != nil {
t.Fatalf("Failed running BlobPut: %v", err) t.Fatalf("Failed running BlobPut: %v", err)
} }
@ -1314,7 +1315,7 @@ func TestBlobPut(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br := bytes.NewReader(blob5) br := bytes.NewReader(blob5)
dp, err := reg.BlobPut(ctx, r, types.Descriptor{}, br) dp, err := reg.BlobPut(ctx, r, descriptor.Descriptor{}, br)
if err != nil { if err != nil {
t.Fatalf("Failed running BlobPut: %v", err) t.Fatalf("Failed running BlobPut: %v", err)
} }
@ -1333,7 +1334,7 @@ func TestBlobPut(t *testing.T) {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
br := bytes.NewReader(blob6) br := bytes.NewReader(blob6)
dp, err := reg.BlobPut(ctx, r, types.Descriptor{Digest: d6, Size: int64(len(blob6))}, br) dp, err := reg.BlobPut(ctx, r, descriptor.Descriptor{Digest: d6, Size: int64(len(blob6))}, br)
if err != nil { if err != nil {
t.Fatalf("Failed running BlobPut: %v", err) t.Fatalf("Failed running BlobPut: %v", err)
} }

View File

@ -13,8 +13,9 @@ import (
"github.com/regclient/regclient/internal/limitread" "github.com/regclient/regclient/internal/limitread"
"github.com/regclient/regclient/internal/reghttp" "github.com/regclient/regclient/internal/reghttp"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -22,7 +23,7 @@ import (
// This will implicitly delete all tags pointing to that manifest. // This will implicitly delete all tags pointing to that manifest.
func (reg *Reg) ManifestDelete(ctx context.Context, r ref.Ref, opts ...scheme.ManifestOpts) error { func (reg *Reg) ManifestDelete(ctx context.Context, r ref.Ref, opts ...scheme.ManifestOpts) error {
if r.Digest == "" { if r.Digest == "" {
return fmt.Errorf("digest required to delete manifest, reference %s%.0w", r.CommonName(), types.ErrMissingDigest) return fmt.Errorf("digest required to delete manifest, reference %s%.0w", r.CommonName(), errs.ErrMissingDigest)
} }
mc := scheme.ManifestConfig{} mc := scheme.ManifestConfig{}
@ -43,7 +44,7 @@ func (reg *Reg) ManifestDelete(ctx context.Context, r ref.Ref, opts ...scheme.Ma
if err == nil && sDesc != nil && sDesc.MediaType != "" && sDesc.Size > 0 { if err == nil && sDesc != nil && sDesc.MediaType != "" && sDesc.Size > 0 {
// attempt to delete the referrer, but ignore if the referrer entry wasn't found // attempt to delete the referrer, but ignore if the referrer entry wasn't found
err = reg.referrerDelete(ctx, r, mc.Manifest) err = reg.referrerDelete(ctx, r, mc.Manifest)
if err != nil && !errors.Is(err, types.ErrNotFound) { if err != nil && !errors.Is(err, errs.ErrNotFound) {
return err return err
} }
} }
@ -88,19 +89,19 @@ func (reg *Reg) ManifestGet(ctx context.Context, r ref.Ref) (manifest.Manifest,
} else if r.Tag != "" { } else if r.Tag != "" {
tagOrDigest = r.Tag tagOrDigest = r.Tag
} else { } else {
return nil, fmt.Errorf("reference missing tag and digest: %s%.0w", r.CommonName(), types.ErrMissingTagOrDigest) return nil, fmt.Errorf("reference missing tag and digest: %s%.0w", r.CommonName(), errs.ErrMissingTagOrDigest)
} }
// build/send request // build/send request
headers := http.Header{ headers := http.Header{
"Accept": []string{ "Accept": []string{
types.MediaTypeOCI1ManifestList, mediatype.OCI1ManifestList,
types.MediaTypeOCI1Manifest, mediatype.OCI1Manifest,
types.MediaTypeDocker2ManifestList, mediatype.Docker2ManifestList,
types.MediaTypeDocker2Manifest, mediatype.Docker2Manifest,
types.MediaTypeDocker1ManifestSigned, mediatype.Docker1ManifestSigned,
types.MediaTypeDocker1Manifest, mediatype.Docker1Manifest,
types.MediaTypeOCI1Artifact, mediatype.OCI1Artifact,
}, },
} }
req := &reghttp.Req{ req := &reghttp.Req{
@ -126,7 +127,7 @@ func (reg *Reg) ManifestGet(ctx context.Context, r ref.Ref) (manifest.Manifest,
// limit length // limit length
size, _ := strconv.Atoi(resp.HTTPResponse().Header.Get("Content-Length")) size, _ := strconv.Atoi(resp.HTTPResponse().Header.Get("Content-Length"))
if size > 0 && reg.manifestMaxPull > 0 && int64(size) > reg.manifestMaxPull { if size > 0 && reg.manifestMaxPull > 0 && int64(size) > reg.manifestMaxPull {
return nil, fmt.Errorf("manifest too large, received %d, limit %d: %s%.0w", size, reg.manifestMaxPull, r.CommonName(), types.ErrSizeLimitExceeded) return nil, fmt.Errorf("manifest too large, received %d, limit %d: %s%.0w", size, reg.manifestMaxPull, r.CommonName(), errs.ErrSizeLimitExceeded)
} }
rdr := &limitread.LimitRead{ rdr := &limitread.LimitRead{
Reader: resp, Reader: resp,
@ -165,19 +166,19 @@ func (reg *Reg) ManifestHead(ctx context.Context, r ref.Ref) (manifest.Manifest,
} else if r.Tag != "" { } else if r.Tag != "" {
tagOrDigest = r.Tag tagOrDigest = r.Tag
} else { } else {
return nil, fmt.Errorf("reference missing tag and digest: %s%.0w", r.CommonName(), types.ErrMissingTagOrDigest) return nil, fmt.Errorf("reference missing tag and digest: %s%.0w", r.CommonName(), errs.ErrMissingTagOrDigest)
} }
// build/send request // build/send request
headers := http.Header{ headers := http.Header{
"Accept": []string{ "Accept": []string{
types.MediaTypeOCI1ManifestList, mediatype.OCI1ManifestList,
types.MediaTypeOCI1Manifest, mediatype.OCI1Manifest,
types.MediaTypeDocker2ManifestList, mediatype.Docker2ManifestList,
types.MediaTypeDocker2Manifest, mediatype.Docker2Manifest,
types.MediaTypeDocker1ManifestSigned, mediatype.Docker1ManifestSigned,
types.MediaTypeDocker1Manifest, mediatype.Docker1Manifest,
types.MediaTypeOCI1Artifact, mediatype.OCI1Artifact,
}, },
} }
req := &reghttp.Req{ req := &reghttp.Req{
@ -217,7 +218,7 @@ func (reg *Reg) ManifestPut(ctx context.Context, r ref.Ref, m manifest.Manifest,
reg.log.WithFields(logrus.Fields{ reg.log.WithFields(logrus.Fields{
"ref": r.Reference, "ref": r.Reference,
}).Warn("Manifest put requires a tag") }).Warn("Manifest put requires a tag")
return types.ErrMissingTag return errs.ErrMissingTag
} }
// create the request body // create the request body
@ -232,7 +233,7 @@ func (reg *Reg) ManifestPut(ctx context.Context, r ref.Ref, m manifest.Manifest,
// limit length // limit length
if reg.manifestMaxPush > 0 && int64(len(mj)) > reg.manifestMaxPush { if reg.manifestMaxPush > 0 && int64(len(mj)) > reg.manifestMaxPush {
return fmt.Errorf("manifest too large, calculated %d, limit %d: %s%.0w", len(mj), reg.manifestMaxPush, r.CommonName(), types.ErrSizeLimitExceeded) return fmt.Errorf("manifest too large, calculated %d, limit %d: %s%.0w", len(mj), reg.manifestMaxPush, r.CommonName(), errs.ErrSizeLimitExceeded)
} }
// build/send request // build/send request

View File

@ -18,9 +18,11 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/reqresp" "github.com/regclient/regclient/internal/reqresp"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -37,14 +39,14 @@ func TestManifest(t *testing.T) {
digest1 := digest.FromString("example1") digest1 := digest.FromString("example1")
digest2 := digest.FromString("example2") digest2 := digest.FromString("example2")
m := schema2.Manifest{ m := schema2.Manifest{
Config: types.Descriptor{ Config: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2ImageConfig, MediaType: mediatype.Docker2ImageConfig,
Size: 8, Size: 8,
Digest: digest1, Digest: digest1,
}, },
Layers: []types.Descriptor{ Layers: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeDocker2LayerGzip, MediaType: mediatype.Docker2LayerGzip,
Size: 8, Size: 8,
Digest: digest2, Digest: digest2,
}, },
@ -68,7 +70,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -84,7 +86,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -100,7 +102,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
}, },
@ -115,7 +117,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
}, },
@ -130,7 +132,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -146,7 +148,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen+defaultManifestMaxPull)}, "Content-Length": {fmt.Sprintf("%d", mLen+defaultManifestMaxPull)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -162,7 +164,7 @@ func TestManifest(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen+10)}, "Content-Length": {fmt.Sprintf("%d", mLen+10)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -184,7 +186,7 @@ func TestManifest(t *testing.T) {
Method: "PUT", Method: "PUT",
Path: "/v2" + repoPath + "/manifests/" + putTag, Path: "/v2" + repoPath + "/manifests/" + putTag,
Headers: http.Header{ Headers: http.Header{
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
}, },
Body: mBody, Body: mBody,
@ -254,7 +256,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestGet: %v", err) t.Fatalf("Failed running ManifestGet: %v", err)
} }
if manifest.GetMediaType(mGet) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mGet) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mGet)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mGet))
} }
if mGet.GetDescriptor().Digest != mDigest { if mGet.GetDescriptor().Digest != mDigest {
@ -270,7 +272,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestHead: %v", err) t.Fatalf("Failed running ManifestHead: %v", err)
} }
if manifest.GetMediaType(mHead) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mHead) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mHead)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mHead))
} }
if mHead.GetDescriptor().Digest != mDigest { if mHead.GetDescriptor().Digest != mDigest {
@ -285,8 +287,8 @@ func TestManifest(t *testing.T) {
mNohead, err := reg.ManifestHead(ctx, noheadRef) mNohead, err := reg.ManifestHead(ctx, noheadRef)
if err == nil { if err == nil {
t.Errorf("Unexpected successful head on \"no head\" registry: %v", mNohead) t.Errorf("Unexpected successful head on \"no head\" registry: %v", mNohead)
} else if !errors.Is(err, types.ErrUnsupportedAPI) { } else if !errors.Is(err, errs.ErrUnsupportedAPI) {
t.Errorf("Expected error, expected %v, received %v", types.ErrUnsupportedAPI, err) t.Errorf("Expected error, expected %v, received %v", errs.ErrUnsupportedAPI, err)
} }
}) })
t.Run("Get No Head", func(t *testing.T) { t.Run("Get No Head", func(t *testing.T) {
@ -298,7 +300,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestGet: %v", err) t.Fatalf("Failed running ManifestGet: %v", err)
} }
if manifest.GetMediaType(mNohead) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mNohead) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mNohead)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mNohead))
} }
if mNohead.GetDescriptor().Digest != mDigest { if mNohead.GetDescriptor().Digest != mDigest {
@ -324,7 +326,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestGet: %v", err) t.Fatalf("Failed running ManifestGet: %v", err)
} }
if manifest.GetMediaType(mGet) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mGet) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mGet)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mGet))
} }
if mGet.GetDescriptor().Digest != mDigest { if mGet.GetDescriptor().Digest != mDigest {
@ -340,7 +342,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestHead: %v", err) t.Fatalf("Failed running ManifestHead: %v", err)
} }
if manifest.GetMediaType(mHead) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mHead) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mHead)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mHead))
} }
if mHead.GetDescriptor().Digest != mDigest { if mHead.GetDescriptor().Digest != mDigest {
@ -356,7 +358,7 @@ func TestManifest(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed running ManifestGet: %v", err) t.Fatalf("Failed running ManifestGet: %v", err)
} }
if manifest.GetMediaType(mGet) != types.MediaTypeDocker2Manifest { if manifest.GetMediaType(mGet) != mediatype.Docker2Manifest {
t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mGet)) t.Errorf("Unexpected media type: %s", manifest.GetMediaType(mGet))
} }
if mGet.GetDescriptor().Digest != mDigest { if mGet.GetDescriptor().Digest != mDigest {
@ -381,8 +383,8 @@ func TestManifest(t *testing.T) {
if err == nil { if err == nil {
t.Fatalf("ManifestGet did not fail") t.Fatalf("ManifestGet did not fail")
} }
if !errors.Is(err, types.ErrSizeLimitExceeded) { if !errors.Is(err, errs.ErrSizeLimitExceeded) {
t.Fatalf("unexpected error, expected %v, received %v", types.ErrSizeLimitExceeded, err) t.Fatalf("unexpected error, expected %v, received %v", errs.ErrSizeLimitExceeded, err)
} }
}) })
t.Run("Read beyond size", func(t *testing.T) { t.Run("Read beyond size", func(t *testing.T) {
@ -394,8 +396,8 @@ func TestManifest(t *testing.T) {
if err == nil { if err == nil {
t.Fatalf("ManifestGet did not fail") t.Fatalf("ManifestGet did not fail")
} }
if !errors.Is(err, types.ErrShortRead) && !errors.Is(err, io.ErrUnexpectedEOF) { if !errors.Is(err, errs.ErrShortRead) && !errors.Is(err, io.ErrUnexpectedEOF) {
t.Fatalf("unexpected error, expected %v, received %v", types.ErrShortRead, err) t.Fatalf("unexpected error, expected %v, received %v", errs.ErrShortRead, err)
} }
}) })
@ -431,8 +433,8 @@ func TestManifest(t *testing.T) {
if err == nil { if err == nil {
t.Fatalf("put manifest did not fail") t.Fatalf("put manifest did not fail")
} }
if !errors.Is(err, types.ErrSizeLimitExceeded) { if !errors.Is(err, errs.ErrSizeLimitExceeded) {
t.Errorf("unexpected error, expected %v, received %v", types.ErrSizeLimitExceeded, err) t.Errorf("unexpected error, expected %v, received %v", errs.ErrSizeLimitExceeded, err)
} }
}) })
} }

View File

@ -15,7 +15,7 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/reqresp" "github.com/regclient/regclient/internal/reqresp"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -146,8 +146,8 @@ func TestPing(t *testing.T) {
result, err := reg.Ping(ctx, r) result, err := reg.Ping(ctx, r)
if err == nil { if err == nil {
t.Fatalf("ping did not fail") t.Fatalf("ping did not fail")
} else if !errors.Is(err, types.ErrHTTPUnauthorized) { } else if !errors.Is(err, errs.ErrHTTPUnauthorized) {
t.Fatalf("unexpected error, expected %v, received %v", types.ErrHTTPUnauthorized, err) t.Fatalf("unexpected error, expected %v, received %v", errs.ErrHTTPUnauthorized, err)
} }
if result.Header == nil { if result.Header == nil {
t.Errorf("headers missing") t.Errorf("headers missing")
@ -163,8 +163,8 @@ func TestPing(t *testing.T) {
result, err := reg.Ping(ctx, r) result, err := reg.Ping(ctx, r)
if err == nil { if err == nil {
t.Fatalf("ping did not fail") t.Fatalf("ping did not fail")
} else if !errors.Is(err, types.ErrNotFound) { } else if !errors.Is(err, errs.ErrNotFound) {
t.Fatalf("unexpected error, expected %v, received %v", types.ErrNotFound, err) t.Fatalf("unexpected error, expected %v, received %v", errs.ErrNotFound, err)
} }
if result.Header == nil { if result.Header == nil {
t.Errorf("headers missing") t.Errorf("headers missing")

View File

@ -10,8 +10,9 @@ import (
"github.com/regclient/regclient/internal/httplink" "github.com/regclient/regclient/internal/httplink"
"github.com/regclient/regclient/internal/reghttp" "github.com/regclient/regclient/internal/reghttp"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -203,7 +204,7 @@ func (reg *Reg) referrerListByAPIPage(ctx context.Context, r ref.Ref, config sch
} }
ociML, ok := m.GetOrig().(v1.Index) ociML, ok := m.GetOrig().(v1.Index)
if !ok { if !ok {
return rl, nil, fmt.Errorf("unexpected manifest type for referrers: %s, %w", m.GetDescriptor().MediaType, types.ErrUnsupportedMediaType) return rl, nil, fmt.Errorf("unexpected manifest type for referrers: %s, %w", m.GetDescriptor().MediaType, errs.ErrUnsupportedMediaType)
} }
rl.Manifest = m rl.Manifest = m
rl.Descriptors = ociML.Manifests rl.Descriptors = ociML.Manifests
@ -223,11 +224,11 @@ func (reg *Reg) referrerListByTag(ctx context.Context, r ref.Ref) (referrer.Refe
} }
m, err := reg.ManifestGet(ctx, rlTag) m, err := reg.ManifestGet(ctx, rlTag)
if err != nil { if err != nil {
if errors.Is(err, types.ErrNotFound) { if errors.Is(err, errs.ErrNotFound) {
// empty list, initialize a new manifest // empty list, initialize a new manifest
rl.Manifest, err = manifest.New(manifest.WithOrig(v1.Index{ rl.Manifest, err = manifest.New(manifest.WithOrig(v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
})) }))
if err != nil { if err != nil {
return rl, err return rl, err
@ -253,7 +254,7 @@ func (reg *Reg) referrerDelete(ctx context.Context, r ref.Ref, m manifest.Manife
// get subject field // get subject field
mSubject, ok := m.(manifest.Subjecter) mSubject, ok := m.(manifest.Subjecter)
if !ok { if !ok {
return fmt.Errorf("manifest does not support the subject field: %w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest does not support the subject field: %w", errs.ErrUnsupportedMediaType)
} }
subject, err := mSubject.GetSubject() subject, err := mSubject.GetSubject()
if err != nil { if err != nil {
@ -261,7 +262,7 @@ func (reg *Reg) referrerDelete(ctx context.Context, r ref.Ref, m manifest.Manife
} }
// validate/set subject descriptor // validate/set subject descriptor
if subject == nil || subject.MediaType == "" || subject.Digest == "" || subject.Size <= 0 { if subject == nil || subject.MediaType == "" || subject.Digest == "" || subject.Size <= 0 {
return fmt.Errorf("refers is not set%.0w", types.ErrNotFound) return fmt.Errorf("refers is not set%.0w", errs.ErrNotFound)
} }
// remove from cache // remove from cache
@ -302,7 +303,7 @@ func (reg *Reg) referrerPut(ctx context.Context, r ref.Ref, m manifest.Manifest)
// get subject field // get subject field
mSubject, ok := m.(manifest.Subjecter) mSubject, ok := m.(manifest.Subjecter)
if !ok { if !ok {
return fmt.Errorf("manifest does not support the subject field: %w", types.ErrUnsupportedMediaType) return fmt.Errorf("manifest does not support the subject field: %w", errs.ErrUnsupportedMediaType)
} }
subject, err := mSubject.GetSubject() subject, err := mSubject.GetSubject()
if err != nil { if err != nil {
@ -310,7 +311,7 @@ func (reg *Reg) referrerPut(ctx context.Context, r ref.Ref, m manifest.Manifest)
} }
// validate/set subject descriptor // validate/set subject descriptor
if subject == nil || subject.MediaType == "" || subject.Digest == "" || subject.Size <= 0 { if subject == nil || subject.MediaType == "" || subject.Digest == "" || subject.Size <= 0 {
return fmt.Errorf("subject is not set%.0w", types.ErrNotFound) return fmt.Errorf("subject is not set%.0w", errs.ErrNotFound)
} }
// lock to avoid internal race conditions between pulling and pushing tag // lock to avoid internal race conditions between pulling and pushing tag

View File

@ -17,9 +17,10 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/reqresp" "github.com/regclient/regclient/internal/reqresp"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -43,14 +44,14 @@ func TestReferrer(t *testing.T) {
// manifest being referenced // manifest being referenced
m := schema2.Manifest{ m := schema2.Manifest{
Versioned: schema2.ManifestSchemaVersion, Versioned: schema2.ManifestSchemaVersion,
Config: types.Descriptor{ Config: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2ImageConfig, MediaType: mediatype.Docker2ImageConfig,
Size: 8, Size: 8,
Digest: digest1, Digest: digest1,
}, },
Layers: []types.Descriptor{ Layers: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeDocker2LayerGzip, MediaType: mediatype.Docker2LayerGzip,
Size: 8, Size: 8,
Digest: digest2, Digest: digest2,
}, },
@ -65,9 +66,9 @@ func TestReferrer(t *testing.T) {
// manifest list // manifest list
mList := schema2.ManifestList{ mList := schema2.ManifestList{
Versioned: schema2.ManifestListSchemaVersion, Versioned: schema2.ManifestListSchemaVersion,
Manifests: []types.Descriptor{ Manifests: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Digest: mDigest, Digest: mDigest,
Size: int64(mLen), Size: int64(mLen),
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -76,7 +77,7 @@ func TestReferrer(t *testing.T) {
}, },
}, },
{ {
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Digest: digest.FromString("missing"), Digest: digest.FromString("missing"),
Size: int64(1234), Size: int64(1234),
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -98,22 +99,22 @@ func TestReferrer(t *testing.T) {
} }
artifact := v1.Manifest{ artifact := v1.Manifest{
Versioned: v1.ManifestSchemaVersion, Versioned: v1.ManifestSchemaVersion,
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Config: types.Descriptor{ Config: descriptor.Descriptor{
MediaType: configMTA, MediaType: configMTA,
Size: 8, Size: 8,
Digest: digest1, Digest: digest1,
}, },
Layers: []types.Descriptor{ Layers: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeOCI1LayerGzip, MediaType: mediatype.OCI1LayerGzip,
Size: 8, Size: 8,
Digest: digest2, Digest: digest2,
}, },
}, },
Annotations: artifactAnnot, Annotations: artifactAnnot,
Subject: &types.Descriptor{ Subject: &descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(mLen), Size: int64(mLen),
Digest: mDigest, Digest: mDigest,
}, },
@ -131,18 +132,18 @@ func TestReferrer(t *testing.T) {
extraAnnot: extraValue2, extraAnnot: extraValue2,
} }
artifact2 := v1.ArtifactManifest{ artifact2 := v1.ArtifactManifest{
MediaType: types.MediaTypeOCI1Artifact, MediaType: mediatype.OCI1Artifact,
ArtifactType: configMTB, ArtifactType: configMTB,
Blobs: []types.Descriptor{ Blobs: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeOCI1LayerGzip, MediaType: mediatype.OCI1LayerGzip,
Size: 8, Size: 8,
Digest: digest2, Digest: digest2,
}, },
}, },
Annotations: artifact2Annot, Annotations: artifact2Annot,
Subject: &types.Descriptor{ Subject: &descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(mLen), Size: int64(mLen),
Digest: mDigest, Digest: mDigest,
}, },
@ -159,7 +160,7 @@ func TestReferrer(t *testing.T) {
// empty response // empty response
emptyReply := v1.Index{ emptyReply := v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
} }
emptyBody, err := json.Marshal(emptyReply) emptyBody, err := json.Marshal(emptyReply)
if err != nil { if err != nil {
@ -170,10 +171,10 @@ func TestReferrer(t *testing.T) {
// a response // a response
replyA := v1.Index{ replyA := v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Manifests: []types.Descriptor{ Manifests: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
ArtifactType: configMTA, ArtifactType: configMTA,
Size: int64(len(artifactBody)), Size: int64(len(artifactBody)),
Digest: artifactM.GetDescriptor().Digest, Digest: artifactM.GetDescriptor().Digest,
@ -190,10 +191,10 @@ func TestReferrer(t *testing.T) {
// a response // a response
replyB := v1.Index{ replyB := v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Manifests: []types.Descriptor{ Manifests: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeOCI1Artifact, MediaType: mediatype.OCI1Artifact,
ArtifactType: configMTB, ArtifactType: configMTB,
Size: int64(len(artifact2Body)), Size: int64(len(artifact2Body)),
Digest: artifact2M.GetDescriptor().Digest, Digest: artifact2M.GetDescriptor().Digest,
@ -210,17 +211,17 @@ func TestReferrer(t *testing.T) {
// full response // full response
replyBoth := v1.Index{ replyBoth := v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Manifests: []types.Descriptor{ Manifests: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
ArtifactType: configMTA, ArtifactType: configMTA,
Size: int64(len(artifactBody)), Size: int64(len(artifactBody)),
Digest: artifactM.GetDescriptor().Digest, Digest: artifactM.GetDescriptor().Digest,
Annotations: artifactAnnot, Annotations: artifactAnnot,
}, },
{ {
MediaType: types.MediaTypeOCI1Artifact, MediaType: mediatype.OCI1Artifact,
ArtifactType: configMTB, ArtifactType: configMTB,
Size: int64(len(artifact2Body)), Size: int64(len(artifact2Body)),
Digest: artifact2M.GetDescriptor().Digest, Digest: artifact2M.GetDescriptor().Digest,
@ -249,7 +250,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
}, },
@ -264,7 +265,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mLen)}, "Content-Length": {fmt.Sprintf("%d", mLen)},
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Docker-Content-Digest": []string{mDigest.String()}, "Docker-Content-Digest": []string{mDigest.String()},
}, },
Body: mBody, Body: mBody,
@ -280,7 +281,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mlLen)}, "Content-Length": {fmt.Sprintf("%d", mlLen)},
"Content-Type": []string{types.MediaTypeDocker2ManifestList}, "Content-Type": []string{mediatype.Docker2ManifestList},
"Docker-Content-Digest": []string{mlDigest.String()}, "Docker-Content-Digest": []string{mlDigest.String()},
}, },
}, },
@ -295,7 +296,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", mlLen)}, "Content-Length": {fmt.Sprintf("%d", mlLen)},
"Content-Type": []string{types.MediaTypeDocker2ManifestList}, "Content-Type": []string{mediatype.Docker2ManifestList},
"Docker-Content-Digest": []string{mlDigest.String()}, "Docker-Content-Digest": []string{mlDigest.String()},
}, },
Body: mlBody, Body: mlBody,
@ -312,7 +313,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", len(artifactBody))}, "Content-Length": {fmt.Sprintf("%d", len(artifactBody))},
"Content-Type": []string{types.MediaTypeOCI1Manifest}, "Content-Type": []string{mediatype.OCI1Manifest},
"Docker-Content-Digest": []string{string(artifactDigest)}, "Docker-Content-Digest": []string{string(artifactDigest)},
}, },
Body: artifactBody, Body: artifactBody,
@ -329,7 +330,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", len(artifact2Body))}, "Content-Length": {fmt.Sprintf("%d", len(artifact2Body))},
"Content-Type": []string{types.MediaTypeOCI1Artifact}, "Content-Type": []string{mediatype.OCI1Artifact},
"Docker-Content-Digest": []string{string(artifact2Digest)}, "Docker-Content-Digest": []string{string(artifact2Digest)},
}, },
Body: artifact2Body, Body: artifact2Body,
@ -420,7 +421,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", replyALen)}, "Content-Length": {fmt.Sprintf("%d", replyALen)},
"Content-Type": []string{types.MediaTypeOCI1ManifestList}, "Content-Type": []string{mediatype.OCI1ManifestList},
"Docker-Content-Digest": []string{replyADig.String()}, "Docker-Content-Digest": []string{replyADig.String()},
}, },
Body: replyABody, Body: replyABody,
@ -437,7 +438,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", replyBothLen)}, "Content-Length": {fmt.Sprintf("%d", replyBothLen)},
"Content-Type": []string{types.MediaTypeOCI1ManifestList}, "Content-Type": []string{mediatype.OCI1ManifestList},
"Docker-Content-Digest": []string{replyBothDig.String()}, "Docker-Content-Digest": []string{replyBothDig.String()},
}, },
Body: replyBothBody, Body: replyBothBody,
@ -528,7 +529,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", replyALen)}, "Content-Length": {fmt.Sprintf("%d", replyALen)},
"Content-Type": []string{types.MediaTypeOCI1ManifestList}, "Content-Type": []string{mediatype.OCI1ManifestList},
"Docker-Content-Digest": []string{replyADig.String()}, "Docker-Content-Digest": []string{replyADig.String()},
}, },
Body: replyABody, Body: replyABody,
@ -545,7 +546,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", replyBothLen)}, "Content-Length": {fmt.Sprintf("%d", replyBothLen)},
"Content-Type": []string{types.MediaTypeOCI1ManifestList}, "Content-Type": []string{mediatype.OCI1ManifestList},
"Docker-Content-Digest": []string{replyBothDig.String()}, "Docker-Content-Digest": []string{replyBothDig.String()},
}, },
Body: replyBothBody, Body: replyBothBody,
@ -646,7 +647,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", emptyLen)}, "Content-Length": {fmt.Sprintf("%d", emptyLen)},
"Content-Type": []string{types.MediaTypeOCI1ManifestList}, "Content-Type": []string{mediatype.OCI1ManifestList},
"Docker-Content-Digest": []string{emptyDigest.String()}, "Docker-Content-Digest": []string{emptyDigest.String()},
}, },
Body: emptyBody, Body: emptyBody,
@ -663,7 +664,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", replyALen)}, "Content-Length": {fmt.Sprintf("%d", replyALen)},
"Content-Type": []string{types.MediaTypeOCI1ManifestList}, "Content-Type": []string{mediatype.OCI1ManifestList},
"Docker-Content-Digest": []string{replyADig.String()}, "Docker-Content-Digest": []string{replyADig.String()},
}, },
Body: replyABody, Body: replyABody,
@ -683,7 +684,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", replyBLen)}, "Content-Length": {fmt.Sprintf("%d", replyBLen)},
"Content-Type": []string{types.MediaTypeOCI1ManifestList}, "Content-Type": []string{mediatype.OCI1ManifestList},
"Docker-Content-Digest": []string{replyBDig.String()}, "Docker-Content-Digest": []string{replyBDig.String()},
}, },
Body: replyBBody, Body: replyBBody,
@ -700,7 +701,7 @@ func TestReferrer(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", replyALen)}, "Content-Length": {fmt.Sprintf("%d", replyALen)},
"Content-Type": []string{types.MediaTypeOCI1ManifestList}, "Content-Type": []string{mediatype.OCI1ManifestList},
"Docker-Content-Digest": []string{replyADig.String()}, "Docker-Content-Digest": []string{replyADig.String()},
"Link": []string{fmt.Sprintf(`</v2%s/referrers/%s?next=1>; rel="next"`, repoPath, mDigest.String())}, "Link": []string{fmt.Sprintf(`</v2%s/referrers/%s?next=1>; rel="next"`, repoPath, mDigest.String())},
}, },
@ -848,7 +849,7 @@ func TestReferrer(t *testing.T) {
if len(rl.Descriptors) < 1 { if len(rl.Descriptors) < 1 {
t.Fatalf("descriptor list missing") t.Fatalf("descriptor list missing")
} }
if rl.Descriptors[0].MediaType != types.MediaTypeOCI1Manifest || if rl.Descriptors[0].MediaType != mediatype.OCI1Manifest ||
rl.Descriptors[0].Size != int64(len(artifactBody)) || rl.Descriptors[0].Size != int64(len(artifactBody)) ||
rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest || rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest ||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) { !mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
@ -870,7 +871,7 @@ func TestReferrer(t *testing.T) {
if len(rl.Descriptors) < 1 { if len(rl.Descriptors) < 1 {
t.Fatalf("descriptor list missing") t.Fatalf("descriptor list missing")
} }
if rl.Descriptors[0].MediaType != types.MediaTypeOCI1Manifest || if rl.Descriptors[0].MediaType != mediatype.OCI1Manifest ||
rl.Descriptors[0].Size != int64(len(artifactBody)) || rl.Descriptors[0].Size != int64(len(artifactBody)) ||
rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest || rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest ||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) { !mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
@ -892,7 +893,7 @@ func TestReferrer(t *testing.T) {
if len(rl.Descriptors) < 1 { if len(rl.Descriptors) < 1 {
t.Fatalf("descriptor list missing") t.Fatalf("descriptor list missing")
} }
if rl.Descriptors[0].MediaType != types.MediaTypeOCI1Manifest || if rl.Descriptors[0].MediaType != mediatype.OCI1Manifest ||
rl.Descriptors[0].Size != int64(len(artifactBody)) || rl.Descriptors[0].Size != int64(len(artifactBody)) ||
rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest || rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest ||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) { !mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
@ -938,14 +939,14 @@ func TestReferrer(t *testing.T) {
if len(rl.Descriptors) != 2 { if len(rl.Descriptors) != 2 {
t.Fatalf("descriptor list expected 2, received %d", len(rl.Descriptors)) t.Fatalf("descriptor list expected 2, received %d", len(rl.Descriptors))
} }
if rl.Descriptors[0].MediaType != types.MediaTypeOCI1Manifest || if rl.Descriptors[0].MediaType != mediatype.OCI1Manifest ||
rl.Descriptors[0].Size != int64(len(artifactBody)) || rl.Descriptors[0].Size != int64(len(artifactBody)) ||
rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest || rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest ||
rl.Descriptors[0].ArtifactType != configMTA || rl.Descriptors[0].ArtifactType != configMTA ||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) { !mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
t.Errorf("returned descriptor mismatch: %v", rl.Descriptors[0]) t.Errorf("returned descriptor mismatch: %v", rl.Descriptors[0])
} }
if rl.Descriptors[1].MediaType != types.MediaTypeOCI1Artifact || if rl.Descriptors[1].MediaType != mediatype.OCI1Artifact ||
rl.Descriptors[1].Size != int64(len(artifact2Body)) || rl.Descriptors[1].Size != int64(len(artifact2Body)) ||
rl.Descriptors[1].Digest != artifact2M.GetDescriptor().Digest || rl.Descriptors[1].Digest != artifact2M.GetDescriptor().Digest ||
rl.Descriptors[1].ArtifactType != configMTB || rl.Descriptors[1].ArtifactType != configMTB ||
@ -968,14 +969,14 @@ func TestReferrer(t *testing.T) {
if len(rl.Descriptors) != 2 { if len(rl.Descriptors) != 2 {
t.Fatalf("descriptor list expected 2, received %d", len(rl.Descriptors)) t.Fatalf("descriptor list expected 2, received %d", len(rl.Descriptors))
} }
if rl.Descriptors[0].MediaType != types.MediaTypeOCI1Manifest || if rl.Descriptors[0].MediaType != mediatype.OCI1Manifest ||
rl.Descriptors[0].Size != int64(len(artifactBody)) || rl.Descriptors[0].Size != int64(len(artifactBody)) ||
rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest || rl.Descriptors[0].Digest != artifactM.GetDescriptor().Digest ||
rl.Descriptors[0].ArtifactType != configMTA || rl.Descriptors[0].ArtifactType != configMTA ||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) { !mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
t.Errorf("returned descriptor mismatch: %v", rl.Descriptors[0]) t.Errorf("returned descriptor mismatch: %v", rl.Descriptors[0])
} }
if rl.Descriptors[1].MediaType != types.MediaTypeOCI1Artifact || if rl.Descriptors[1].MediaType != mediatype.OCI1Artifact ||
rl.Descriptors[1].Size != int64(len(artifact2Body)) || rl.Descriptors[1].Size != int64(len(artifact2Body)) ||
rl.Descriptors[1].Digest != artifact2M.GetDescriptor().Digest || rl.Descriptors[1].Digest != artifact2M.GetDescriptor().Digest ||
rl.Descriptors[1].ArtifactType != configMTB || rl.Descriptors[1].ArtifactType != configMTB ||
@ -992,14 +993,14 @@ func TestReferrer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
rl, err := reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{ArtifactType: configMTA})) rl, err := reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{ArtifactType: configMTA}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }
if len(rl.Descriptors) != 1 { if len(rl.Descriptors) != 1 {
t.Fatalf("descriptor list mismatch: %v", rl.Descriptors) t.Fatalf("descriptor list mismatch: %v", rl.Descriptors)
} }
rl, err = reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{ArtifactType: "application/vnd.example.unknown"})) rl, err = reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{ArtifactType: "application/vnd.example.unknown"}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }
@ -1012,21 +1013,21 @@ func TestReferrer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("Failed creating ref: %v", err) t.Fatalf("Failed creating ref: %v", err)
} }
rl, err := reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{Annotations: map[string]string{extraAnnot: extraValue2}})) rl, err := reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{Annotations: map[string]string{extraAnnot: extraValue2}}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }
if len(rl.Descriptors) != 1 { if len(rl.Descriptors) != 1 {
t.Fatalf("descriptor list mismatch: %v", rl.Descriptors) t.Fatalf("descriptor list mismatch: %v", rl.Descriptors)
} }
rl, err = reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{Annotations: map[string]string{extraAnnot: "unknown value"}})) rl, err = reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{Annotations: map[string]string{extraAnnot: "unknown value"}}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }
if len(rl.Descriptors) > 0 { if len(rl.Descriptors) > 0 {
t.Fatalf("unexpected descriptors: %v", rl.Descriptors) t.Fatalf("unexpected descriptors: %v", rl.Descriptors)
} }
rl, err = reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(types.MatchOpt{Annotations: map[string]string{extraAnnot: ""}})) rl, err = reg.ReferrerList(ctx, r, scheme.WithReferrerMatchOpt(descriptor.MatchOpt{Annotations: map[string]string{extraAnnot: ""}}))
if err != nil { if err != nil {
t.Fatalf("Failed running ReferrerList: %v", err) t.Fatalf("Failed running ReferrerList: %v", err)
} }

View File

@ -12,7 +12,7 @@ import (
"github.com/regclient/regclient/internal/reghttp" "github.com/regclient/regclient/internal/reghttp"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/repo" "github.com/regclient/regclient/types/repo"
) )
@ -65,7 +65,7 @@ func (reg *Reg) RepoList(ctx context.Context, hostname string, opts ...scheme.Re
}).Warn("Failed to read repo list") }).Warn("Failed to read repo list")
return nil, fmt.Errorf("failed to read repo list for %s: %w", hostname, err) return nil, fmt.Errorf("failed to read repo list for %s: %w", hostname, err)
} }
mt := types.MediaTypeBase(resp.HTTPResponse().Header.Get("Content-Type")) mt := mediatype.Base(resp.HTTPResponse().Header.Get("Content-Type"))
rl, err := repo.New( rl, err := repo.New(
repo.WithMT(mt), repo.WithMT(mt),
repo.WithRaw(respBody), repo.WithRaw(respBody),

View File

@ -17,7 +17,7 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/reqresp" "github.com/regclient/regclient/internal/reqresp"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
func TestRepo(t *testing.T) { func TestRepo(t *testing.T) {
@ -227,8 +227,8 @@ func TestRepo(t *testing.T) {
_, err := reg.RepoList(ctx, host) _, err := reg.RepoList(ctx, host)
if err == nil { if err == nil {
t.Errorf("unexpected success listing repos on disabled registry") t.Errorf("unexpected success listing repos on disabled registry")
} else if !errors.Is(err, types.ErrHTTPStatus) { } else if !errors.Is(err, errs.ErrHTTPStatus) {
t.Errorf("unexpected error: expected %v, received %v", types.ErrHTTPStatus, err) t.Errorf("unexpected error: expected %v, received %v", errs.ErrHTTPStatus, err)
} }
}) })
// test with unknown media-type header // test with unknown media-type header
@ -238,8 +238,8 @@ func TestRepo(t *testing.T) {
_, err := reg.RepoList(ctx, host) _, err := reg.RepoList(ctx, host)
if err == nil { if err == nil {
t.Errorf("unexpected success listing repos on unknown-mt registry") t.Errorf("unexpected success listing repos on unknown-mt registry")
} else if !errors.Is(err, types.ErrUnsupportedMediaType) { } else if !errors.Is(err, errs.ErrUnsupportedMediaType) {
t.Errorf("unexpected error: expected %v, received %v", types.ErrUnsupportedMediaType, err) t.Errorf("unexpected error: expected %v, received %v", errs.ErrUnsupportedMediaType, err)
} }
}) })
// test with parsing errors // test with parsing errors

View File

@ -22,9 +22,11 @@ import (
"github.com/regclient/regclient/internal/httplink" "github.com/regclient/regclient/internal/httplink"
"github.com/regclient/regclient/internal/reghttp" "github.com/regclient/regclient/internal/reghttp"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -37,7 +39,7 @@ import (
func (reg *Reg) TagDelete(ctx context.Context, r ref.Ref) error { func (reg *Reg) TagDelete(ctx context.Context, r ref.Ref) error {
var tempManifest manifest.Manifest var tempManifest manifest.Manifest
if r.Tag == "" { if r.Tag == "" {
return types.ErrMissingTag return errs.ErrMissingTag
} }
// attempt to delete the tag directly, available in OCI distribution-spec, and Hub API // attempt to delete the tag directly, available in OCI distribution-spec, and Hub API
@ -70,7 +72,7 @@ func (reg *Reg) TagDelete(ctx context.Context, r ref.Ref) error {
// lookup the current manifest media type // lookup the current manifest media type
curManifest, err := reg.ManifestHead(ctx, r) curManifest, err := reg.ManifestHead(ctx, r)
if err != nil && errors.Is(err, types.ErrUnsupportedAPI) { if err != nil && errors.Is(err, errs.ErrUnsupportedAPI) {
curManifest, err = reg.ManifestGet(ctx, r) curManifest, err = reg.ManifestGet(ctx, r)
} }
if err != nil { if err != nil {
@ -102,7 +104,7 @@ func (reg *Reg) TagDelete(ctx context.Context, r ref.Ref) error {
RootFS: v1.RootFS{ RootFS: v1.RootFS{
Type: "layers", Type: "layers",
DiffIDs: []digest.Digest{ DiffIDs: []digest.Digest{
types.EmptyDigest, descriptor.EmptyDigest,
}, },
}, },
} }
@ -120,20 +122,20 @@ func (reg *Reg) TagDelete(ctx context.Context, r ref.Ref) error {
// create manifest with config, matching the original tag manifest type // create manifest with config, matching the original tag manifest type
switch manifest.GetMediaType(curManifest) { switch manifest.GetMediaType(curManifest) {
case types.MediaTypeOCI1Manifest, types.MediaTypeOCI1ManifestList: case mediatype.OCI1Manifest, mediatype.OCI1ManifestList:
tempManifest, err = manifest.New(manifest.WithOrig(v1.Manifest{ tempManifest, err = manifest.New(manifest.WithOrig(v1.Manifest{
Versioned: v1.ManifestSchemaVersion, Versioned: v1.ManifestSchemaVersion,
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Config: types.Descriptor{ Config: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ImageConfig, MediaType: mediatype.OCI1ImageConfig,
Digest: confDigest, Digest: confDigest,
Size: int64(len(confB)), Size: int64(len(confB)),
}, },
Layers: []types.Descriptor{ Layers: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeOCI1Layer, MediaType: mediatype.OCI1Layer,
Size: int64(len(types.EmptyData)), Size: int64(len(descriptor.EmptyData)),
Digest: types.EmptyDigest, Digest: descriptor.EmptyDigest,
}, },
}, },
})) }))
@ -143,16 +145,16 @@ func (reg *Reg) TagDelete(ctx context.Context, r ref.Ref) error {
default: // default to the docker v2 schema default: // default to the docker v2 schema
tempManifest, err = manifest.New(manifest.WithOrig(schema2.Manifest{ tempManifest, err = manifest.New(manifest.WithOrig(schema2.Manifest{
Versioned: schema2.ManifestSchemaVersion, Versioned: schema2.ManifestSchemaVersion,
Config: types.Descriptor{ Config: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2ImageConfig, MediaType: mediatype.Docker2ImageConfig,
Digest: confDigest, Digest: confDigest,
Size: int64(len(confB)), Size: int64(len(confB)),
}, },
Layers: []types.Descriptor{ Layers: []descriptor.Descriptor{
{ {
MediaType: types.MediaTypeDocker2LayerGzip, MediaType: mediatype.Docker2LayerGzip,
Size: int64(len(types.EmptyData)), Size: int64(len(descriptor.EmptyData)),
Digest: types.EmptyDigest, Digest: descriptor.EmptyDigest,
}, },
}, },
})) }))
@ -165,13 +167,13 @@ func (reg *Reg) TagDelete(ctx context.Context, r ref.Ref) error {
}).Debug("Sending dummy manifest to replace tag") }).Debug("Sending dummy manifest to replace tag")
// push empty layer // push empty layer
_, err = reg.BlobPut(ctx, r, types.Descriptor{Digest: types.EmptyDigest, Size: int64(len(types.EmptyData))}, bytes.NewReader(types.EmptyData)) _, err = reg.BlobPut(ctx, r, descriptor.Descriptor{Digest: descriptor.EmptyDigest, Size: int64(len(descriptor.EmptyData))}, bytes.NewReader(descriptor.EmptyData))
if err != nil { if err != nil {
return err return err
} }
// push config // push config
_, err = reg.BlobPut(ctx, r, types.Descriptor{Digest: confDigest, Size: int64(len(confB))}, bytes.NewReader(confB)) _, err = reg.BlobPut(ctx, r, descriptor.Descriptor{Digest: confDigest, Size: int64(len(confB))}, bytes.NewReader(confB))
if err != nil { if err != nil {
return fmt.Errorf("failed sending dummy config to delete %s: %w", r.CommonName(), err) return fmt.Errorf("failed sending dummy config to delete %s: %w", r.CommonName(), err)
} }

View File

@ -19,7 +19,8 @@ import (
"github.com/regclient/regclient/config" "github.com/regclient/regclient/config"
"github.com/regclient/regclient/internal/reqresp" "github.com/regclient/regclient/internal/reqresp"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -188,7 +189,7 @@ func TestTag(t *testing.T) {
Status: http.StatusOK, Status: http.StatusOK,
Headers: http.Header{ Headers: http.Header{
"Content-Length": {fmt.Sprintf("%d", len(delFallbackManifest))}, "Content-Length": {fmt.Sprintf("%d", len(delFallbackManifest))},
"Content-Type": {types.MediaTypeDocker2Manifest}, "Content-Type": {mediatype.Docker2Manifest},
"Docker-Content-Digest": {delFallbackDigest.String()}, "Docker-Content-Digest": {delFallbackDigest.String()},
}, },
}, },
@ -229,7 +230,7 @@ func TestTag(t *testing.T) {
Method: "PUT", Method: "PUT",
Path: "/v2" + repoPath + "/manifests/" + delFallbackTag, Path: "/v2" + repoPath + "/manifests/" + delFallbackTag,
Headers: http.Header{ Headers: http.Header{
"Content-Type": {types.MediaTypeDocker2Manifest}, "Content-Type": {mediatype.Docker2Manifest},
}, },
}, },
RespEntry: reqresp.RespEntry{ RespEntry: reqresp.RespEntry{
@ -347,8 +348,8 @@ func TestTag(t *testing.T) {
_, err = reg.TagList(ctx, listRef) _, err = reg.TagList(ctx, listRef)
if err == nil { if err == nil {
t.Fatalf("tag listing succeeded on missing repo") t.Fatalf("tag listing succeeded on missing repo")
} else if !errors.Is(err, types.ErrNotFound) { } else if !errors.Is(err, errs.ErrNotFound) {
t.Fatalf("unexpected error: expected %v, received %v", types.ErrNotFound, err) t.Fatalf("unexpected error: expected %v, received %v", errs.ErrNotFound, err)
} }
}) })

View File

@ -6,8 +6,8 @@ import (
"io" "io"
"github.com/regclient/regclient/internal/throttle" "github.com/regclient/regclient/internal/throttle"
"github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/blob" "github.com/regclient/regclient/types/blob"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/manifest" "github.com/regclient/regclient/types/manifest"
"github.com/regclient/regclient/types/ping" "github.com/regclient/regclient/types/ping"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -18,15 +18,15 @@ import (
// API is used to interface between different methods to store images. // API is used to interface between different methods to store images.
type API interface { type API interface {
// BlobDelete removes a blob from the repository. // BlobDelete removes a blob from the repository.
BlobDelete(ctx context.Context, r ref.Ref, d types.Descriptor) error BlobDelete(ctx context.Context, r ref.Ref, d descriptor.Descriptor) error
// BlobGet retrieves a blob, returning a reader. // BlobGet retrieves a blob, returning a reader.
BlobGet(ctx context.Context, r ref.Ref, d types.Descriptor) (blob.Reader, error) BlobGet(ctx context.Context, r ref.Ref, d descriptor.Descriptor) (blob.Reader, error)
// BlobHead verifies the existence of a blob, the reader contains the headers but no body to read. // BlobHead verifies the existence of a blob, the reader contains the headers but no body to read.
BlobHead(ctx context.Context, r ref.Ref, d types.Descriptor) (blob.Reader, error) BlobHead(ctx context.Context, r ref.Ref, d descriptor.Descriptor) (blob.Reader, error)
// BlobMount attempts to perform a server side copy of the blob. // BlobMount attempts to perform a server side copy of the blob.
BlobMount(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d types.Descriptor) error BlobMount(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d descriptor.Descriptor) error
// BlobPut sends a blob to the repository, returns the digest and size when successful. // BlobPut sends a blob to the repository, returns the digest and size when successful.
BlobPut(ctx context.Context, r ref.Ref, d types.Descriptor, rdr io.Reader) (types.Descriptor, error) BlobPut(ctx context.Context, r ref.Ref, d descriptor.Descriptor, rdr io.Reader) (descriptor.Descriptor, error)
// ManifestDelete removes a manifest, including all tags that point to that manifest. // ManifestDelete removes a manifest, including all tags that point to that manifest.
ManifestDelete(ctx context.Context, r ref.Ref, opts ...ManifestOpts) error ManifestDelete(ctx context.Context, r ref.Ref, opts ...ManifestOpts) error
@ -105,15 +105,15 @@ func WithManifest(m manifest.Manifest) ManifestOpts {
// ReferrerConfig is used by schemes to import [ReferrerOpts]. // ReferrerConfig is used by schemes to import [ReferrerOpts].
type ReferrerConfig struct { type ReferrerConfig struct {
MatchOpt types.MatchOpt // filter/sort results MatchOpt descriptor.MatchOpt // filter/sort results
Platform string // get referrers for a specific platform Platform string // get referrers for a specific platform
} }
// ReferrerOpts is used to set options on referrer APIs. // ReferrerOpts is used to set options on referrer APIs.
type ReferrerOpts func(*ReferrerConfig) type ReferrerOpts func(*ReferrerConfig)
// WithReferrerMatchOpt filters results using [types.MatchOpt]. // WithReferrerMatchOpt filters results using [descriptor.MatchOpt].
func WithReferrerMatchOpt(mo types.MatchOpt) ReferrerOpts { func WithReferrerMatchOpt(mo descriptor.MatchOpt) ReferrerOpts {
return func(config *ReferrerConfig) { return func(config *ReferrerConfig) {
config.MatchOpt = mo config.MatchOpt = mo
} }
@ -167,7 +167,7 @@ func ReferrerFilter(config ReferrerConfig, rlIn referrer.ReferrerList) referrer.
Manifest: rlIn.Manifest, Manifest: rlIn.Manifest,
Annotations: rlIn.Annotations, Annotations: rlIn.Annotations,
Tags: rlIn.Tags, Tags: rlIn.Tags,
Descriptors: types.DescriptorListFilter(rlIn.Descriptors, config.MatchOpt), Descriptors: descriptor.DescriptorListFilter(rlIn.Descriptors, config.MatchOpt),
} }
} }

6
tag.go
View File

@ -5,7 +5,7 @@ import (
"fmt" "fmt"
"github.com/regclient/regclient/scheme" "github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
"github.com/regclient/regclient/types/tag" "github.com/regclient/regclient/types/tag"
) )
@ -18,7 +18,7 @@ import (
// 3. Delete the digest for that new manifest that is only used by that tag. // 3. Delete the digest for that new manifest that is only used by that tag.
func (rc *RegClient) TagDelete(ctx context.Context, r ref.Ref) error { func (rc *RegClient) TagDelete(ctx context.Context, r ref.Ref) error {
if !r.IsSet() { if !r.IsSet() {
return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
schemeAPI, err := rc.schemeGet(r.Scheme) schemeAPI, err := rc.schemeGet(r.Scheme)
if err != nil { if err != nil {
@ -30,7 +30,7 @@ func (rc *RegClient) TagDelete(ctx context.Context, r ref.Ref) error {
// TagList returns a tag list from a repository // TagList returns a tag list from a repository
func (rc *RegClient) TagList(ctx context.Context, r ref.Ref, opts ...scheme.TagOpts) (*tag.List, error) { func (rc *RegClient) TagList(ctx context.Context, r ref.Ref, opts ...scheme.TagOpts) (*tag.List, error) {
if !r.IsSetRepo() { if !r.IsSetRepo() {
return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), types.ErrInvalidReference) return nil, fmt.Errorf("ref is not set: %s%.0w", r.CommonName(), errs.ErrInvalidReference)
} }
schemeAPI, err := rc.schemeGet(r.Scheme) schemeAPI, err := rc.schemeGet(r.Scheme)
if err != nil { if err != nil {

View File

@ -7,7 +7,7 @@ import (
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -15,7 +15,7 @@ import (
// Blob interface is used for returning blobs. // Blob interface is used for returning blobs.
type Blob interface { type Blob interface {
// GetDescriptor returns the descriptor associated with the blob. // GetDescriptor returns the descriptor associated with the blob.
GetDescriptor() types.Descriptor GetDescriptor() descriptor.Descriptor
// RawBody returns the raw content of the blob. // RawBody returns the raw content of the blob.
RawBody() ([]byte, error) RawBody() ([]byte, error)
// RawHeaders returns the headers received from the registry. // RawHeaders returns the headers received from the registry.
@ -38,7 +38,7 @@ type Blob interface {
} }
type blobConfig struct { type blobConfig struct {
desc types.Descriptor desc descriptor.Descriptor
header http.Header header http.Header
image *v1.Image image *v1.Image
r ref.Ref r ref.Ref
@ -51,7 +51,7 @@ type blobConfig struct {
type Opts func(*blobConfig) type Opts func(*blobConfig)
// WithDesc specifies the descriptor associated with the blob. // WithDesc specifies the descriptor associated with the blob.
func WithDesc(d types.Descriptor) Opts { func WithDesc(d descriptor.Descriptor) Opts {
return func(bc *blobConfig) { return func(bc *blobConfig) {
bc.desc = d bc.desc = d
} }

View File

@ -12,7 +12,9 @@ import (
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -53,19 +55,19 @@ var (
`) `)
exLen = int64(len(exBlob)) exLen = int64(len(exBlob))
exDigest = digest.FromBytes(exBlob) exDigest = digest.FromBytes(exBlob)
exMT = types.MediaTypeDocker2ImageConfig exMT = mediatype.Docker2ImageConfig
exHeaders = http.Header{ exHeaders = http.Header{
"Content-Type": {types.MediaTypeDocker2ImageConfig}, "Content-Type": {mediatype.Docker2ImageConfig},
"Content-Length": {fmt.Sprintf("%d", exLen)}, "Content-Length": {fmt.Sprintf("%d", exLen)},
"Docker-Content-Digest": {exDigest.String()}, "Docker-Content-Digest": {exDigest.String()},
} }
exHeadersShort = http.Header{ exHeadersShort = http.Header{
"Content-Type": {types.MediaTypeDocker2ImageConfig}, "Content-Type": {mediatype.Docker2ImageConfig},
"Content-Length": {fmt.Sprintf("%d", exLen-5)}, "Content-Length": {fmt.Sprintf("%d", exLen-5)},
"Docker-Content-Digest": {exDigest.String()}, "Docker-Content-Digest": {exDigest.String()},
} }
exHeadersLong = http.Header{ exHeadersLong = http.Header{
"Content-Type": {types.MediaTypeDocker2ImageConfig}, "Content-Type": {mediatype.Docker2ImageConfig},
"Content-Length": {fmt.Sprintf("%d", exLen+5)}, "Content-Length": {fmt.Sprintf("%d", exLen+5)},
"Docker-Content-Digest": {exDigest.String()}, "Docker-Content-Digest": {exDigest.String()},
} }
@ -76,7 +78,7 @@ var (
ContentLength: exLen, ContentLength: exLen,
Body: io.NopCloser(bytes.NewReader(exBlob)), Body: io.NopCloser(bytes.NewReader(exBlob)),
} }
exDesc = types.Descriptor{ exDesc = descriptor.Descriptor{
MediaType: exMT, MediaType: exMT,
Digest: exDigest, Digest: exDigest,
Size: exLen, Size: exLen,
@ -111,7 +113,7 @@ func TestCommon(t *testing.T) {
name: "descriptor", name: "descriptor",
opts: []Opts{ opts: []Opts{
WithReader(bytes.NewReader(exBlob)), WithReader(bytes.NewReader(exBlob)),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: exMT, MediaType: exMT,
Digest: exDigest, Digest: exDigest,
Size: exLen, Size: exLen,
@ -160,7 +162,7 @@ func TestCommon(t *testing.T) {
eHeaders: exHeadersShort, eHeaders: exHeadersShort,
eLen: exLen, eLen: exLen,
eMT: exMT, eMT: exMT,
eErr: types.ErrSizeLimitExceeded, eErr: errs.ErrSizeLimitExceeded,
}, },
{ {
name: "short read", name: "short read",
@ -174,7 +176,7 @@ func TestCommon(t *testing.T) {
eHeaders: exHeadersLong, eHeaders: exHeadersLong,
eLen: exLen, eLen: exLen,
eMT: exMT, eMT: exMT,
eErr: types.ErrShortRead, eErr: errs.ErrShortRead,
}, },
} }
for _, tc := range tt { for _, tc := range tt {
@ -296,8 +298,8 @@ func TestReader(t *testing.T) {
if err == nil { if err == nil {
t.Fatalf("readall did not fail") t.Fatalf("readall did not fail")
} }
if !errors.Is(err, types.ErrSizeLimitExceeded) { if !errors.Is(err, errs.ErrSizeLimitExceeded) {
t.Errorf("unexpected error on readall, expected %v, received %v", types.ErrSizeLimitExceeded, err) t.Errorf("unexpected error on readall, expected %v, received %v", errs.ErrSizeLimitExceeded, err)
} }
}) })
@ -305,7 +307,7 @@ func TestReader(t *testing.T) {
// create blob // create blob
b := NewReader( b := NewReader(
WithReader(bytes.NewReader(exBlob)), WithReader(bytes.NewReader(exBlob)),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: exMT, MediaType: exMT,
Digest: exDigest, Digest: exDigest,
Size: exLen, Size: exLen,
@ -357,7 +359,7 @@ func TestOCI(t *testing.T) {
fromJSON []byte fromJSON []byte
wantRaw []byte wantRaw []byte
wantJSON []byte wantJSON []byte
wantDesc types.Descriptor wantDesc descriptor.Descriptor
}{ }{
{ {
name: "RawBody", name: "RawBody",
@ -383,7 +385,7 @@ func TestOCI(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithImage(ociConfig), WithImage(ociConfig),
}, },
wantDesc: types.Descriptor{MediaType: types.MediaTypeOCI1ImageConfig}, wantDesc: descriptor.Descriptor{MediaType: mediatype.OCI1ImageConfig},
}, },
{ {
name: "Config with Docker Desc", name: "Config with Docker Desc",
@ -391,7 +393,7 @@ func TestOCI(t *testing.T) {
WithImage(ociConfig), WithImage(ociConfig),
WithDesc(exDesc), WithDesc(exDesc),
}, },
wantDesc: types.Descriptor{MediaType: exMT}, wantDesc: descriptor.Descriptor{MediaType: exMT},
}, },
} }
@ -440,7 +442,7 @@ func TestOCI(t *testing.T) {
// create blob // create blob
oc := NewOCIConfig( oc := NewOCIConfig(
WithRawBody(exBlob), WithRawBody(exBlob),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: exMT, MediaType: exMT,
Digest: exDigest, Digest: exDigest,
Size: exLen, Size: exLen,
@ -493,8 +495,8 @@ func TestTarReader(t *testing.T) {
{ {
name: "good desc", name: "good desc",
opts: []Opts{ opts: []Opts{
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Layer, MediaType: mediatype.OCI1Layer,
Size: fhSize, Size: fhSize,
Digest: dig, Digest: dig,
}), }),
@ -503,8 +505,8 @@ func TestTarReader(t *testing.T) {
{ {
name: "bad desc", name: "bad desc",
opts: []Opts{ opts: []Opts{
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Layer, MediaType: mediatype.OCI1Layer,
Size: fhSize, Size: fhSize,
Digest: digest.FromString("bad digest"), Digest: digest.FromString("bad digest"),
}), }),
@ -573,7 +575,7 @@ func TestReadFile(t *testing.T) {
{ {
name: "layer2", name: "layer2",
filename: "layer2.txt", filename: "layer2.txt",
expectErr: types.ErrFileDeleted, expectErr: errs.ErrFileDeleted,
}, },
{ {
name: "layer3", name: "layer3",
@ -583,12 +585,12 @@ func TestReadFile(t *testing.T) {
{ {
name: "opaque dir", name: "opaque dir",
filename: "exdir/test.txt", filename: "exdir/test.txt",
expectErr: types.ErrFileDeleted, expectErr: errs.ErrFileDeleted,
}, },
{ {
name: "missing", name: "missing",
filename: "missing.txt", filename: "missing.txt",
expectErr: types.ErrFileNotFound, expectErr: errs.ErrFileNotFound,
}, },
{ {
name: "invalid", name: "invalid",
@ -607,7 +609,7 @@ func TestReadFile(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to open test data: %v", err) t.Fatalf("failed to open test data: %v", err)
} }
btr := NewTarReader(WithReader(fh), WithDesc(types.Descriptor{Size: int64(len(fileBytes)), Digest: blobDigest, MediaType: types.MediaTypeOCI1Layer})) btr := NewTarReader(WithReader(fh), WithDesc(descriptor.Descriptor{Size: int64(len(fileBytes)), Digest: blobDigest, MediaType: mediatype.OCI1Layer}))
defer btr.Close() defer btr.Close()
th, rdr, err := btr.ReadFile(tc.filename) th, rdr, err := btr.ReadFile(tc.filename)
if tc.expectErr != nil { if tc.expectErr != nil {
@ -649,12 +651,12 @@ func TestReadFile(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to open test data: %v", err) t.Fatalf("failed to open test data: %v", err)
} }
btr := NewTarReader(WithReader(fh), WithDesc(types.Descriptor{Size: int64(len(fileBytes)), Digest: digest.FromString("bad digest"), MediaType: types.MediaTypeOCI1Layer})) btr := NewTarReader(WithReader(fh), WithDesc(descriptor.Descriptor{Size: int64(len(fileBytes)), Digest: digest.FromString("bad digest"), MediaType: mediatype.OCI1Layer}))
_, _, err = btr.ReadFile("missing.txt") _, _, err = btr.ReadFile("missing.txt")
if err == nil { if err == nil {
t.Errorf("ReadFile did not fail") t.Errorf("ReadFile did not fail")
} else if !errors.Is(err, types.ErrDigestMismatch) { } else if !errors.Is(err, errs.ErrDigestMismatch) {
t.Errorf("unexpected error, expected %v, received %v", types.ErrDigestMismatch, err) t.Errorf("unexpected error, expected %v, received %v", errs.ErrDigestMismatch, err)
} }
}) })
} }

View File

@ -9,7 +9,7 @@ import (
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
@ -19,14 +19,14 @@ type Common = *BCommon
// BCommon is a common struct for all blobs which includes various shared methods. // BCommon is a common struct for all blobs which includes various shared methods.
type BCommon struct { type BCommon struct {
r ref.Ref r ref.Ref
desc types.Descriptor desc descriptor.Descriptor
blobSet bool blobSet bool
rawHeader http.Header rawHeader http.Header
resp *http.Response resp *http.Response
} }
// GetDescriptor returns the descriptor associated with the blob. // GetDescriptor returns the descriptor associated with the blob.
func (c *BCommon) GetDescriptor() types.Descriptor { func (c *BCommon) GetDescriptor() descriptor.Descriptor {
return c.desc return c.desc
} }

View File

@ -10,7 +10,7 @@ import (
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
) )
@ -50,7 +50,7 @@ func NewOCIConfig(opts ...Opts) *BOCIConfig {
bc.desc.Digest = digest.FromBytes(bc.rawBody) bc.desc.Digest = digest.FromBytes(bc.rawBody)
bc.desc.Size = int64(len(bc.rawBody)) bc.desc.Size = int64(len(bc.rawBody))
if bc.desc.MediaType == "" { if bc.desc.MediaType == "" {
bc.desc.MediaType = types.MediaTypeOCI1ImageConfig bc.desc.MediaType = mediatype.OCI1ImageConfig
} }
} }
b := BOCIConfig{ b := BOCIConfig{
@ -91,7 +91,7 @@ func (oc *BOCIConfig) SetConfig(image v1.Image) {
oc.image = image oc.image = image
oc.rawBody, _ = json.Marshal(oc.image) oc.rawBody, _ = json.Marshal(oc.image)
if oc.desc.MediaType == "" { if oc.desc.MediaType == "" {
oc.desc.MediaType = types.MediaTypeOCI1ImageConfig oc.desc.MediaType = mediatype.OCI1ImageConfig
} }
oc.desc.Digest = digest.FromBytes(oc.rawBody) oc.desc.Digest = digest.FromBytes(oc.rawBody)
oc.desc.Size = int64(len(oc.rawBody)) oc.desc.Size = int64(len(oc.rawBody))
@ -119,7 +119,7 @@ func (oc *BOCIConfig) UnmarshalJSON(data []byte) error {
oc.rawBody = make([]byte, len(data)) oc.rawBody = make([]byte, len(data))
copy(oc.rawBody, data) copy(oc.rawBody, data)
if oc.desc.MediaType == "" { if oc.desc.MediaType == "" {
oc.desc.MediaType = types.MediaTypeOCI1ImageConfig oc.desc.MediaType = mediatype.OCI1ImageConfig
} }
oc.desc.Digest = digest.FromBytes(oc.rawBody) oc.desc.Digest = digest.FromBytes(oc.rawBody)
oc.desc.Size = int64(len(oc.rawBody)) oc.desc.Size = int64(len(oc.rawBody))

View File

@ -12,7 +12,8 @@ import (
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/internal/limitread" "github.com/regclient/regclient/internal/limitread"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
) )
// Reader was previously an interface. A type alias is provided for upgrading. // Reader was previously an interface. A type alias is provided for upgrading.
@ -45,7 +46,7 @@ func NewReader(opts ...Opts) *BReader {
if bc.header != nil { if bc.header != nil {
// extract fields from header if descriptor not passed // extract fields from header if descriptor not passed
if bc.desc.MediaType == "" { if bc.desc.MediaType == "" {
bc.desc.MediaType = types.MediaTypeBase(bc.header.Get("Content-Type")) bc.desc.MediaType = mediatype.Base(bc.header.Get("Content-Type"))
} }
if bc.desc.Size == 0 { if bc.desc.Size == 0 {
cl, _ := strconv.Atoi(bc.header.Get("Content-Length")) cl, _ := strconv.Atoi(bc.header.Get("Content-Length"))
@ -109,15 +110,15 @@ func (r *BReader) Read(p []byte) (int, error) {
if r.desc.Size == 0 { if r.desc.Size == 0 {
r.desc.Size = r.readBytes r.desc.Size = r.readBytes
} else if r.readBytes < r.desc.Size { } else if r.readBytes < r.desc.Size {
err = fmt.Errorf("%w [expected %d, received %d]: %w", types.ErrShortRead, r.desc.Size, r.readBytes, err) err = fmt.Errorf("%w [expected %d, received %d]: %w", errs.ErrShortRead, r.desc.Size, r.readBytes, err)
} else if r.readBytes > r.desc.Size { } else if r.readBytes > r.desc.Size {
err = fmt.Errorf("%w [expected %d, received %d]: %w", types.ErrSizeLimitExceeded, r.desc.Size, r.readBytes, err) err = fmt.Errorf("%w [expected %d, received %d]: %w", errs.ErrSizeLimitExceeded, r.desc.Size, r.readBytes, err)
} }
// check/save digest // check/save digest
if r.desc.Digest == "" { if r.desc.Digest == "" {
r.desc.Digest = r.digester.Digest() r.desc.Digest = r.digester.Digest()
} else if r.desc.Digest != r.digester.Digest() { } else if r.desc.Digest != r.digester.Digest() {
err = fmt.Errorf("%w [expected %s, calculated %s]: %w", types.ErrDigestMismatch, r.desc.Digest.String(), r.digester.Digest().String(), err) err = fmt.Errorf("%w [expected %s, calculated %s]: %w", errs.ErrDigestMismatch, r.desc.Digest.String(), r.digester.Digest().String(), err)
} }
} }
return size, err return size, err

View File

@ -12,7 +12,7 @@ import (
"github.com/regclient/regclient/internal/limitread" "github.com/regclient/regclient/internal/limitread"
"github.com/regclient/regclient/pkg/archive" "github.com/regclient/regclient/pkg/archive"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/errs"
) )
// TarReader was previously an interface. A type alias is provided for upgrading. // TarReader was previously an interface. A type alias is provided for upgrading.
@ -98,7 +98,7 @@ func (tr *BTarReader) RawBody() ([]byte, error) {
dig := tr.digester.Digest() dig := tr.digester.Digest()
tr.digester = nil tr.digester = nil
if tr.desc.Digest.String() != "" && dig != tr.desc.Digest { if tr.desc.Digest.String() != "" && dig != tr.desc.Digest {
return b, fmt.Errorf("%w, expected %s, received %s", types.ErrDigestMismatch, tr.desc.Digest.String(), dig.String()) return b, fmt.Errorf("%w, expected %s, received %s", errs.ErrDigestMismatch, tr.desc.Digest.String(), dig.String())
} }
tr.desc.Digest = dig tr.desc.Digest = dig
} }
@ -150,18 +150,18 @@ func (tr *BTarReader) ReadFile(filename string) (*tar.Header, io.Reader, error)
} }
// EOF encountered // EOF encountered
if whiteout { if whiteout {
return nil, nil, types.ErrFileDeleted return nil, nil, errs.ErrFileDeleted
} }
if tr.digester != nil { if tr.digester != nil {
_, _ = io.Copy(io.Discard, tr.reader) // process/digest any trailing bytes from reader _, _ = io.Copy(io.Discard, tr.reader) // process/digest any trailing bytes from reader
dig := tr.digester.Digest() dig := tr.digester.Digest()
tr.digester = nil tr.digester = nil
if tr.desc.Digest.String() != "" && dig != tr.desc.Digest { if tr.desc.Digest.String() != "" && dig != tr.desc.Digest {
return nil, nil, fmt.Errorf("%w, expected %s, received %s", types.ErrDigestMismatch, tr.desc.Digest.String(), dig.String()) return nil, nil, fmt.Errorf("%w, expected %s, received %s", errs.ErrDigestMismatch, tr.desc.Digest.String(), dig.String())
} }
tr.desc.Digest = dig tr.desc.Digest = dig
} }
return nil, nil, types.ErrFileNotFound return nil, nil, errs.ErrFileNotFound
} }
func tarCmpWhiteout(whFile, tgtFile string) bool { func tarCmpWhiteout(whFile, tgtFile string) bool {

View File

@ -1,272 +1,27 @@
package types package types
import ( import "github.com/regclient/regclient/types/descriptor"
"fmt"
"sort"
"strings"
"text/tabwriter"
// crypto libraries included for go-digest type (
_ "crypto/sha256" // Descriptor is used in manifests to refer to content by media type, size, and digest.
_ "crypto/sha512" //
// Deprecated: replace with [descriptor.Descriptor].
"github.com/opencontainers/go-digest" Descriptor = descriptor.Descriptor
// MatchOpt defines conditions for a match descriptor.
"github.com/regclient/regclient/internal/units" //
"github.com/regclient/regclient/types/platform" // Deprecated: replace with [descriptor.MatchOpt].
MatchOpt = descriptor.MatchOpt
) )
// Descriptor is used in manifests to refer to content by media type, size, and digest. var (
type Descriptor struct { // EmptyData is the content of the empty JSON descriptor. See [mediatype.OCI1Empty].
// MediaType describe the type of the content. //
MediaType string `json:"mediaType"` // Deprecated: replace with [descriptor.EmptyData].
EmptyData = descriptor.EmptyData
// Digest uniquely identifies the content. // EmptyDigest is the digest of the empty JSON descriptor. See [mediatype.OCI1Empty].
Digest digest.Digest `json:"digest"` //
// Deprecated: replace with [descriptor.EmptyDigest].
// Size in bytes of content. EmptyDigest = descriptor.EmptyDigest
Size int64 `json:"size"` DescriptorListFilter = descriptor.DescriptorListFilter
DescriptorListSearch = descriptor.DescriptorListSearch
// URLs contains the source URLs of this content. )
URLs []string `json:"urls,omitempty"`
// Annotations contains arbitrary metadata relating to the targeted content.
Annotations map[string]string `json:"annotations,omitempty"`
// Data is an embedding of the targeted content. This is encoded as a base64
// string when marshalled to JSON (automatically, by encoding/json). If
// present, Data can be used directly to avoid fetching the targeted content.
Data []byte `json:"data,omitempty"`
// Platform describes the platform which the image in the manifest runs on.
// This should only be used when referring to a manifest.
Platform *platform.Platform `json:"platform,omitempty"`
// ArtifactType is the media type of the artifact this descriptor refers to.
ArtifactType string `json:"artifactType,omitempty"`
}
var EmptyData = []byte("{}")
var EmptyDigest = digest.FromBytes(EmptyData)
var emptyDigest = digest.FromBytes([]byte{})
var mtToOCI map[string]string
func init() {
mtToOCI = map[string]string{
MediaTypeDocker2ManifestList: MediaTypeOCI1ManifestList,
MediaTypeDocker2Manifest: MediaTypeOCI1Manifest,
MediaTypeDocker2ImageConfig: MediaTypeOCI1ImageConfig,
MediaTypeDocker2LayerGzip: MediaTypeOCI1LayerGzip,
MediaTypeOCI1ManifestList: MediaTypeOCI1ManifestList,
MediaTypeOCI1Manifest: MediaTypeOCI1Manifest,
MediaTypeOCI1ImageConfig: MediaTypeOCI1ImageConfig,
MediaTypeOCI1LayerGzip: MediaTypeOCI1LayerGzip,
}
}
// GetData decodes the Data field from the descriptor if available
func (d Descriptor) GetData() ([]byte, error) {
if len(d.Data) == 0 && d.Digest != emptyDigest {
return nil, ErrParsingFailed
}
// verify length
if int64(len(d.Data)) != d.Size {
return nil, ErrParsingFailed
}
// generate and verify digest
dDig := digest.FromBytes(d.Data)
if d.Digest != dDig {
return nil, ErrParsingFailed
}
// return data
return d.Data, nil
}
// Equal indicates the two descriptors are identical, effectively a DeepEqual.
func (d Descriptor) Equal(d2 Descriptor) bool {
if !d.Same(d2) {
return false
}
if d.MediaType != d2.MediaType {
return false
}
if d.ArtifactType != d2.ArtifactType {
return false
}
if d.Platform == nil || d2.Platform == nil {
if d.Platform != nil || d2.Platform != nil {
return false
}
} else if !platform.Match(*d.Platform, *d2.Platform) {
return false
}
if d.URLs == nil || d2.URLs == nil {
if d.URLs != nil || d2.URLs != nil {
return false
}
} else if len(d.URLs) != len(d2.URLs) {
return false
} else {
for i := range d.URLs {
if d.URLs[i] != d2.URLs[i] {
return false
}
}
}
if d.Annotations == nil || d2.Annotations == nil {
if d.Annotations != nil || d2.Annotations != nil {
return false
}
} else if len(d.Annotations) != len(d2.Annotations) {
return false
} else {
for i := range d.Annotations {
if d.Annotations[i] != d2.Annotations[i] {
return false
}
}
}
return true
}
// Same indicates two descriptors point to the same CAS object.
// This verifies the digest, media type, and size all match
func (d Descriptor) Same(d2 Descriptor) bool {
if d.Digest != d2.Digest || d.Size != d2.Size {
return false
}
// loosen the check on media type since this can be converted from a build
if d.MediaType != d2.MediaType {
if _, ok := mtToOCI[d.MediaType]; !ok {
return false
} else if mtToOCI[d.MediaType] != mtToOCI[d2.MediaType] {
return false
}
}
return true
}
func (d Descriptor) MarshalPrettyTW(tw *tabwriter.Writer, prefix string) error {
fmt.Fprintf(tw, "%sDigest:\t%s\n", prefix, string(d.Digest))
fmt.Fprintf(tw, "%sMediaType:\t%s\n", prefix, d.MediaType)
if d.ArtifactType != "" {
fmt.Fprintf(tw, "%sArtifactType:\t%s\n", prefix, d.ArtifactType)
}
switch d.MediaType {
case MediaTypeDocker1Manifest, MediaTypeDocker1ManifestSigned,
MediaTypeDocker2Manifest, MediaTypeDocker2ManifestList,
MediaTypeOCI1Manifest, MediaTypeOCI1ManifestList:
// skip printing size for descriptors to manifests
default:
if d.Size > 100000 {
fmt.Fprintf(tw, "%sSize:\t%s\n", prefix, units.HumanSize(float64(d.Size)))
} else {
fmt.Fprintf(tw, "%sSize:\t%dB\n", prefix, d.Size)
}
}
if p := d.Platform; p != nil && p.OS != "" {
fmt.Fprintf(tw, "%sPlatform:\t%s\n", prefix, p.String())
if p.OSVersion != "" {
fmt.Fprintf(tw, "%sOSVersion:\t%s\n", prefix, p.OSVersion)
}
if len(p.OSFeatures) > 0 {
fmt.Fprintf(tw, "%sOSFeatures:\t%s\n", prefix, strings.Join(p.OSFeatures, ", "))
}
}
if len(d.URLs) > 0 {
fmt.Fprintf(tw, "%sURLs:\t%s\n", prefix, strings.Join(d.URLs, ", "))
}
if d.Annotations != nil {
fmt.Fprintf(tw, "%sAnnotations:\t\n", prefix)
for k, v := range d.Annotations {
fmt.Fprintf(tw, "%s %s:\t%s\n", prefix, k, v)
}
}
return nil
}
// MatchOpt defines conditions for a match descriptor
type MatchOpt struct {
Platform *platform.Platform // Platform to match including compatible platforms (darwin/arm64 matches linux/arm64)
ArtifactType string // Match ArtifactType in the descriptor
Annotations map[string]string // Match each of the specified annotations and their value, an empty value verifies the key is set
SortAnnotation string // Sort the results by an annotation, string based comparison, descriptors without the annotation are sorted last
SortDesc bool // Set to true to sort in descending order
}
// Match returns true if the descriptor matches the options, including compatible platforms
func (d Descriptor) Match(opt MatchOpt) bool {
if opt.ArtifactType != "" && d.ArtifactType != opt.ArtifactType {
return false
}
if opt.Annotations != nil && len(opt.Annotations) > 0 {
if d.Annotations == nil {
return false
}
for k, v := range opt.Annotations {
if dv, ok := d.Annotations[k]; !ok || (v != "" && v != dv) {
return false
}
}
}
if opt.Platform != nil {
if d.Platform == nil {
return false
}
if !platform.Compatible(*opt.Platform, *d.Platform) {
return false
}
}
return true
}
// DescriptorListFilter returns a list of descriptors from the list matching the search options.
// When opt.SortAnnotation is set, the order of descriptors with matching annotations is undefined.
func DescriptorListFilter(dl []Descriptor, opt MatchOpt) []Descriptor {
ret := []Descriptor{}
for _, d := range dl {
if d.Match(opt) {
ret = append(ret, d)
}
}
if opt.SortAnnotation != "" {
sort.Slice(ret, func(i, j int) bool {
// if annotations are not defined, sort to the very end
if ret[i].Annotations == nil {
return false
}
if _, ok := ret[i].Annotations[opt.SortAnnotation]; !ok {
return false
}
if ret[j].Annotations == nil {
return true
}
if _, ok := ret[j].Annotations[opt.SortAnnotation]; !ok {
return true
}
// else sort by string
if strings.Compare(ret[i].Annotations[opt.SortAnnotation], ret[j].Annotations[opt.SortAnnotation]) < 0 {
return !opt.SortDesc
}
return opt.SortDesc
})
}
return ret
}
// DescriptorListSearch returns the first descriptor from the list matching the search options
func DescriptorListSearch(dl []Descriptor, opt MatchOpt) (Descriptor, error) {
filter := DescriptorListFilter(dl, opt)
if len(filter) < 1 {
return Descriptor{}, ErrNotFound
}
// prefer exact platform match when available
if opt.Platform != nil {
for _, d := range filter {
if platform.Match(*opt.Platform, *d.Platform) {
return d, nil
}
}
}
return filter[0], nil
}

View File

@ -0,0 +1,279 @@
// Package descriptor defines the OCI descriptor data structure used in manifests to reference content addressable data.
package descriptor
import (
"fmt"
"sort"
"strings"
"text/tabwriter"
// crypto libraries included for go-digest
_ "crypto/sha256"
_ "crypto/sha512"
"github.com/opencontainers/go-digest"
"github.com/regclient/regclient/internal/units"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/platform"
)
// Descriptor is used in manifests to refer to content by media type, size, and digest.
type Descriptor struct {
// MediaType describe the type of the content.
MediaType string `json:"mediaType"`
// Digest uniquely identifies the content.
Digest digest.Digest `json:"digest"`
// Size in bytes of content.
Size int64 `json:"size"`
// URLs contains the source URLs of this content.
URLs []string `json:"urls,omitempty"`
// Annotations contains arbitrary metadata relating to the targeted content.
Annotations map[string]string `json:"annotations,omitempty"`
// Data is an embedding of the targeted content. This is encoded as a base64
// string when marshalled to JSON (automatically, by encoding/json). If
// present, Data can be used directly to avoid fetching the targeted content.
Data []byte `json:"data,omitempty"`
// Platform describes the platform which the image in the manifest runs on.
// This should only be used when referring to a manifest.
Platform *platform.Platform `json:"platform,omitempty"`
// ArtifactType is the media type of the artifact this descriptor refers to.
ArtifactType string `json:"artifactType,omitempty"`
}
var (
// EmptyData is the content of the empty JSON descriptor. See [mediatype.OCI1Empty].
EmptyData = []byte("{}")
// EmptyDigest is the digest of the empty JSON descriptor. See [mediatype.OCI1Empty].
EmptyDigest = digest.FromBytes(EmptyData)
emptyDigest = digest.FromBytes([]byte{})
mtToOCI map[string]string
)
func init() {
mtToOCI = map[string]string{
mediatype.Docker2ManifestList: mediatype.OCI1ManifestList,
mediatype.Docker2Manifest: mediatype.OCI1Manifest,
mediatype.Docker2ImageConfig: mediatype.OCI1ImageConfig,
mediatype.Docker2LayerGzip: mediatype.OCI1LayerGzip,
mediatype.OCI1ManifestList: mediatype.OCI1ManifestList,
mediatype.OCI1Manifest: mediatype.OCI1Manifest,
mediatype.OCI1ImageConfig: mediatype.OCI1ImageConfig,
mediatype.OCI1LayerGzip: mediatype.OCI1LayerGzip,
}
}
// GetData decodes the Data field from the descriptor if available
func (d Descriptor) GetData() ([]byte, error) {
if len(d.Data) == 0 && d.Digest != emptyDigest {
return nil, errs.ErrParsingFailed
}
// verify length
if int64(len(d.Data)) != d.Size {
return nil, errs.ErrParsingFailed
}
// generate and verify digest
dDig := digest.FromBytes(d.Data)
if d.Digest != dDig {
return nil, errs.ErrParsingFailed
}
// return data
return d.Data, nil
}
// Equal indicates the two descriptors are identical, effectively a DeepEqual.
func (d Descriptor) Equal(d2 Descriptor) bool {
if !d.Same(d2) {
return false
}
if d.MediaType != d2.MediaType {
return false
}
if d.ArtifactType != d2.ArtifactType {
return false
}
if d.Platform == nil || d2.Platform == nil {
if d.Platform != nil || d2.Platform != nil {
return false
}
} else if !platform.Match(*d.Platform, *d2.Platform) {
return false
}
if d.URLs == nil || d2.URLs == nil {
if d.URLs != nil || d2.URLs != nil {
return false
}
} else if len(d.URLs) != len(d2.URLs) {
return false
} else {
for i := range d.URLs {
if d.URLs[i] != d2.URLs[i] {
return false
}
}
}
if d.Annotations == nil || d2.Annotations == nil {
if d.Annotations != nil || d2.Annotations != nil {
return false
}
} else if len(d.Annotations) != len(d2.Annotations) {
return false
} else {
for i := range d.Annotations {
if d.Annotations[i] != d2.Annotations[i] {
return false
}
}
}
return true
}
// Same indicates two descriptors point to the same CAS object.
// This verifies the digest, media type, and size all match.
func (d Descriptor) Same(d2 Descriptor) bool {
if d.Digest != d2.Digest || d.Size != d2.Size {
return false
}
// loosen the check on media type since this can be converted from a build
if d.MediaType != d2.MediaType {
if _, ok := mtToOCI[d.MediaType]; !ok {
return false
} else if mtToOCI[d.MediaType] != mtToOCI[d2.MediaType] {
return false
}
}
return true
}
func (d Descriptor) MarshalPrettyTW(tw *tabwriter.Writer, prefix string) error {
fmt.Fprintf(tw, "%sDigest:\t%s\n", prefix, string(d.Digest))
fmt.Fprintf(tw, "%sMediaType:\t%s\n", prefix, d.MediaType)
if d.ArtifactType != "" {
fmt.Fprintf(tw, "%sArtifactType:\t%s\n", prefix, d.ArtifactType)
}
switch d.MediaType {
case mediatype.Docker1Manifest, mediatype.Docker1ManifestSigned,
mediatype.Docker2Manifest, mediatype.Docker2ManifestList,
mediatype.OCI1Manifest, mediatype.OCI1ManifestList:
// skip printing size for descriptors to manifests
default:
if d.Size > 100000 {
fmt.Fprintf(tw, "%sSize:\t%s\n", prefix, units.HumanSize(float64(d.Size)))
} else {
fmt.Fprintf(tw, "%sSize:\t%dB\n", prefix, d.Size)
}
}
if p := d.Platform; p != nil && p.OS != "" {
fmt.Fprintf(tw, "%sPlatform:\t%s\n", prefix, p.String())
if p.OSVersion != "" {
fmt.Fprintf(tw, "%sOSVersion:\t%s\n", prefix, p.OSVersion)
}
if len(p.OSFeatures) > 0 {
fmt.Fprintf(tw, "%sOSFeatures:\t%s\n", prefix, strings.Join(p.OSFeatures, ", "))
}
}
if len(d.URLs) > 0 {
fmt.Fprintf(tw, "%sURLs:\t%s\n", prefix, strings.Join(d.URLs, ", "))
}
if d.Annotations != nil {
fmt.Fprintf(tw, "%sAnnotations:\t\n", prefix)
for k, v := range d.Annotations {
fmt.Fprintf(tw, "%s %s:\t%s\n", prefix, k, v)
}
}
return nil
}
// MatchOpt defines conditions for a match descriptor.
type MatchOpt struct {
Platform *platform.Platform // Platform to match including compatible platforms (darwin/arm64 matches linux/arm64)
ArtifactType string // Match ArtifactType in the descriptor
Annotations map[string]string // Match each of the specified annotations and their value, an empty value verifies the key is set
SortAnnotation string // Sort the results by an annotation, string based comparison, descriptors without the annotation are sorted last
SortDesc bool // Set to true to sort in descending order
}
// Match returns true if the descriptor matches the options, including compatible platforms.
func (d Descriptor) Match(opt MatchOpt) bool {
if opt.ArtifactType != "" && d.ArtifactType != opt.ArtifactType {
return false
}
if opt.Annotations != nil && len(opt.Annotations) > 0 {
if d.Annotations == nil {
return false
}
for k, v := range opt.Annotations {
if dv, ok := d.Annotations[k]; !ok || (v != "" && v != dv) {
return false
}
}
}
if opt.Platform != nil {
if d.Platform == nil {
return false
}
if !platform.Compatible(*opt.Platform, *d.Platform) {
return false
}
}
return true
}
// DescriptorListFilter returns a list of descriptors from the list matching the search options.
// When opt.SortAnnotation is set, the order of descriptors with matching annotations is undefined.
func DescriptorListFilter(dl []Descriptor, opt MatchOpt) []Descriptor {
ret := []Descriptor{}
for _, d := range dl {
if d.Match(opt) {
ret = append(ret, d)
}
}
if opt.SortAnnotation != "" {
sort.Slice(ret, func(i, j int) bool {
// if annotations are not defined, sort to the very end
if ret[i].Annotations == nil {
return false
}
if _, ok := ret[i].Annotations[opt.SortAnnotation]; !ok {
return false
}
if ret[j].Annotations == nil {
return true
}
if _, ok := ret[j].Annotations[opt.SortAnnotation]; !ok {
return true
}
// else sort by string
if strings.Compare(ret[i].Annotations[opt.SortAnnotation], ret[j].Annotations[opt.SortAnnotation]) < 0 {
return !opt.SortDesc
}
return opt.SortDesc
})
}
return ret
}
// DescriptorListSearch returns the first descriptor from the list matching the search options
func DescriptorListSearch(dl []Descriptor, opt MatchOpt) (Descriptor, error) {
filter := DescriptorListFilter(dl, opt)
if len(filter) < 1 {
return Descriptor{}, errs.ErrNotFound
}
// prefer exact platform match when available
if opt.Platform != nil {
for _, d := range filter {
if platform.Match(*opt.Platform, *d.Platform) {
return d, nil
}
}
}
return filter[0], nil
}

View File

@ -1,4 +1,4 @@
package types package descriptor
import ( import (
"bytes" "bytes"
@ -9,6 +9,8 @@ import (
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
) )
@ -23,36 +25,36 @@ func TestDescriptorData(t *testing.T) {
{ {
name: "No Data", name: "No Data",
d: Descriptor{ d: Descriptor{
MediaType: MediaTypeDocker2LayerGzip, MediaType: mediatype.Docker2LayerGzip,
Size: 941, Size: 941,
Digest: digest.Digest("sha256:f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14"), Digest: digest.Digest("sha256:f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14"),
}, },
wantErr: ErrParsingFailed, wantErr: errs.ErrParsingFailed,
}, },
{ {
name: "Bad Digest", name: "Bad Digest",
d: Descriptor{ d: Descriptor{
MediaType: MediaTypeOCI1LayerGzip, MediaType: mediatype.OCI1LayerGzip,
Size: 10, Size: 10,
Digest: digest.Digest("sha256:e4a380728755139f156563e8b795581d5915dcc947fe937c524c6d52fd604b99"), Digest: digest.Digest("sha256:e4a380728755139f156563e8b795581d5915dcc947fe937c524c6d52fd604b99"),
Data: []byte("example data"), Data: []byte("example data"),
}, },
wantErr: ErrParsingFailed, wantErr: errs.ErrParsingFailed,
}, },
{ {
name: "Bad Size", name: "Bad Size",
d: Descriptor{ d: Descriptor{
MediaType: MediaTypeOCI1LayerGzip, MediaType: mediatype.OCI1LayerGzip,
Size: 1000, Size: 1000,
Digest: digest.Digest("sha256:44752f37272e944fd2c913a35342eaccdd1aaf189bae50676b301ab213fc5061"), Digest: digest.Digest("sha256:44752f37272e944fd2c913a35342eaccdd1aaf189bae50676b301ab213fc5061"),
Data: []byte("example data"), Data: []byte("example data"),
}, },
wantErr: ErrParsingFailed, wantErr: errs.ErrParsingFailed,
}, },
{ {
name: "Good data", name: "Good data",
d: Descriptor{ d: Descriptor{
MediaType: MediaTypeOCI1LayerGzip, MediaType: mediatype.OCI1LayerGzip,
Size: 12, Size: 12,
Digest: digest.Digest("sha256:44752f37272e944fd2c913a35342eaccdd1aaf189bae50676b301ab213fc5061"), Digest: digest.Digest("sha256:44752f37272e944fd2c913a35342eaccdd1aaf189bae50676b301ab213fc5061"),
Data: []byte("example data"), Data: []byte("example data"),
@ -98,7 +100,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "empty d1", name: "empty d1",
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
@ -108,7 +110,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "empty d2", name: "empty d2",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
@ -118,12 +120,12 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "same simple manifest", name: "same simple manifest",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
@ -133,12 +135,12 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "converting OCI media type", name: "converting OCI media type",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
@ -148,12 +150,12 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "different media type", name: "different media type",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2ManifestList, MediaType: mediatype.Docker2ManifestList,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
@ -163,12 +165,12 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "different size", name: "different size",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 4321, Size: 4321,
Digest: digA, Digest: digA,
}, },
@ -178,12 +180,12 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "different digest", name: "different digest",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digB, Digest: digB,
}, },
@ -193,7 +195,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "annotation eq", name: "annotation eq",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Annotations: map[string]string{ Annotations: map[string]string{
@ -202,7 +204,7 @@ func TestDescriptorEq(t *testing.T) {
}, },
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Annotations: map[string]string{ Annotations: map[string]string{
@ -216,7 +218,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "annotation diff", name: "annotation diff",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Annotations: map[string]string{ Annotations: map[string]string{
@ -225,7 +227,7 @@ func TestDescriptorEq(t *testing.T) {
}, },
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Annotations: map[string]string{ Annotations: map[string]string{
@ -239,7 +241,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "annotation missing", name: "annotation missing",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Annotations: map[string]string{ Annotations: map[string]string{
@ -248,7 +250,7 @@ func TestDescriptorEq(t *testing.T) {
}, },
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
@ -258,7 +260,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "urls eq", name: "urls eq",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
URLs: []string{ URLs: []string{
@ -267,7 +269,7 @@ func TestDescriptorEq(t *testing.T) {
}, },
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
URLs: []string{ URLs: []string{
@ -281,7 +283,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "urls diff", name: "urls diff",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
URLs: []string{ URLs: []string{
@ -290,7 +292,7 @@ func TestDescriptorEq(t *testing.T) {
}, },
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
URLs: []string{ URLs: []string{
@ -304,7 +306,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "urls missing", name: "urls missing",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
URLs: []string{ URLs: []string{
@ -313,7 +315,7 @@ func TestDescriptorEq(t *testing.T) {
}, },
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
@ -323,7 +325,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "platform eq", name: "platform eq",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -332,7 +334,7 @@ func TestDescriptorEq(t *testing.T) {
}, },
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -346,7 +348,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "platform diff", name: "platform diff",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -355,7 +357,7 @@ func TestDescriptorEq(t *testing.T) {
}, },
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -369,7 +371,7 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "platform missing", name: "platform missing",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -378,7 +380,7 @@ func TestDescriptorEq(t *testing.T) {
}, },
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
@ -388,13 +390,13 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "artifactType eq", name: "artifactType eq",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
ArtifactType: "application/vnd.example.test", ArtifactType: "application/vnd.example.test",
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
ArtifactType: "application/vnd.example.test", ArtifactType: "application/vnd.example.test",
@ -405,13 +407,13 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "artifactType diff", name: "artifactType diff",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
ArtifactType: "application/vnd.example.test", ArtifactType: "application/vnd.example.test",
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
ArtifactType: "application/vnd.example.test2", ArtifactType: "application/vnd.example.test2",
@ -422,13 +424,13 @@ func TestDescriptorEq(t *testing.T) {
{ {
name: "artifactType missing", name: "artifactType missing",
d1: Descriptor{ d1: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
ArtifactType: "application/vnd.example.test", ArtifactType: "application/vnd.example.test",
}, },
d2: Descriptor{ d2: Descriptor{
MediaType: MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: 1234, Size: 1234,
Digest: digA, Digest: digA,
}, },
@ -463,7 +465,7 @@ func TestDataJSON(t *testing.T) {
"digest": "sha256:f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14", "digest": "sha256:f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14",
"size": 941 "size": 941
}`), }`),
wantErr: ErrParsingFailed, wantErr: errs.ErrParsingFailed,
}, },
{ {
name: "Bad Data", name: "Bad Data",
@ -483,7 +485,7 @@ func TestDataJSON(t *testing.T) {
"size": 10, "size": 10,
"data": "ZXhhbXBsZSBkYXRh" "data": "ZXhhbXBsZSBkYXRh"
}`), }`),
wantErr: ErrParsingFailed, wantErr: errs.ErrParsingFailed,
}, },
{ {
name: "Bad Size", name: "Bad Size",
@ -493,7 +495,7 @@ func TestDataJSON(t *testing.T) {
"size": 1000, "size": 1000,
"data": "ZXhhbXBsZSBkYXRh" "data": "ZXhhbXBsZSBkYXRh"
}`), }`),
wantErr: ErrParsingFailed, wantErr: errs.ErrParsingFailed,
}, },
{ {
name: "Good data", name: "Good data",
@ -538,7 +540,7 @@ func TestDataJSON(t *testing.T) {
func TestDescriptorSearch(t *testing.T) { func TestDescriptorSearch(t *testing.T) {
t.Parallel() t.Parallel()
dAMD64 := Descriptor{ dAMD64 := Descriptor{
MediaType: MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 12345, Size: 12345,
Digest: EmptyDigest, Digest: EmptyDigest,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -547,7 +549,7 @@ func TestDescriptorSearch(t *testing.T) {
}, },
} }
dAMD64Win := Descriptor{ dAMD64Win := Descriptor{
MediaType: MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 12345, Size: 12345,
Digest: EmptyDigest, Digest: EmptyDigest,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -556,7 +558,7 @@ func TestDescriptorSearch(t *testing.T) {
}, },
} }
dARM64 := Descriptor{ dARM64 := Descriptor{
MediaType: MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 12345, Size: 12345,
Digest: EmptyDigest, Digest: EmptyDigest,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -565,7 +567,7 @@ func TestDescriptorSearch(t *testing.T) {
}, },
} }
dAnnotations := Descriptor{ dAnnotations := Descriptor{
MediaType: MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 12345, Size: 12345,
Digest: EmptyDigest, Digest: EmptyDigest,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -579,7 +581,7 @@ func TestDescriptorSearch(t *testing.T) {
}, },
} }
dAnnotations2 := Descriptor{ dAnnotations2 := Descriptor{
MediaType: MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 12345, Size: 12345,
Digest: EmptyDigest, Digest: EmptyDigest,
Platform: &platform.Platform{ Platform: &platform.Platform{
@ -593,7 +595,7 @@ func TestDescriptorSearch(t *testing.T) {
}, },
} }
dArtifact := Descriptor{ dArtifact := Descriptor{
MediaType: MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 12345, Size: 12345,
Digest: EmptyDigest, Digest: EmptyDigest,
ArtifactType: "application/example.artifact", ArtifactType: "application/example.artifact",
@ -603,7 +605,7 @@ func TestDescriptorSearch(t *testing.T) {
}, },
} }
dArtifact2 := Descriptor{ dArtifact2 := Descriptor{
MediaType: MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 12345, Size: 12345,
Digest: EmptyDigest, Digest: EmptyDigest,
ArtifactType: "application/example.artifact", ArtifactType: "application/example.artifact",
@ -614,7 +616,7 @@ func TestDescriptorSearch(t *testing.T) {
}, },
} }
dArtifact3 := Descriptor{ dArtifact3 := Descriptor{
MediaType: MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 12345, Size: 12345,
Digest: EmptyDigest, Digest: EmptyDigest,
ArtifactType: "application/example.artifact", ArtifactType: "application/example.artifact",
@ -642,7 +644,7 @@ func TestDescriptorSearch(t *testing.T) {
}{ }{
{ {
name: "empty", name: "empty",
err: ErrNotFound, err: errs.ErrNotFound,
}, },
{ {
name: "amd64", name: "amd64",
@ -701,7 +703,7 @@ func TestDescriptorSearch(t *testing.T) {
Architecture: "amd64", Architecture: "amd64",
}, },
}, },
err: ErrNotFound, err: errs.ErrNotFound,
}, },
{ {
name: "artifact", name: "artifact",

View File

@ -10,20 +10,20 @@ import (
"github.com/docker/libtrust" "github.com/docker/libtrust"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/docker" "github.com/regclient/regclient/types/docker"
"github.com/regclient/regclient/types/mediatype"
) )
var ( var (
// ManifestSchemaVersion provides a pre-initialized version structure schema1 manifests. // ManifestSchemaVersion provides a pre-initialized version structure schema1 manifests.
ManifestSchemaVersion = docker.Versioned{ ManifestSchemaVersion = docker.Versioned{
SchemaVersion: 1, SchemaVersion: 1,
MediaType: types.MediaTypeDocker1Manifest, MediaType: mediatype.Docker1Manifest,
} }
// ManifestSignedSchemaVersion provides a pre-initialized version structure schema1 signed manifests. // ManifestSignedSchemaVersion provides a pre-initialized version structure schema1 signed manifests.
ManifestSignedSchemaVersion = docker.Versioned{ ManifestSignedSchemaVersion = docker.Versioned{
SchemaVersion: 1, SchemaVersion: 1,
MediaType: types.MediaTypeDocker1ManifestSigned, MediaType: mediatype.Docker1ManifestSigned,
} }
) )
@ -119,7 +119,7 @@ func (sm *SignedManifest) MarshalJSON() ([]byte, error) {
// Payload returns the signed content of the signed manifest. // Payload returns the signed content of the signed manifest.
func (sm SignedManifest) Payload() (string, []byte, error) { func (sm SignedManifest) Payload() (string, []byte, error) {
return types.MediaTypeDocker1ManifestSigned, sm.all, nil return mediatype.Docker1ManifestSigned, sm.all, nil
} }
// Signatures returns the signatures as provided by (*libtrust.JSONSignature).Signatures. // Signatures returns the signatures as provided by (*libtrust.JSONSignature).Signatures.

View File

@ -1,14 +1,15 @@
package schema2 package schema2
import ( import (
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker" "github.com/regclient/regclient/types/docker"
"github.com/regclient/regclient/types/mediatype"
) )
// ManifestSchemaVersion is a pre-configured versioned field for manifests // ManifestSchemaVersion is a pre-configured versioned field for manifests
var ManifestSchemaVersion = docker.Versioned{ var ManifestSchemaVersion = docker.Versioned{
SchemaVersion: 2, SchemaVersion: 2,
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
} }
// Manifest defines a schema2 manifest. // Manifest defines a schema2 manifest.
@ -16,11 +17,11 @@ type Manifest struct {
docker.Versioned docker.Versioned
// Config references the image configuration as a blob. // Config references the image configuration as a blob.
Config types.Descriptor `json:"config"` Config descriptor.Descriptor `json:"config"`
// Layers lists descriptors for the layers referenced by the // Layers lists descriptors for the layers referenced by the
// configuration. // configuration.
Layers []types.Descriptor `json:"layers"` Layers []descriptor.Descriptor `json:"layers"`
// Annotations contains arbitrary metadata for the image index. // Annotations contains arbitrary metadata for the image index.
// Note, this is not a defined docker schema2 field. // Note, this is not a defined docker schema2 field.

View File

@ -1,14 +1,15 @@
package schema2 package schema2
import ( import (
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker" "github.com/regclient/regclient/types/docker"
"github.com/regclient/regclient/types/mediatype"
) )
// ManifestListSchemaVersion is a pre-configured versioned field for manifest lists // ManifestListSchemaVersion is a pre-configured versioned field for manifest lists
var ManifestListSchemaVersion = docker.Versioned{ var ManifestListSchemaVersion = docker.Versioned{
SchemaVersion: 2, SchemaVersion: 2,
MediaType: types.MediaTypeDocker2ManifestList, MediaType: mediatype.Docker2ManifestList,
} }
// ManifestList references manifests for various platforms. // ManifestList references manifests for various platforms.
@ -16,7 +17,7 @@ type ManifestList struct {
docker.Versioned docker.Versioned
// Manifests lists descriptors in the manifest list // Manifests lists descriptors in the manifest list
Manifests []types.Descriptor `json:"manifests"` Manifests []descriptor.Descriptor `json:"manifests"`
// Annotations contains arbitrary metadata for the image index. // Annotations contains arbitrary metadata for the image index.
// Note, this is not a defined docker schema2 field. // Note, this is not a defined docker schema2 field.

View File

@ -1,86 +1,150 @@
package types package types
import ( import "github.com/regclient/regclient/types/errs"
"errors"
"fmt"
"io/fs"
)
var ( var (
// ErrAllRequestsFailed when there are no mirrors left to try // ErrAllRequestsFailed when there are no mirrors left to try
ErrAllRequestsFailed = errors.New("all requests failed") //
// Deprecated: replace with [errs.ErrAllRequestsFailed].
ErrAllRequestsFailed = errs.ErrAllRequestsFailed
// ErrAPINotFound if an api is not available for the host // ErrAPINotFound if an api is not available for the host
ErrAPINotFound = errors.New("API not found") //
// Deprecated: replace with [errs.ErrAPINotFound].
ErrAPINotFound = errs.ErrAPINotFound
// ErrBackoffLimit maximum backoff attempts reached // ErrBackoffLimit maximum backoff attempts reached
ErrBackoffLimit = errors.New("backoff limit reached") //
// Deprecated: replace with [errs.ErrBackoffLimit].
ErrBackoffLimit = errs.ErrBackoffLimit
// ErrCanceled if the context was canceled // ErrCanceled if the context was canceled
ErrCanceled = errors.New("context was canceled") //
// Deprecated: replace with [errs.ErrCanceled].
ErrCanceled = errs.ErrCanceled
// ErrDigestMismatch if the expected digest wasn't received // ErrDigestMismatch if the expected digest wasn't received
ErrDigestMismatch = errors.New("digest mismatch") //
// Deprecated: replace with [errs.ErrDigestMismatch].
ErrDigestMismatch = errs.ErrDigestMismatch
// ErrEmptyChallenge indicates an issue with the received challenge in the WWW-Authenticate header // ErrEmptyChallenge indicates an issue with the received challenge in the WWW-Authenticate header
ErrEmptyChallenge = errors.New("empty challenge header") //
// Deprecated: replace with [errs.ErrEmptyChallenge].
ErrEmptyChallenge = errs.ErrEmptyChallenge
// ErrFileDeleted indicates a requested file has been deleted // ErrFileDeleted indicates a requested file has been deleted
ErrFileDeleted = errors.New("file deleted") //
// Deprecated: replace with [errs.ErrFileDeleted].
ErrFileDeleted = errs.ErrFileDeleted
// ErrFileNotFound indicates a requested file is not found // ErrFileNotFound indicates a requested file is not found
ErrFileNotFound = fmt.Errorf("file not found%.0w", fs.ErrNotExist) //
// Deprecated: replace with [errs.ErrFileNotFound].
ErrFileNotFound = errs.ErrFileNotFound
// ErrHTTPStatus if the http status code was unexpected // ErrHTTPStatus if the http status code was unexpected
ErrHTTPStatus = errors.New("unexpected http status code") //
// Deprecated: replace with [errs.ErrHTTPStatus].
ErrHTTPStatus = errs.ErrHTTPStatus
// ErrInvalidChallenge indicates an issue with the received challenge in the WWW-Authenticate header // ErrInvalidChallenge indicates an issue with the received challenge in the WWW-Authenticate header
ErrInvalidChallenge = errors.New("invalid challenge header") //
// Deprecated: replace with [errs.ErrInvalidChallenge].
ErrInvalidChallenge = errs.ErrInvalidChallenge
// ErrInvalidReference indicates the reference to an image is has an invalid syntax // ErrInvalidReference indicates the reference to an image is has an invalid syntax
ErrInvalidReference = errors.New("invalid reference") //
// Deprecated: replace with [errs.ErrInvalidReference].
ErrInvalidReference = errs.ErrInvalidReference
// ErrLoopDetected indicates a child node points back to the parent // ErrLoopDetected indicates a child node points back to the parent
ErrLoopDetected = errors.New("loop detected") //
// Deprecated: replace with [errs.ErrLoopDetected].
ErrLoopDetected = errs.ErrLoopDetected
// ErrManifestNotSet indicates the manifest is not set, it must be pulled with a ManifestGet first // ErrManifestNotSet indicates the manifest is not set, it must be pulled with a ManifestGet first
ErrManifestNotSet = errors.New("manifest not set") //
// Deprecated: replace with [errs.ErrManifestNotSet].
ErrManifestNotSet = errs.ErrManifestNotSet
// ErrMissingAnnotation returned when a needed annotation is not found // ErrMissingAnnotation returned when a needed annotation is not found
ErrMissingAnnotation = errors.New("annotation is missing") //
// Deprecated: replace with [errs.ErrMissingAnnotation].
ErrMissingAnnotation = errs.ErrMissingAnnotation
// ErrMissingDigest returned when image reference does not include a digest // ErrMissingDigest returned when image reference does not include a digest
ErrMissingDigest = errors.New("digest missing from image reference") //
// Deprecated: replace with [errs.ErrMissingDigest].
ErrMissingDigest = errs.ErrMissingDigest
// ErrMissingLocation returned when the location header is missing // ErrMissingLocation returned when the location header is missing
ErrMissingLocation = errors.New("location header missing") //
// Deprecated: replace with [errs.ErrMissingLocation].
ErrMissingLocation = errs.ErrMissingLocation
// ErrMissingName returned when name missing for host // ErrMissingName returned when name missing for host
ErrMissingName = errors.New("name missing") //
// Deprecated: replace with [errs.ErrMissingName].
ErrMissingName = errs.ErrMissingName
// ErrMissingTag returned when image reference does not include a tag // ErrMissingTag returned when image reference does not include a tag
ErrMissingTag = errors.New("tag missing from image reference") //
// Deprecated: replace with [errs.ErrMissingTag].
ErrMissingTag = errs.ErrMissingTag
// ErrMissingTagOrDigest returned when image reference does not include a tag or digest // ErrMissingTagOrDigest returned when image reference does not include a tag or digest
ErrMissingTagOrDigest = errors.New("tag or Digest missing from image reference") //
// Deprecated: replace with [errs.ErrMissingTagOrDigest].
ErrMissingTagOrDigest = errs.ErrMissingTagOrDigest
// ErrMismatch returned when a comparison detects a difference // ErrMismatch returned when a comparison detects a difference
ErrMismatch = errors.New("content does not match") //
// Deprecated: replace with [errs.ErrMismatch].
ErrMismatch = errs.ErrMismatch
// ErrMountReturnedLocation when a blob mount fails but a location header is received // ErrMountReturnedLocation when a blob mount fails but a location header is received
ErrMountReturnedLocation = errors.New("blob mount returned a location to upload") //
// Deprecated: replace with [errs.ErrMountReturnedLocation].
ErrMountReturnedLocation = errs.ErrMountReturnedLocation
// ErrNoNewChallenge indicates a challenge update did not result in any change // ErrNoNewChallenge indicates a challenge update did not result in any change
ErrNoNewChallenge = errors.New("no new challenge") //
// Deprecated: replace with [errs.ErrNoNewChallenge].
ErrNoNewChallenge = errs.ErrNoNewChallenge
// ErrNotFound isn't there, search for your value elsewhere // ErrNotFound isn't there, search for your value elsewhere
ErrNotFound = errors.New("not found") //
// Deprecated: replace with [errs.ErrNotFound].
ErrNotFound = errs.ErrNotFound
// ErrNotImplemented returned when method has not been implemented yet // ErrNotImplemented returned when method has not been implemented yet
ErrNotImplemented = errors.New("not implemented") //
// Deprecated: replace with [errs.ErrNotImplemented].
ErrNotImplemented = errs.ErrNotImplemented
// ErrNotRetryable indicates the process cannot be retried // ErrNotRetryable indicates the process cannot be retried
ErrNotRetryable = errors.New("not retryable") //
// Deprecated: replace with [errs.ErrNotRetryable].
ErrNotRetryable = errs.ErrNotRetryable
// ErrParsingFailed when a string cannot be parsed // ErrParsingFailed when a string cannot be parsed
ErrParsingFailed = errors.New("parsing failed") //
// Deprecated: replace with [errs.ErrParsingFailed].
ErrParsingFailed = errs.ErrParsingFailed
// ErrRetryNeeded indicates a request needs to be retried // ErrRetryNeeded indicates a request needs to be retried
ErrRetryNeeded = errors.New("retry needed") //
// Deprecated: replace with [errs.ErrRetryNeeded].
ErrRetryNeeded = errs.ErrRetryNeeded
// ErrShortRead if contents are less than expected the size // ErrShortRead if contents are less than expected the size
ErrShortRead = errors.New("short read") //
// Deprecated: replace with [errs.ErrShortRead].
ErrShortRead = errs.ErrShortRead
// ErrSizeLimitExceeded if contents exceed the size limit // ErrSizeLimitExceeded if contents exceed the size limit
ErrSizeLimitExceeded = errors.New("size limit exceeded") //
// Deprecated: replace with [errs.ErrSizeLimitExceeded].
ErrSizeLimitExceeded = errs.ErrSizeLimitExceeded
// ErrUnavailable when a requested value is not available // ErrUnavailable when a requested value is not available
ErrUnavailable = errors.New("unavailable") //
// Deprecated: replace with [errs.ErrUnavailable].
ErrUnavailable = errs.ErrUnavailable
// ErrUnsupported indicates the request was unsupported // ErrUnsupported indicates the request was unsupported
ErrUnsupported = errors.New("unsupported") //
// Deprecated: replace with [errs.ErrUnsupported].
ErrUnsupported = errs.ErrUnsupported
// ErrUnsupportedAPI happens when an API is not supported on a registry // ErrUnsupportedAPI happens when an API is not supported on a registry
ErrUnsupportedAPI = errors.New("unsupported API") //
// Deprecated: replace with [errs.ErrUnsupportedAPI].
ErrUnsupportedAPI = errs.ErrUnsupportedAPI
// ErrUnsupportedConfigVersion happens when config file version is greater than this command supports // ErrUnsupportedConfigVersion happens when config file version is greater than this command supports
ErrUnsupportedConfigVersion = errors.New("unsupported config version") //
// Deprecated: replace with [errs.ErrUnsupportedConfigVersion].
ErrUnsupportedConfigVersion = errs.ErrUnsupportedConfigVersion
// ErrUnsupportedMediaType returned when media type is unknown or unsupported // ErrUnsupportedMediaType returned when media type is unknown or unsupported
ErrUnsupportedMediaType = errors.New("unsupported media type") //
) // Deprecated: replace with [errs.ErrUnsupportedMediaType].
ErrUnsupportedMediaType = errs.ErrUnsupportedMediaType
// custom HTTP errors extend the ErrHTTPStatus error
var (
// ErrHTTPRateLimit when requests exceed server rate limit // ErrHTTPRateLimit when requests exceed server rate limit
ErrHTTPRateLimit = fmt.Errorf("rate limit exceeded%.0w", ErrHTTPStatus) //
// Deprecated: replace with [errs.ErrHTTPRateLimit].
ErrHTTPRateLimit = errs.ErrHTTPRateLimit
// ErrHTTPUnauthorized when authentication fails // ErrHTTPUnauthorized when authentication fails
ErrHTTPUnauthorized = fmt.Errorf("unauthorized%.0w", ErrHTTPStatus) //
// Deprecated: replace with [errs.ErrHTTPUnauthorized].
ErrHTTPUnauthorized = errs.ErrHTTPUnauthorized
) )

87
types/errs/error.go Normal file
View File

@ -0,0 +1,87 @@
// Package errs is used for predefined error values.
package errs
import (
"errors"
"fmt"
"io/fs"
)
var (
// ErrAllRequestsFailed when there are no mirrors left to try
ErrAllRequestsFailed = errors.New("all requests failed")
// ErrAPINotFound if an api is not available for the host
ErrAPINotFound = errors.New("API not found")
// ErrBackoffLimit maximum backoff attempts reached
ErrBackoffLimit = errors.New("backoff limit reached")
// ErrCanceled if the context was canceled
ErrCanceled = errors.New("context was canceled")
// ErrDigestMismatch if the expected digest wasn't received
ErrDigestMismatch = errors.New("digest mismatch")
// ErrEmptyChallenge indicates an issue with the received challenge in the WWW-Authenticate header
ErrEmptyChallenge = errors.New("empty challenge header")
// ErrFileDeleted indicates a requested file has been deleted
ErrFileDeleted = errors.New("file deleted")
// ErrFileNotFound indicates a requested file is not found
ErrFileNotFound = fmt.Errorf("file not found%.0w", fs.ErrNotExist)
// ErrHTTPStatus if the http status code was unexpected
ErrHTTPStatus = errors.New("unexpected http status code")
// ErrInvalidChallenge indicates an issue with the received challenge in the WWW-Authenticate header
ErrInvalidChallenge = errors.New("invalid challenge header")
// ErrInvalidReference indicates the reference to an image is has an invalid syntax
ErrInvalidReference = errors.New("invalid reference")
// ErrLoopDetected indicates a child node points back to the parent
ErrLoopDetected = errors.New("loop detected")
// ErrManifestNotSet indicates the manifest is not set, it must be pulled with a ManifestGet first
ErrManifestNotSet = errors.New("manifest not set")
// ErrMissingAnnotation returned when a needed annotation is not found
ErrMissingAnnotation = errors.New("annotation is missing")
// ErrMissingDigest returned when image reference does not include a digest
ErrMissingDigest = errors.New("digest missing from image reference")
// ErrMissingLocation returned when the location header is missing
ErrMissingLocation = errors.New("location header missing")
// ErrMissingName returned when name missing for host
ErrMissingName = errors.New("name missing")
// ErrMissingTag returned when image reference does not include a tag
ErrMissingTag = errors.New("tag missing from image reference")
// ErrMissingTagOrDigest returned when image reference does not include a tag or digest
ErrMissingTagOrDigest = errors.New("tag or Digest missing from image reference")
// ErrMismatch returned when a comparison detects a difference
ErrMismatch = errors.New("content does not match")
// ErrMountReturnedLocation when a blob mount fails but a location header is received
ErrMountReturnedLocation = errors.New("blob mount returned a location to upload")
// ErrNoNewChallenge indicates a challenge update did not result in any change
ErrNoNewChallenge = errors.New("no new challenge")
// ErrNotFound isn't there, search for your value elsewhere
ErrNotFound = errors.New("not found")
// ErrNotImplemented returned when method has not been implemented yet
ErrNotImplemented = errors.New("not implemented")
// ErrNotRetryable indicates the process cannot be retried
ErrNotRetryable = errors.New("not retryable")
// ErrParsingFailed when a string cannot be parsed
ErrParsingFailed = errors.New("parsing failed")
// ErrRetryNeeded indicates a request needs to be retried
ErrRetryNeeded = errors.New("retry needed")
// ErrShortRead if contents are less than expected the size
ErrShortRead = errors.New("short read")
// ErrSizeLimitExceeded if contents exceed the size limit
ErrSizeLimitExceeded = errors.New("size limit exceeded")
// ErrUnavailable when a requested value is not available
ErrUnavailable = errors.New("unavailable")
// ErrUnsupported indicates the request was unsupported
ErrUnsupported = errors.New("unsupported")
// ErrUnsupportedAPI happens when an API is not supported on a registry
ErrUnsupportedAPI = errors.New("unsupported API")
// ErrUnsupportedConfigVersion happens when config file version is greater than this command supports
ErrUnsupportedConfigVersion = errors.New("unsupported config version")
// ErrUnsupportedMediaType returned when media type is unknown or unsupported
ErrUnsupportedMediaType = errors.New("unsupported media type")
)
// custom HTTP errors extend the ErrHTTPStatus error
var (
// ErrHTTPRateLimit when requests exceed server rate limit
ErrHTTPRateLimit = fmt.Errorf("rate limit exceeded%.0w", ErrHTTPStatus)
// ErrHTTPUnauthorized when authentication fails
ErrHTTPUnauthorized = fmt.Errorf("unauthorized%.0w", ErrHTTPStatus)
)

View File

@ -12,12 +12,14 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
) )
type common struct { type common struct {
r ref.Ref r ref.Ref
desc types.Descriptor desc descriptor.Descriptor
manifSet bool manifSet bool
ratelimit types.RateLimit ratelimit types.RateLimit
rawHeader http.Header rawHeader http.Header
@ -30,7 +32,7 @@ func (m *common) GetDigest() digest.Digest {
} }
// GetDescriptor returns the descriptor // GetDescriptor returns the descriptor
func (m *common) GetDescriptor() types.Descriptor { func (m *common) GetDescriptor() descriptor.Descriptor {
return m.desc return m.desc
} }
@ -74,7 +76,7 @@ func (m *common) IsSet() bool {
// RawBody returns the raw body from the manifest if available. // RawBody returns the raw body from the manifest if available.
func (m *common) RawBody() ([]byte, error) { func (m *common) RawBody() ([]byte, error) {
if len(m.rawBody) == 0 { if len(m.rawBody) == 0 {
return m.rawBody, types.ErrManifestNotSet return m.rawBody, errs.ErrManifestNotSet
} }
return m.rawBody, nil return m.rawBody, nil
} }

View File

@ -12,8 +12,10 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema1" "github.com/regclient/regclient/types/docker/schema1"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
) )
@ -33,47 +35,47 @@ type docker1SignedManifest struct {
schema1.SignedManifest schema1.SignedManifest
} }
func (m *docker1Manifest) GetConfig() (types.Descriptor, error) { func (m *docker1Manifest) GetConfig() (descriptor.Descriptor, error) {
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return descriptor.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1Manifest) GetConfigDigest() (digest.Digest, error) { func (m *docker1Manifest) GetConfigDigest() (digest.Digest, error) {
return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1SignedManifest) GetConfig() (types.Descriptor, error) { func (m *docker1SignedManifest) GetConfig() (descriptor.Descriptor, error) {
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return descriptor.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1SignedManifest) GetConfigDigest() (digest.Digest, error) { func (m *docker1SignedManifest) GetConfigDigest() (digest.Digest, error) {
return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1Manifest) GetManifestList() ([]types.Descriptor, error) { func (m *docker1Manifest) GetManifestList() ([]descriptor.Descriptor, error) {
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return []descriptor.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1SignedManifest) GetManifestList() ([]types.Descriptor, error) { func (m *docker1SignedManifest) GetManifestList() ([]descriptor.Descriptor, error) {
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return []descriptor.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1Manifest) GetLayers() ([]types.Descriptor, error) { func (m *docker1Manifest) GetLayers() ([]descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return []types.Descriptor{}, types.ErrManifestNotSet return []descriptor.Descriptor{}, errs.ErrManifestNotSet
} }
var dl []types.Descriptor var dl []descriptor.Descriptor
for _, sd := range m.FSLayers { for _, sd := range m.FSLayers {
dl = append(dl, types.Descriptor{ dl = append(dl, descriptor.Descriptor{
Digest: sd.BlobSum, Digest: sd.BlobSum,
}) })
} }
return dl, nil return dl, nil
} }
func (m *docker1SignedManifest) GetLayers() ([]types.Descriptor, error) { func (m *docker1SignedManifest) GetLayers() ([]descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return []types.Descriptor{}, types.ErrManifestNotSet return []descriptor.Descriptor{}, errs.ErrManifestNotSet
} }
var dl []types.Descriptor var dl []descriptor.Descriptor
for _, sd := range m.FSLayers { for _, sd := range m.FSLayers {
dl = append(dl, types.Descriptor{ dl = append(dl, descriptor.Descriptor{
Digest: sd.BlobSum, Digest: sd.BlobSum,
}) })
} }
@ -87,31 +89,31 @@ func (m *docker1SignedManifest) GetOrig() interface{} {
return m.SignedManifest return m.SignedManifest
} }
func (m *docker1Manifest) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) { func (m *docker1Manifest) GetPlatformDesc(p *platform.Platform) (*descriptor.Descriptor, error) {
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1SignedManifest) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) { func (m *docker1SignedManifest) GetPlatformDesc(p *platform.Platform) (*descriptor.Descriptor, error) {
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1Manifest) GetPlatformList() ([]*platform.Platform, error) { func (m *docker1Manifest) GetPlatformList() ([]*platform.Platform, error) {
return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1SignedManifest) GetPlatformList() ([]*platform.Platform, error) { func (m *docker1SignedManifest) GetPlatformList() ([]*platform.Platform, error) {
return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1Manifest) GetSize() (int64, error) { func (m *docker1Manifest) GetSize() (int64, error) {
return 0, fmt.Errorf("GetSize is not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return 0, fmt.Errorf("GetSize is not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1SignedManifest) GetSize() (int64, error) { func (m *docker1SignedManifest) GetSize() (int64, error) {
return 0, fmt.Errorf("GetSize is not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return 0, fmt.Errorf("GetSize is not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1Manifest) MarshalJSON() ([]byte, error) { func (m *docker1Manifest) MarshalJSON() ([]byte, error) {
if !m.manifSet { if !m.manifSet {
return []byte{}, types.ErrManifestNotSet return []byte{}, errs.ErrManifestNotSet
} }
if len(m.rawBody) > 0 { if len(m.rawBody) > 0 {
@ -123,7 +125,7 @@ func (m *docker1Manifest) MarshalJSON() ([]byte, error) {
func (m *docker1SignedManifest) MarshalJSON() ([]byte, error) { func (m *docker1SignedManifest) MarshalJSON() ([]byte, error) {
if !m.manifSet { if !m.manifSet {
return []byte{}, types.ErrManifestNotSet return []byte{}, errs.ErrManifestNotSet
} }
return m.SignedManifest.MarshalJSON() return m.SignedManifest.MarshalJSON()
@ -168,30 +170,30 @@ func (m *docker1SignedManifest) MarshalPretty() ([]byte, error) {
return buf.Bytes(), err return buf.Bytes(), err
} }
func (m *docker1Manifest) SetConfig(d types.Descriptor) error { func (m *docker1Manifest) SetConfig(d descriptor.Descriptor) error {
return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1SignedManifest) SetConfig(d types.Descriptor) error { func (m *docker1SignedManifest) SetConfig(d descriptor.Descriptor) error {
return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1Manifest) SetLayers(dl []types.Descriptor) error { func (m *docker1Manifest) SetLayers(dl []descriptor.Descriptor) error {
return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1SignedManifest) SetLayers(dl []types.Descriptor) error { func (m *docker1SignedManifest) SetLayers(dl []descriptor.Descriptor) error {
return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker1Manifest) SetOrig(origIn interface{}) error { func (m *docker1Manifest) SetOrig(origIn interface{}) error {
orig, ok := origIn.(schema1.Manifest) orig, ok := origIn.(schema1.Manifest)
if !ok { if !ok {
return types.ErrUnsupportedMediaType return errs.ErrUnsupportedMediaType
} }
if orig.MediaType != types.MediaTypeDocker1Manifest { if orig.MediaType != mediatype.Docker1Manifest {
// TODO: error? // TODO: error?
orig.MediaType = types.MediaTypeDocker1Manifest orig.MediaType = mediatype.Docker1Manifest
} }
mj, err := json.Marshal(orig) mj, err := json.Marshal(orig)
if err != nil { if err != nil {
@ -199,8 +201,8 @@ func (m *docker1Manifest) SetOrig(origIn interface{}) error {
} }
m.manifSet = true m.manifSet = true
m.rawBody = mj m.rawBody = mj
m.desc = types.Descriptor{ m.desc = descriptor.Descriptor{
MediaType: types.MediaTypeDocker1Manifest, MediaType: mediatype.Docker1Manifest,
Digest: digest.FromBytes(mj), Digest: digest.FromBytes(mj),
Size: int64(len(mj)), Size: int64(len(mj)),
} }
@ -212,11 +214,11 @@ func (m *docker1Manifest) SetOrig(origIn interface{}) error {
func (m *docker1SignedManifest) SetOrig(origIn interface{}) error { func (m *docker1SignedManifest) SetOrig(origIn interface{}) error {
orig, ok := origIn.(schema1.SignedManifest) orig, ok := origIn.(schema1.SignedManifest)
if !ok { if !ok {
return types.ErrUnsupportedMediaType return errs.ErrUnsupportedMediaType
} }
if orig.MediaType != types.MediaTypeDocker1ManifestSigned { if orig.MediaType != mediatype.Docker1ManifestSigned {
// TODO: error? // TODO: error?
orig.MediaType = types.MediaTypeDocker1ManifestSigned orig.MediaType = mediatype.Docker1ManifestSigned
} }
mj, err := json.Marshal(orig) mj, err := json.Marshal(orig)
if err != nil { if err != nil {
@ -224,8 +226,8 @@ func (m *docker1SignedManifest) SetOrig(origIn interface{}) error {
} }
m.manifSet = true m.manifSet = true
m.rawBody = mj m.rawBody = mj
m.desc = types.Descriptor{ m.desc = descriptor.Descriptor{
MediaType: types.MediaTypeDocker1ManifestSigned, MediaType: mediatype.Docker1ManifestSigned,
Digest: digest.FromBytes(mj), Digest: digest.FromBytes(mj),
Size: int64(len(mj)), Size: int64(len(mj)),
} }

View File

@ -14,16 +14,18 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/internal/units" "github.com/regclient/regclient/internal/units"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
) )
const ( const (
// MediaTypeDocker2Manifest is the media type when pulling manifests from a v2 registry // MediaTypeDocker2Manifest is the media type when pulling manifests from a v2 registry
MediaTypeDocker2Manifest = types.MediaTypeDocker2Manifest MediaTypeDocker2Manifest = mediatype.Docker2Manifest
// MediaTypeDocker2ManifestList is the media type when pulling a manifest list from a v2 registry // MediaTypeDocker2ManifestList is the media type when pulling a manifest list from a v2 registry
MediaTypeDocker2ManifestList = types.MediaTypeDocker2ManifestList MediaTypeDocker2ManifestList = mediatype.Docker2ManifestList
) )
type docker2Manifest struct { type docker2Manifest struct {
@ -37,53 +39,53 @@ type docker2ManifestList struct {
func (m *docker2Manifest) GetAnnotations() (map[string]string, error) { func (m *docker2Manifest) GetAnnotations() (map[string]string, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Annotations, nil return m.Annotations, nil
} }
func (m *docker2Manifest) GetConfig() (types.Descriptor, error) { func (m *docker2Manifest) GetConfig() (descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return types.Descriptor{}, types.ErrManifestNotSet return descriptor.Descriptor{}, errs.ErrManifestNotSet
} }
return m.Config, nil return m.Config, nil
} }
func (m *docker2Manifest) GetConfigDigest() (digest.Digest, error) { func (m *docker2Manifest) GetConfigDigest() (digest.Digest, error) {
if !m.manifSet { if !m.manifSet {
return digest.Digest(""), types.ErrManifestNotSet return digest.Digest(""), errs.ErrManifestNotSet
} }
return m.Config.Digest, nil return m.Config.Digest, nil
} }
func (m *docker2ManifestList) GetAnnotations() (map[string]string, error) { func (m *docker2ManifestList) GetAnnotations() (map[string]string, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Annotations, nil return m.Annotations, nil
} }
func (m *docker2ManifestList) GetConfig() (types.Descriptor, error) { func (m *docker2ManifestList) GetConfig() (descriptor.Descriptor, error) {
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return descriptor.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker2ManifestList) GetConfigDigest() (digest.Digest, error) { func (m *docker2ManifestList) GetConfigDigest() (digest.Digest, error) {
return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker2Manifest) GetManifestList() ([]types.Descriptor, error) { func (m *docker2Manifest) GetManifestList() ([]descriptor.Descriptor, error) {
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return []descriptor.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker2ManifestList) GetManifestList() ([]types.Descriptor, error) { func (m *docker2ManifestList) GetManifestList() ([]descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return []types.Descriptor{}, types.ErrManifestNotSet return []descriptor.Descriptor{}, errs.ErrManifestNotSet
} }
return m.Manifests, nil return m.Manifests, nil
} }
func (m *docker2Manifest) GetLayers() ([]types.Descriptor, error) { func (m *docker2Manifest) GetLayers() ([]descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return []types.Descriptor{}, types.ErrManifestNotSet return []descriptor.Descriptor{}, errs.ErrManifestNotSet
} }
return m.Layers, nil return m.Layers, nil
} }
func (m *docker2ManifestList) GetLayers() ([]types.Descriptor, error) { func (m *docker2ManifestList) GetLayers() ([]descriptor.Descriptor, error) {
return []types.Descriptor{}, fmt.Errorf("layers are not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return []descriptor.Descriptor{}, fmt.Errorf("layers are not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker2Manifest) GetOrig() interface{} { func (m *docker2Manifest) GetOrig() interface{} {
@ -93,17 +95,17 @@ func (m *docker2ManifestList) GetOrig() interface{} {
return m.ManifestList return m.ManifestList
} }
func (m *docker2Manifest) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) { func (m *docker2Manifest) GetPlatformDesc(p *platform.Platform) (*descriptor.Descriptor, error) {
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker2ManifestList) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) { func (m *docker2ManifestList) GetPlatformDesc(p *platform.Platform) (*descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
if p == nil { if p == nil {
return nil, fmt.Errorf("invalid input, platform is nil%.0w", types.ErrNotFound) return nil, fmt.Errorf("invalid input, platform is nil%.0w", errs.ErrNotFound)
} }
d, err := types.DescriptorListSearch(m.Manifests, types.MatchOpt{Platform: p}) d, err := descriptor.DescriptorListSearch(m.Manifests, descriptor.MatchOpt{Platform: p})
if err != nil { if err != nil {
return nil, fmt.Errorf("platform not found: %s%.0w", *p, err) return nil, fmt.Errorf("platform not found: %s%.0w", *p, err)
} }
@ -111,7 +113,7 @@ func (m *docker2ManifestList) GetPlatformDesc(p *platform.Platform) (*types.Desc
} }
func (m *docker2Manifest) GetPlatformList() ([]*platform.Platform, error) { func (m *docker2Manifest) GetPlatformList() ([]*platform.Platform, error) {
return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *docker2ManifestList) GetPlatformList() ([]*platform.Platform, error) { func (m *docker2ManifestList) GetPlatformList() ([]*platform.Platform, error) {
dl, err := m.GetManifestList() dl, err := m.GetManifestList()
@ -124,7 +126,7 @@ func (m *docker2ManifestList) GetPlatformList() ([]*platform.Platform, error) {
// GetSize returns the size in bytes of all layers // GetSize returns the size in bytes of all layers
func (m *docker2Manifest) GetSize() (int64, error) { func (m *docker2Manifest) GetSize() (int64, error) {
if !m.manifSet { if !m.manifSet {
return 0, types.ErrManifestNotSet return 0, errs.ErrManifestNotSet
} }
var total int64 var total int64
for _, d := range m.Layers { for _, d := range m.Layers {
@ -135,7 +137,7 @@ func (m *docker2Manifest) GetSize() (int64, error) {
func (m *docker2Manifest) MarshalJSON() ([]byte, error) { func (m *docker2Manifest) MarshalJSON() ([]byte, error) {
if !m.manifSet { if !m.manifSet {
return []byte{}, types.ErrManifestNotSet return []byte{}, errs.ErrManifestNotSet
} }
if len(m.rawBody) > 0 { if len(m.rawBody) > 0 {
return m.rawBody, nil return m.rawBody, nil
@ -144,7 +146,7 @@ func (m *docker2Manifest) MarshalJSON() ([]byte, error) {
} }
func (m *docker2ManifestList) MarshalJSON() ([]byte, error) { func (m *docker2ManifestList) MarshalJSON() ([]byte, error) {
if !m.manifSet { if !m.manifSet {
return []byte{}, types.ErrManifestNotSet return []byte{}, errs.ErrManifestNotSet
} }
if len(m.rawBody) > 0 { if len(m.rawBody) > 0 {
return m.rawBody, nil return m.rawBody, nil
@ -241,7 +243,7 @@ func (m *docker2ManifestList) MarshalPretty() ([]byte, error) {
func (m *docker2Manifest) SetAnnotation(key, val string) error { func (m *docker2Manifest) SetAnnotation(key, val string) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
if m.Annotations == nil { if m.Annotations == nil {
m.Annotations = map[string]string{} m.Annotations = map[string]string{}
@ -255,7 +257,7 @@ func (m *docker2Manifest) SetAnnotation(key, val string) error {
} }
func (m *docker2ManifestList) SetAnnotation(key, val string) error { func (m *docker2ManifestList) SetAnnotation(key, val string) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
if m.Annotations == nil { if m.Annotations == nil {
m.Annotations = map[string]string{} m.Annotations = map[string]string{}
@ -268,25 +270,25 @@ func (m *docker2ManifestList) SetAnnotation(key, val string) error {
return m.updateDesc() return m.updateDesc()
} }
func (m *docker2Manifest) SetConfig(d types.Descriptor) error { func (m *docker2Manifest) SetConfig(d descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.Config = d m.Config = d
return m.updateDesc() return m.updateDesc()
} }
func (m *docker2Manifest) SetLayers(dl []types.Descriptor) error { func (m *docker2Manifest) SetLayers(dl []descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.Layers = dl m.Layers = dl
return m.updateDesc() return m.updateDesc()
} }
func (m *docker2ManifestList) SetManifestList(dl []types.Descriptor) error { func (m *docker2ManifestList) SetManifestList(dl []descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.Manifests = dl m.Manifests = dl
return m.updateDesc() return m.updateDesc()
@ -295,11 +297,11 @@ func (m *docker2ManifestList) SetManifestList(dl []types.Descriptor) error {
func (m *docker2Manifest) SetOrig(origIn interface{}) error { func (m *docker2Manifest) SetOrig(origIn interface{}) error {
orig, ok := origIn.(schema2.Manifest) orig, ok := origIn.(schema2.Manifest)
if !ok { if !ok {
return types.ErrUnsupportedMediaType return errs.ErrUnsupportedMediaType
} }
if orig.MediaType != types.MediaTypeDocker2Manifest { if orig.MediaType != mediatype.Docker2Manifest {
// TODO: error? // TODO: error?
orig.MediaType = types.MediaTypeDocker2Manifest orig.MediaType = mediatype.Docker2Manifest
} }
m.manifSet = true m.manifSet = true
m.Manifest = orig m.Manifest = orig
@ -309,11 +311,11 @@ func (m *docker2Manifest) SetOrig(origIn interface{}) error {
func (m *docker2ManifestList) SetOrig(origIn interface{}) error { func (m *docker2ManifestList) SetOrig(origIn interface{}) error {
orig, ok := origIn.(schema2.ManifestList) orig, ok := origIn.(schema2.ManifestList)
if !ok { if !ok {
return types.ErrUnsupportedMediaType return errs.ErrUnsupportedMediaType
} }
if orig.MediaType != types.MediaTypeDocker2ManifestList { if orig.MediaType != mediatype.Docker2ManifestList {
// TODO: error? // TODO: error?
orig.MediaType = types.MediaTypeDocker2ManifestList orig.MediaType = mediatype.Docker2ManifestList
} }
m.manifSet = true m.manifSet = true
m.ManifestList = orig m.ManifestList = orig
@ -326,8 +328,8 @@ func (m *docker2Manifest) updateDesc() error {
return err return err
} }
m.rawBody = mj m.rawBody = mj
m.desc = types.Descriptor{ m.desc = descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Digest: digest.FromBytes(mj), Digest: digest.FromBytes(mj),
Size: int64(len(mj)), Size: int64(len(mj)),
} }
@ -339,8 +341,8 @@ func (m *docker2ManifestList) updateDesc() error {
return err return err
} }
m.rawBody = mj m.rawBody = mj
m.desc = types.Descriptor{ m.desc = descriptor.Descriptor{
MediaType: types.MediaTypeDocker2ManifestList, MediaType: mediatype.Docker2ManifestList,
Digest: digest.FromBytes(mj), Digest: digest.FromBytes(mj),
Size: int64(len(mj)), Size: int64(len(mj)),
} }

View File

@ -17,8 +17,11 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types"
"github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema1" "github.com/regclient/regclient/types/docker/schema1"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -27,7 +30,7 @@ import (
// Manifest interface is implemented by all supported manifests but // Manifest interface is implemented by all supported manifests but
// many calls are only supported by certain underlying media types. // many calls are only supported by certain underlying media types.
type Manifest interface { type Manifest interface {
GetDescriptor() types.Descriptor GetDescriptor() descriptor.Descriptor
GetOrig() interface{} GetOrig() interface{}
GetRef() ref.Ref GetRef() ref.Ref
IsList() bool IsList() bool
@ -38,12 +41,12 @@ type Manifest interface {
SetOrig(interface{}) error SetOrig(interface{}) error
// Deprecated: GetConfig should be accessed using [Imager] interface. // Deprecated: GetConfig should be accessed using [Imager] interface.
GetConfig() (types.Descriptor, error) GetConfig() (descriptor.Descriptor, error)
// Deprecated: GetLayers should be accessed using [Imager] interface. // Deprecated: GetLayers should be accessed using [Imager] interface.
GetLayers() ([]types.Descriptor, error) GetLayers() ([]descriptor.Descriptor, error)
// Deprecated: GetManifestList should be accessed using [Indexer] interface. // Deprecated: GetManifestList should be accessed using [Indexer] interface.
GetManifestList() ([]types.Descriptor, error) GetManifestList() ([]descriptor.Descriptor, error)
// Deprecated: GetConfigDigest should be replaced with [GetConfig]. // Deprecated: GetConfigDigest should be replaced with [GetConfig].
GetConfigDigest() (digest.Digest, error) GetConfigDigest() (digest.Digest, error)
@ -52,7 +55,7 @@ type Manifest interface {
// Deprecated: GetMediaType should be replaced with GetDescriptor().MediaType, see [GetDescriptor]. // Deprecated: GetMediaType should be replaced with GetDescriptor().MediaType, see [GetDescriptor].
GetMediaType() string GetMediaType() string
// Deprecated: GetPlatformDesc method should be replaced with [manifest.GetPlatformDesc]. // Deprecated: GetPlatformDesc method should be replaced with [manifest.GetPlatformDesc].
GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) GetPlatformDesc(p *platform.Platform) (*descriptor.Descriptor, error)
// Deprecated: GetPlatformList method should be replaced with [manifest.GetPlatformList]. // Deprecated: GetPlatformList method should be replaced with [manifest.GetPlatformList].
GetPlatformList() ([]*platform.Platform, error) GetPlatformList() ([]*platform.Platform, error)
// Deprecated: GetRateLimit method should be replaced with [manifest.GetRateLimit]. // Deprecated: GetRateLimit method should be replaced with [manifest.GetRateLimit].
@ -70,28 +73,28 @@ type Annotator interface {
// Indexer is used by manifests that contain a manifest list. // Indexer is used by manifests that contain a manifest list.
type Indexer interface { type Indexer interface {
GetManifestList() ([]types.Descriptor, error) GetManifestList() ([]descriptor.Descriptor, error)
SetManifestList(dl []types.Descriptor) error SetManifestList(dl []descriptor.Descriptor) error
} }
// Imager is used by manifests packaging an image. // Imager is used by manifests packaging an image.
type Imager interface { type Imager interface {
GetConfig() (types.Descriptor, error) GetConfig() (descriptor.Descriptor, error)
GetLayers() ([]types.Descriptor, error) GetLayers() ([]descriptor.Descriptor, error)
SetConfig(d types.Descriptor) error SetConfig(d descriptor.Descriptor) error
SetLayers(dl []types.Descriptor) error SetLayers(dl []descriptor.Descriptor) error
GetSize() (int64, error) GetSize() (int64, error)
} }
// Subjecter is used by manifests that may have a subject field. // Subjecter is used by manifests that may have a subject field.
type Subjecter interface { type Subjecter interface {
GetSubject() (*types.Descriptor, error) GetSubject() (*descriptor.Descriptor, error)
SetSubject(d *types.Descriptor) error SetSubject(d *descriptor.Descriptor) error
} }
type manifestConfig struct { type manifestConfig struct {
r ref.Ref r ref.Ref
desc types.Descriptor desc descriptor.Descriptor
raw []byte raw []byte
orig interface{} orig interface{}
header http.Header header http.Header
@ -113,7 +116,7 @@ func New(opts ...Opts) (Manifest, error) {
// extract fields from header where available // extract fields from header where available
if mc.header != nil { if mc.header != nil {
if c.desc.MediaType == "" { if c.desc.MediaType == "" {
c.desc.MediaType = types.MediaTypeBase(mc.header.Get("Content-Type")) c.desc.MediaType = mediatype.Base(mc.header.Get("Content-Type"))
} }
if c.desc.Size == 0 { if c.desc.Size == 0 {
cl, _ := strconv.Atoi(mc.header.Get("Content-Length")) cl, _ := strconv.Atoi(mc.header.Get("Content-Length"))
@ -131,7 +134,7 @@ func New(opts ...Opts) (Manifest, error) {
} }
// WithDesc specifies the descriptor for the manifest. // WithDesc specifies the descriptor for the manifest.
func WithDesc(desc types.Descriptor) Opts { func WithDesc(desc descriptor.Descriptor) Opts {
return func(mc *manifestConfig) { return func(mc *manifestConfig) {
mc.desc = desc mc.desc = desc
} }
@ -178,15 +181,15 @@ func GetMediaType(m Manifest) string {
} }
// GetPlatformDesc returns the descriptor for a specific platform from an index. // GetPlatformDesc returns the descriptor for a specific platform from an index.
func GetPlatformDesc(m Manifest, p *platform.Platform) (*types.Descriptor, error) { func GetPlatformDesc(m Manifest, p *platform.Platform) (*descriptor.Descriptor, error) {
dl, err := m.GetManifestList() dl, err := m.GetManifestList()
if err != nil { if err != nil {
return nil, err return nil, err
} }
if p == nil { if p == nil {
return nil, fmt.Errorf("invalid input, platform is nil%.0w", types.ErrNotFound) return nil, fmt.Errorf("invalid input, platform is nil%.0w", errs.ErrNotFound)
} }
d, err := types.DescriptorListSearch(dl, types.MatchOpt{Platform: p}) d, err := descriptor.DescriptorListSearch(dl, descriptor.MatchOpt{Platform: p})
if err != nil { if err != nil {
return nil, fmt.Errorf("platform not found: %s%.0w", *p, err) return nil, fmt.Errorf("platform not found: %s%.0w", *p, err)
} }
@ -265,7 +268,7 @@ func HasRateLimit(m Manifest) bool {
func OCIIndexFromAny(orig interface{}) (v1.Index, error) { func OCIIndexFromAny(orig interface{}) (v1.Index, error) {
ociI := v1.Index{ ociI := v1.Index{
Versioned: v1.IndexSchemaVersion, Versioned: v1.IndexSchemaVersion,
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
} }
switch orig := orig.(type) { switch orig := orig.(type) {
case schema2.ManifestList: case schema2.ManifestList:
@ -311,7 +314,7 @@ func OCIIndexToAny(ociI v1.Index, origP interface{}) error {
func OCIManifestFromAny(orig interface{}) (v1.Manifest, error) { func OCIManifestFromAny(orig interface{}) (v1.Manifest, error) {
ociM := v1.Manifest{ ociM := v1.Manifest{
Versioned: v1.ManifestSchemaVersion, Versioned: v1.ManifestSchemaVersion,
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
} }
switch orig := orig.(type) { switch orig := orig.(type) {
case schema2.Manifest: case schema2.Manifest:
@ -382,14 +385,14 @@ func fromOrig(c common, orig interface{}) (Manifest, error) {
switch mOrig := orig.(type) { switch mOrig := orig.(type) {
case schema1.Manifest: case schema1.Manifest:
mt = mOrig.MediaType mt = mOrig.MediaType
c.desc.MediaType = types.MediaTypeDocker1Manifest c.desc.MediaType = mediatype.Docker1Manifest
m = &docker1Manifest{ m = &docker1Manifest{
common: c, common: c,
Manifest: mOrig, Manifest: mOrig,
} }
case schema1.SignedManifest: case schema1.SignedManifest:
mt = mOrig.MediaType mt = mOrig.MediaType
c.desc.MediaType = types.MediaTypeDocker1ManifestSigned c.desc.MediaType = mediatype.Docker1ManifestSigned
// recompute digest on the canonical data // recompute digest on the canonical data
c.desc.Digest = digest.FromBytes(mOrig.Canonical) c.desc.Digest = digest.FromBytes(mOrig.Canonical)
m = &docker1SignedManifest{ m = &docker1SignedManifest{
@ -398,35 +401,35 @@ func fromOrig(c common, orig interface{}) (Manifest, error) {
} }
case schema2.Manifest: case schema2.Manifest:
mt = mOrig.MediaType mt = mOrig.MediaType
c.desc.MediaType = types.MediaTypeDocker2Manifest c.desc.MediaType = mediatype.Docker2Manifest
m = &docker2Manifest{ m = &docker2Manifest{
common: c, common: c,
Manifest: mOrig, Manifest: mOrig,
} }
case schema2.ManifestList: case schema2.ManifestList:
mt = mOrig.MediaType mt = mOrig.MediaType
c.desc.MediaType = types.MediaTypeDocker2ManifestList c.desc.MediaType = mediatype.Docker2ManifestList
m = &docker2ManifestList{ m = &docker2ManifestList{
common: c, common: c,
ManifestList: mOrig, ManifestList: mOrig,
} }
case v1.Manifest: case v1.Manifest:
mt = mOrig.MediaType mt = mOrig.MediaType
c.desc.MediaType = types.MediaTypeOCI1Manifest c.desc.MediaType = mediatype.OCI1Manifest
m = &oci1Manifest{ m = &oci1Manifest{
common: c, common: c,
Manifest: mOrig, Manifest: mOrig,
} }
case v1.Index: case v1.Index:
mt = mOrig.MediaType mt = mOrig.MediaType
c.desc.MediaType = types.MediaTypeOCI1ManifestList c.desc.MediaType = mediatype.OCI1ManifestList
m = &oci1Index{ m = &oci1Index{
common: c, common: c,
Index: orig.(v1.Index), Index: orig.(v1.Index),
} }
case v1.ArtifactManifest: case v1.ArtifactManifest:
mt = mOrig.MediaType mt = mOrig.MediaType
c.desc.MediaType = types.MediaTypeOCI1Artifact c.desc.MediaType = mediatype.OCI1Artifact
m = &oci1Artifact{ m = &oci1Artifact{
common: c, common: c,
ArtifactManifest: mOrig, ArtifactManifest: mOrig,
@ -458,49 +461,49 @@ func fromCommon(c common) (Manifest, error) {
// extract media type from body, either explicitly or with duck typing // extract media type from body, either explicitly or with duck typing
if c.desc.MediaType == "" { if c.desc.MediaType == "" {
mt := struct { mt := struct {
MediaType string `json:"mediaType,omitempty"` MediaType string `json:"mediaType,omitempty"`
SchemaVersion int `json:"schemaVersion,omitempty"` SchemaVersion int `json:"schemaVersion,omitempty"`
Signatures []interface{} `json:"signatures,omitempty"` Signatures []interface{} `json:"signatures,omitempty"`
Manifests []types.Descriptor `json:"manifests,omitempty"` Manifests []descriptor.Descriptor `json:"manifests,omitempty"`
Layers []types.Descriptor `json:"layers,omitempty"` Layers []descriptor.Descriptor `json:"layers,omitempty"`
}{} }{}
err = json.Unmarshal(c.rawBody, &mt) err = json.Unmarshal(c.rawBody, &mt)
if mt.MediaType != "" { if mt.MediaType != "" {
c.desc.MediaType = mt.MediaType c.desc.MediaType = mt.MediaType
} else if mt.SchemaVersion == 1 && len(mt.Signatures) > 0 { } else if mt.SchemaVersion == 1 && len(mt.Signatures) > 0 {
c.desc.MediaType = types.MediaTypeDocker1ManifestSigned c.desc.MediaType = mediatype.Docker1ManifestSigned
} else if mt.SchemaVersion == 1 { } else if mt.SchemaVersion == 1 {
c.desc.MediaType = types.MediaTypeDocker1Manifest c.desc.MediaType = mediatype.Docker1Manifest
} else if len(mt.Manifests) > 0 { } else if len(mt.Manifests) > 0 {
if strings.HasPrefix(mt.Manifests[0].MediaType, "application/vnd.docker.") { if strings.HasPrefix(mt.Manifests[0].MediaType, "application/vnd.docker.") {
c.desc.MediaType = types.MediaTypeDocker2ManifestList c.desc.MediaType = mediatype.Docker2ManifestList
} else { } else {
c.desc.MediaType = types.MediaTypeOCI1ManifestList c.desc.MediaType = mediatype.OCI1ManifestList
} }
} else if len(mt.Layers) > 0 { } else if len(mt.Layers) > 0 {
if strings.HasPrefix(mt.Layers[0].MediaType, "application/vnd.docker.") { if strings.HasPrefix(mt.Layers[0].MediaType, "application/vnd.docker.") {
c.desc.MediaType = types.MediaTypeDocker2Manifest c.desc.MediaType = mediatype.Docker2Manifest
} else { } else {
c.desc.MediaType = types.MediaTypeOCI1Manifest c.desc.MediaType = mediatype.OCI1Manifest
} }
} }
} }
// compute digest // compute digest
if c.desc.MediaType != types.MediaTypeDocker1ManifestSigned { if c.desc.MediaType != mediatype.Docker1ManifestSigned {
d := digest.FromBytes(c.rawBody) d := digest.FromBytes(c.rawBody)
c.desc.Digest = d c.desc.Digest = d
c.desc.Size = int64(len(c.rawBody)) c.desc.Size = int64(len(c.rawBody))
} }
} }
switch c.desc.MediaType { switch c.desc.MediaType {
case types.MediaTypeDocker1Manifest: case mediatype.Docker1Manifest:
var mOrig schema1.Manifest var mOrig schema1.Manifest
if len(c.rawBody) > 0 { if len(c.rawBody) > 0 {
err = json.Unmarshal(c.rawBody, &mOrig) err = json.Unmarshal(c.rawBody, &mOrig)
mt = mOrig.MediaType mt = mOrig.MediaType
} }
m = &docker1Manifest{common: c, Manifest: mOrig} m = &docker1Manifest{common: c, Manifest: mOrig}
case types.MediaTypeDocker1ManifestSigned: case mediatype.Docker1ManifestSigned:
var mOrig schema1.SignedManifest var mOrig schema1.SignedManifest
if len(c.rawBody) > 0 { if len(c.rawBody) > 0 {
err = json.Unmarshal(c.rawBody, &mOrig) err = json.Unmarshal(c.rawBody, &mOrig)
@ -510,35 +513,35 @@ func fromCommon(c common) (Manifest, error) {
c.desc.Size = int64(len(mOrig.Canonical)) c.desc.Size = int64(len(mOrig.Canonical))
} }
m = &docker1SignedManifest{common: c, SignedManifest: mOrig} m = &docker1SignedManifest{common: c, SignedManifest: mOrig}
case types.MediaTypeDocker2Manifest: case mediatype.Docker2Manifest:
var mOrig schema2.Manifest var mOrig schema2.Manifest
if len(c.rawBody) > 0 { if len(c.rawBody) > 0 {
err = json.Unmarshal(c.rawBody, &mOrig) err = json.Unmarshal(c.rawBody, &mOrig)
mt = mOrig.MediaType mt = mOrig.MediaType
} }
m = &docker2Manifest{common: c, Manifest: mOrig} m = &docker2Manifest{common: c, Manifest: mOrig}
case types.MediaTypeDocker2ManifestList: case mediatype.Docker2ManifestList:
var mOrig schema2.ManifestList var mOrig schema2.ManifestList
if len(c.rawBody) > 0 { if len(c.rawBody) > 0 {
err = json.Unmarshal(c.rawBody, &mOrig) err = json.Unmarshal(c.rawBody, &mOrig)
mt = mOrig.MediaType mt = mOrig.MediaType
} }
m = &docker2ManifestList{common: c, ManifestList: mOrig} m = &docker2ManifestList{common: c, ManifestList: mOrig}
case types.MediaTypeOCI1Manifest: case mediatype.OCI1Manifest:
var mOrig v1.Manifest var mOrig v1.Manifest
if len(c.rawBody) > 0 { if len(c.rawBody) > 0 {
err = json.Unmarshal(c.rawBody, &mOrig) err = json.Unmarshal(c.rawBody, &mOrig)
mt = mOrig.MediaType mt = mOrig.MediaType
} }
m = &oci1Manifest{common: c, Manifest: mOrig} m = &oci1Manifest{common: c, Manifest: mOrig}
case types.MediaTypeOCI1ManifestList: case mediatype.OCI1ManifestList:
var mOrig v1.Index var mOrig v1.Index
if len(c.rawBody) > 0 { if len(c.rawBody) > 0 {
err = json.Unmarshal(c.rawBody, &mOrig) err = json.Unmarshal(c.rawBody, &mOrig)
mt = mOrig.MediaType mt = mOrig.MediaType
} }
m = &oci1Index{common: c, Index: mOrig} m = &oci1Index{common: c, Index: mOrig}
case types.MediaTypeOCI1Artifact: case mediatype.OCI1Artifact:
var mOrig v1.ArtifactManifest var mOrig v1.ArtifactManifest
if len(c.rawBody) > 0 { if len(c.rawBody) > 0 {
err = json.Unmarshal(c.rawBody, &mOrig) err = json.Unmarshal(c.rawBody, &mOrig)
@ -546,7 +549,7 @@ func fromCommon(c common) (Manifest, error) {
} }
m = &oci1Artifact{common: c, ArtifactManifest: mOrig} m = &oci1Artifact{common: c, ArtifactManifest: mOrig}
default: default:
return nil, fmt.Errorf("%w: \"%s\"", types.ErrUnsupportedMediaType, c.desc.MediaType) return nil, fmt.Errorf("%w: \"%s\"", errs.ErrUnsupportedMediaType, c.desc.MediaType)
} }
if err != nil { if err != nil {
return nil, fmt.Errorf("error unmarshaling manifest for %s: %w", c.r.CommonName(), err) return nil, fmt.Errorf("error unmarshaling manifest for %s: %w", c.r.CommonName(), err)
@ -570,7 +573,7 @@ func verifyMT(expected, received string) error {
return nil return nil
} }
func getPlatformList(dl []types.Descriptor) ([]*platform.Platform, error) { func getPlatformList(dl []descriptor.Descriptor) ([]*platform.Platform, error) {
var l []*platform.Platform var l []*platform.Platform
for _, d := range dl { for _, d := range dl {
if d.Platform != nil { if d.Platform != nil {

View File

@ -9,9 +9,11 @@ import (
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/docker/schema1" "github.com/regclient/regclient/types/docker/schema1"
"github.com/regclient/regclient/types/docker/schema2" "github.com/regclient/regclient/types/docker/schema2"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
"github.com/regclient/regclient/types/ref" "github.com/regclient/regclient/types/ref"
@ -418,7 +420,7 @@ func TestNew(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to unmarshal OCI Artifact json: %v", err) t.Fatalf("failed to unmarshal OCI Artifact json: %v", err)
} }
manifestInvalid.MediaType = types.MediaTypeOCI1Manifest manifestInvalid.MediaType = mediatype.OCI1Manifest
err = json.Unmarshal(rawDockerSchema1Signed, &manifestDockerSchema1Signed) err = json.Unmarshal(rawDockerSchema1Signed, &manifestDockerSchema1Signed)
if err != nil { if err != nil {
t.Fatalf("failed to unmarshal docker schema1 signed json: %v", err) t.Fatalf("failed to unmarshal docker schema1 signed json: %v", err)
@ -427,20 +429,20 @@ func TestNew(t *testing.T) {
name string name string
opts []Opts opts []Opts
wantR ref.Ref wantR ref.Ref
wantDesc types.Descriptor wantDesc descriptor.Descriptor
wantE error wantE error
isSet bool isSet bool
testAnnot bool testAnnot bool
hasAnnot bool hasAnnot bool
testPlat string testPlat string
wantPlat types.Descriptor wantPlat descriptor.Descriptor
wantSize int64 wantSize int64
testSubject bool testSubject bool
hasSubject bool hasSubject bool
}{ }{
{ {
name: "empty", name: "empty",
wantE: fmt.Errorf("%w: \"%s\"", types.ErrUnsupportedMediaType, ""), wantE: fmt.Errorf("%w: \"%s\"", errs.ErrUnsupportedMediaType, ""),
}, },
{ {
name: "Docker Schema 2 Manifest", name: "Docker Schema 2 Manifest",
@ -449,8 +451,8 @@ func TestNew(t *testing.T) {
WithRaw(rawDockerSchema2), WithRaw(rawDockerSchema2),
}, },
wantR: r, wantR: r,
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -464,15 +466,15 @@ func TestNew(t *testing.T) {
{ {
name: "Docker Schema 2 Manifest full desc", name: "Docker Schema 2 Manifest full desc",
opts: []Opts{ opts: []Opts{
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
}), }),
WithRaw(rawDockerSchema2), WithRaw(rawDockerSchema2),
}, },
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -499,7 +501,7 @@ func TestNew(t *testing.T) {
testSubject: true, testSubject: true,
hasAnnot: true, hasAnnot: true,
testPlat: "linux/amd64", testPlat: "linux/amd64",
wantPlat: types.Descriptor{ wantPlat: descriptor.Descriptor{
MediaType: "application/vnd.docker.distribution.manifest.v2+json", MediaType: "application/vnd.docker.distribution.manifest.v2+json",
Digest: "sha256:41b9947d8f19e154a5415c88ef71b851d37fa3ceb1de56ffe88d1b616ce503d9", Digest: "sha256:41b9947d8f19e154a5415c88ef71b851d37fa3ceb1de56ffe88d1b616ce503d9",
Size: 1152, Size: 1152,
@ -517,7 +519,7 @@ func TestNew(t *testing.T) {
testSubject: true, testSubject: true,
hasAnnot: true, hasAnnot: true,
testPlat: "darwin/arm64", testPlat: "darwin/arm64",
wantPlat: types.Descriptor{ wantPlat: descriptor.Descriptor{
MediaType: "application/vnd.docker.distribution.manifest.v2+json", MediaType: "application/vnd.docker.distribution.manifest.v2+json",
Digest: "sha256:b302f648065bb2ba542dc75167db065781f296ef72bb504585d652b27b5079ad", Digest: "sha256:b302f648065bb2ba542dc75167db065781f296ef72bb504585d652b27b5079ad",
Size: 1152, Size: 1152,
@ -529,7 +531,7 @@ func TestNew(t *testing.T) {
WithRef(r), WithRef(r),
WithRaw(rawOCI1Artifact), WithRaw(rawOCI1Artifact),
WithHeader(http.Header{ WithHeader(http.Header{
"Content-Type": []string{types.MediaTypeOCI1Artifact}, "Content-Type": []string{mediatype.OCI1Artifact},
"Docker-Content-Digest": []string{digestOCIArtifact.String()}, "Docker-Content-Digest": []string{digestOCIArtifact.String()},
}), }),
}, },
@ -548,8 +550,8 @@ func TestNew(t *testing.T) {
WithRaw(rawOCIImage), WithRaw(rawOCIImage),
}, },
wantR: r, wantR: r,
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: int64(len(rawOCIImage)), Size: int64(len(rawOCIImage)),
Digest: digestOCIImage, Digest: digestOCIImage,
}, },
@ -568,8 +570,8 @@ func TestNew(t *testing.T) {
WithRaw(rawOCIIndex), WithRaw(rawOCIIndex),
}, },
wantR: r, wantR: r,
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Size: int64(len(rawOCIIndex)), Size: int64(len(rawOCIIndex)),
Digest: digestOCIIndex, Digest: digestOCIIndex,
}, },
@ -585,13 +587,13 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithHeader(http.Header{ WithHeader(http.Header{
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))}, "Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
"Docker-Content-Digest": []string{digestDockerSchema2.String()}, "Docker-Content-Digest": []string{digestDockerSchema2.String()},
}), }),
}, },
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -602,13 +604,13 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithHeader(http.Header{ WithHeader(http.Header{
"Content-Type": []string{types.MediaTypeDocker1Manifest}, "Content-Type": []string{mediatype.Docker1Manifest},
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))}, "Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
"Docker-Content-Digest": []string{digestDockerSchema2.String()}, "Docker-Content-Digest": []string{digestDockerSchema2.String()},
}), }),
}, },
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeDocker1Manifest, MediaType: mediatype.Docker1Manifest,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -619,13 +621,13 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithHeader(http.Header{ WithHeader(http.Header{
"Content-Type": []string{types.MediaTypeDocker1ManifestSigned}, "Content-Type": []string{mediatype.Docker1ManifestSigned},
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))}, "Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
"Docker-Content-Digest": []string{digestDockerSchema2.String()}, "Docker-Content-Digest": []string{digestDockerSchema2.String()},
}), }),
}, },
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeDocker1ManifestSigned, MediaType: mediatype.Docker1ManifestSigned,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -636,13 +638,13 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithHeader(http.Header{ WithHeader(http.Header{
"Content-Type": []string{types.MediaTypeDocker2Manifest}, "Content-Type": []string{mediatype.Docker2Manifest},
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))}, "Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
"Docker-Content-Digest": []string{digestDockerSchema2.String()}, "Docker-Content-Digest": []string{digestDockerSchema2.String()},
}), }),
}, },
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -653,13 +655,13 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithHeader(http.Header{ WithHeader(http.Header{
"Content-Type": []string{types.MediaTypeDocker2ManifestList}, "Content-Type": []string{mediatype.Docker2ManifestList},
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))}, "Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
"Docker-Content-Digest": []string{digestDockerSchema2.String()}, "Docker-Content-Digest": []string{digestDockerSchema2.String()},
}), }),
}, },
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2ManifestList, MediaType: mediatype.Docker2ManifestList,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -670,13 +672,13 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithHeader(http.Header{ WithHeader(http.Header{
"Content-Type": []string{types.MediaTypeOCI1Manifest}, "Content-Type": []string{mediatype.OCI1Manifest},
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))}, "Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
"Docker-Content-Digest": []string{digestDockerSchema2.String()}, "Docker-Content-Digest": []string{digestDockerSchema2.String()},
}), }),
}, },
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -687,13 +689,13 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithHeader(http.Header{ WithHeader(http.Header{
"Content-Type": []string{types.MediaTypeOCI1ManifestList}, "Content-Type": []string{mediatype.OCI1ManifestList},
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))}, "Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
"Docker-Content-Digest": []string{digestDockerSchema2.String()}, "Docker-Content-Digest": []string{digestDockerSchema2.String()},
}), }),
}, },
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -704,13 +706,13 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithHeader(http.Header{ WithHeader(http.Header{
"Content-Type": []string{types.MediaTypeOCI1Artifact}, "Content-Type": []string{mediatype.OCI1Artifact},
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))}, "Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
"Docker-Content-Digest": []string{digestDockerSchema2.String()}, "Docker-Content-Digest": []string{digestDockerSchema2.String()},
}), }),
}, },
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Artifact, MediaType: mediatype.OCI1Artifact,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
}, },
@ -731,8 +733,8 @@ func TestNew(t *testing.T) {
name: "Docker Schema 1 Signed Manifest", name: "Docker Schema 1 Signed Manifest",
opts: []Opts{ opts: []Opts{
WithRaw(rawDockerSchema1Signed), WithRaw(rawDockerSchema1Signed),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeDocker1ManifestSigned, MediaType: mediatype.Docker1ManifestSigned,
Digest: digestDockerSchema1Signed, Digest: digestDockerSchema1Signed,
Size: int64(len(rawDockerSchema1Signed)), Size: int64(len(rawDockerSchema1Signed)),
}), }),
@ -757,8 +759,8 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithRaw(rawAmbiguousOCI), WithRaw(rawAmbiguousOCI),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
}), }),
}, },
wantE: nil, wantE: nil,
@ -769,8 +771,8 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithRaw(rawAmbiguousOCI), WithRaw(rawAmbiguousOCI),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
}), }),
}, },
wantE: nil, wantE: nil,
@ -781,30 +783,30 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithRaw(rawOCIImage), WithRaw(rawOCIImage),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
}), }),
}, },
wantE: fmt.Errorf("manifest contains an unexpected media type: expected %s, received %s", types.MediaTypeOCI1ManifestList, types.MediaTypeOCI1Manifest), wantE: fmt.Errorf("manifest contains an unexpected media type: expected %s, received %s", mediatype.OCI1ManifestList, mediatype.OCI1Manifest),
}, },
{ {
name: "Invalid OCI Image", name: "Invalid OCI Image",
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithRaw(rawOCIIndex), WithRaw(rawOCIIndex),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
}), }),
}, },
wantE: fmt.Errorf("manifest contains an unexpected media type: expected %s, received %s", types.MediaTypeOCI1Manifest, types.MediaTypeOCI1ManifestList), wantE: fmt.Errorf("manifest contains an unexpected media type: expected %s, received %s", mediatype.OCI1Manifest, mediatype.OCI1ManifestList),
}, },
{ {
name: "Invalid digest", name: "Invalid digest",
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithRaw(rawDockerSchema2), WithRaw(rawDockerSchema2),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Digest: digestInvalid, Digest: digestInvalid,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
}), }),
@ -816,13 +818,13 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithRef(r), WithRef(r),
WithRaw(rawOCIImage), WithRaw(rawOCIImage),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Digest: digestOCIImage, Digest: digestOCIImage,
Size: int64(len(rawOCIImage)), Size: int64(len(rawOCIImage)),
}), }),
}, },
wantE: fmt.Errorf("manifest contains an unexpected media type: expected %s, received %s", types.MediaTypeOCI1ManifestList, types.MediaTypeOCI1Manifest), wantE: fmt.Errorf("manifest contains an unexpected media type: expected %s, received %s", mediatype.OCI1ManifestList, mediatype.OCI1Manifest),
}, },
{ {
name: "Docker Schema2 Orig", name: "Docker Schema2 Orig",
@ -860,7 +862,7 @@ func TestNew(t *testing.T) {
opts: []Opts{ opts: []Opts{
WithOrig(manifestInvalid), WithOrig(manifestInvalid),
}, },
wantE: fmt.Errorf("manifest contains an unexpected media type: expected %s, received %s", types.MediaTypeDocker2Manifest, types.MediaTypeOCI1Manifest), wantE: fmt.Errorf("manifest contains an unexpected media type: expected %s, received %s", mediatype.Docker2Manifest, mediatype.OCI1Manifest),
}, },
{ {
name: "OCI Image without mediaType", name: "OCI Image without mediaType",
@ -869,8 +871,8 @@ func TestNew(t *testing.T) {
}, },
wantE: nil, wantE: nil,
isSet: true, isSet: true,
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: int64(len(rawOCIImageDuck)), Size: int64(len(rawOCIImageDuck)),
Digest: digestOCIImageDuck, Digest: digestOCIImageDuck,
}, },
@ -882,8 +884,8 @@ func TestNew(t *testing.T) {
}, },
wantE: nil, wantE: nil,
isSet: true, isSet: true,
wantDesc: types.Descriptor{ wantDesc: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Size: int64(len(rawOCIIndexDuck)), Size: int64(len(rawOCIIndexDuck)),
Digest: digestOCIIndexDuck, Digest: digestOCIIndexDuck,
}, },
@ -895,8 +897,8 @@ func TestNew(t *testing.T) {
// - test if manifest is set // - test if manifest is set
// - test raw body // - test raw body
} }
subDesc := types.Descriptor{ subDesc := descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Size: 1234, Size: 1234,
Digest: digest.FromString("test referrer"), Digest: digest.FromString("test referrer"),
} }
@ -939,32 +941,32 @@ func TestNew(t *testing.T) {
if m.IsSet() { if m.IsSet() {
t.Errorf("manifest reports it is set") t.Errorf("manifest reports it is set")
} }
if _, err := m.RawBody(); !errors.Is(err, types.ErrManifestNotSet) && !errors.Is(err, types.ErrUnsupportedMediaType) { if _, err := m.RawBody(); !errors.Is(err, errs.ErrManifestNotSet) && !errors.Is(err, errs.ErrUnsupportedMediaType) {
t.Errorf("RawBody did not return ManifestNotSet: %v", err) t.Errorf("RawBody did not return ManifestNotSet: %v", err)
} }
if _, err := m.MarshalJSON(); !errors.Is(err, types.ErrManifestNotSet) && !errors.Is(err, types.ErrUnsupportedMediaType) { if _, err := m.MarshalJSON(); !errors.Is(err, errs.ErrManifestNotSet) && !errors.Is(err, errs.ErrUnsupportedMediaType) {
t.Errorf("MarshalJSON did not return ManifestNotSet: %v", err) t.Errorf("MarshalJSON did not return ManifestNotSet: %v", err)
} }
if ma, ok := m.(Annotator); ok { if ma, ok := m.(Annotator); ok {
if _, err := ma.GetAnnotations(); !errors.Is(err, types.ErrManifestNotSet) && !errors.Is(err, types.ErrUnsupportedMediaType) { if _, err := ma.GetAnnotations(); !errors.Is(err, errs.ErrManifestNotSet) && !errors.Is(err, errs.ErrUnsupportedMediaType) {
t.Errorf("GetAnnotations did not return ManifestNotSet: %v", err) t.Errorf("GetAnnotations did not return ManifestNotSet: %v", err)
} }
} }
if mi, ok := m.(Indexer); ok { if mi, ok := m.(Indexer); ok {
if _, err := mi.GetManifestList(); !errors.Is(err, types.ErrManifestNotSet) && !errors.Is(err, types.ErrUnsupportedMediaType) { if _, err := mi.GetManifestList(); !errors.Is(err, errs.ErrManifestNotSet) && !errors.Is(err, errs.ErrUnsupportedMediaType) {
t.Errorf("GetManifestList did not return ManifestNotSet: %v", err) t.Errorf("GetManifestList did not return ManifestNotSet: %v", err)
} }
} }
if mi, ok := m.(Imager); ok { if mi, ok := m.(Imager); ok {
if _, err := mi.GetConfig(); !errors.Is(err, types.ErrManifestNotSet) && !errors.Is(err, types.ErrUnsupportedMediaType) { if _, err := mi.GetConfig(); !errors.Is(err, errs.ErrManifestNotSet) && !errors.Is(err, errs.ErrUnsupportedMediaType) {
t.Errorf("GetConfig did not return ManifestNotSet: %v", err) t.Errorf("GetConfig did not return ManifestNotSet: %v", err)
} }
if _, err := mi.GetLayers(); !errors.Is(err, types.ErrManifestNotSet) && !errors.Is(err, types.ErrUnsupportedMediaType) { if _, err := mi.GetLayers(); !errors.Is(err, errs.ErrManifestNotSet) && !errors.Is(err, errs.ErrUnsupportedMediaType) {
t.Errorf("GetLayers did not return ManifestNotSet: %v", err) t.Errorf("GetLayers did not return ManifestNotSet: %v", err)
} }
} }
if ms, ok := m.(Subjecter); ok { if ms, ok := m.(Subjecter); ok {
if _, err := ms.GetSubject(); !errors.Is(err, types.ErrManifestNotSet) && !errors.Is(err, types.ErrUnsupportedMediaType) { if _, err := ms.GetSubject(); !errors.Is(err, errs.ErrManifestNotSet) && !errors.Is(err, errs.ErrUnsupportedMediaType) {
t.Errorf("GetSubject did not return ManifestNotSet: %v", err) t.Errorf("GetSubject did not return ManifestNotSet: %v", err)
} }
} }
@ -973,32 +975,32 @@ func TestNew(t *testing.T) {
if !m.IsSet() { if !m.IsSet() {
t.Errorf("manifest reports it is not set") t.Errorf("manifest reports it is not set")
} }
if _, err := m.RawBody(); errors.Is(err, types.ErrManifestNotSet) { if _, err := m.RawBody(); errors.Is(err, errs.ErrManifestNotSet) {
t.Errorf("RawBody returned ManifestNotSet: %v", err) t.Errorf("RawBody returned ManifestNotSet: %v", err)
} }
if _, err := m.MarshalJSON(); errors.Is(err, types.ErrManifestNotSet) { if _, err := m.MarshalJSON(); errors.Is(err, errs.ErrManifestNotSet) {
t.Errorf("MarshalJSON returned ManifestNotSet: %v", err) t.Errorf("MarshalJSON returned ManifestNotSet: %v", err)
} }
if ma, ok := m.(Annotator); ok { if ma, ok := m.(Annotator); ok {
if _, err := ma.GetAnnotations(); errors.Is(err, types.ErrManifestNotSet) { if _, err := ma.GetAnnotations(); errors.Is(err, errs.ErrManifestNotSet) {
t.Errorf("GetAnnotations returned ManifestNotSet: %v", err) t.Errorf("GetAnnotations returned ManifestNotSet: %v", err)
} }
} }
if mi, ok := m.(Indexer); ok { if mi, ok := m.(Indexer); ok {
if _, err := mi.GetManifestList(); errors.Is(err, types.ErrManifestNotSet) { if _, err := mi.GetManifestList(); errors.Is(err, errs.ErrManifestNotSet) {
t.Errorf("GetManifestList returned ManifestNotSet: %v", err) t.Errorf("GetManifestList returned ManifestNotSet: %v", err)
} }
} }
if mi, ok := m.(Imager); ok { if mi, ok := m.(Imager); ok {
if _, err := mi.GetConfig(); errors.Is(err, types.ErrManifestNotSet) { if _, err := mi.GetConfig(); errors.Is(err, errs.ErrManifestNotSet) {
t.Errorf("GetConfig returned ManifestNotSet: %v", err) t.Errorf("GetConfig returned ManifestNotSet: %v", err)
} }
if _, err := mi.GetLayers(); errors.Is(err, types.ErrManifestNotSet) { if _, err := mi.GetLayers(); errors.Is(err, errs.ErrManifestNotSet) {
t.Errorf("GetLayers returned ManifestNotSet: %v", err) t.Errorf("GetLayers returned ManifestNotSet: %v", err)
} }
} }
if ms, ok := m.(Subjecter); ok { if ms, ok := m.(Subjecter); ok {
if _, err := ms.GetSubject(); errors.Is(err, types.ErrManifestNotSet) { if _, err := ms.GetSubject(); errors.Is(err, errs.ErrManifestNotSet) {
t.Errorf("GetSubject returned ManifestNotSet: %v", err) t.Errorf("GetSubject returned ManifestNotSet: %v", err)
} }
} }
@ -1078,7 +1080,7 @@ func TestNew(t *testing.T) {
func TestModify(t *testing.T) { func TestModify(t *testing.T) {
t.Parallel() t.Parallel()
addDigest := digest.FromString("new layer digest") addDigest := digest.FromString("new layer digest")
addDesc := types.Descriptor{ addDesc := descriptor.Descriptor{
Digest: addDigest, Digest: addDigest,
Size: 42, Size: 42,
Annotations: map[string]string{ Annotations: map[string]string{
@ -1090,22 +1092,22 @@ func TestModify(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
opts []Opts opts []Opts
addDesc types.Descriptor addDesc descriptor.Descriptor
origDesc types.Descriptor origDesc descriptor.Descriptor
}{ }{
{ {
name: "Docker Schema 2 Manifest", name: "Docker Schema 2 Manifest",
opts: []Opts{ opts: []Opts{
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
}), }),
WithRaw(rawDockerSchema2), WithRaw(rawDockerSchema2),
}, },
addDesc: addDesc, addDesc: addDesc,
origDesc: types.Descriptor{ origDesc: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
}, },
@ -1113,16 +1115,16 @@ func TestModify(t *testing.T) {
{ {
name: "Docker Schema 2 List", name: "Docker Schema 2 List",
opts: []Opts{ opts: []Opts{
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeDocker2ManifestList, MediaType: mediatype.Docker2ManifestList,
Digest: digestDockerSchema2List, Digest: digestDockerSchema2List,
Size: int64(len(rawDockerSchema2List)), Size: int64(len(rawDockerSchema2List)),
}), }),
WithRaw(rawDockerSchema2List), WithRaw(rawDockerSchema2List),
}, },
addDesc: addDesc, addDesc: addDesc,
origDesc: types.Descriptor{ origDesc: descriptor.Descriptor{
MediaType: types.MediaTypeDocker2ManifestList, MediaType: mediatype.Docker2ManifestList,
Digest: digestDockerSchema2List, Digest: digestDockerSchema2List,
Size: int64(len(rawDockerSchema2List)), Size: int64(len(rawDockerSchema2List)),
}, },
@ -1131,15 +1133,15 @@ func TestModify(t *testing.T) {
name: "OCI Image", name: "OCI Image",
opts: []Opts{ opts: []Opts{
WithRaw(rawOCIImage), WithRaw(rawOCIImage),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Digest: digestOCIImage, Digest: digestOCIImage,
Size: int64(len(rawOCIImage)), Size: int64(len(rawOCIImage)),
}), }),
}, },
addDesc: addDesc, addDesc: addDesc,
origDesc: types.Descriptor{ origDesc: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Digest: digestOCIImage, Digest: digestOCIImage,
Size: int64(len(rawOCIImage)), Size: int64(len(rawOCIImage)),
}, },
@ -1148,15 +1150,15 @@ func TestModify(t *testing.T) {
name: "OCI Index", name: "OCI Index",
opts: []Opts{ opts: []Opts{
WithRaw(rawOCIIndex), WithRaw(rawOCIIndex),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Digest: digestOCIIndex, Digest: digestOCIIndex,
Size: int64(len(rawOCIIndex)), Size: int64(len(rawOCIIndex)),
}), }),
}, },
addDesc: addDesc, addDesc: addDesc,
origDesc: types.Descriptor{ origDesc: descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Digest: digestOCIIndex, Digest: digestOCIIndex,
Size: int64(len(rawOCIIndex)), Size: int64(len(rawOCIIndex)),
}, },
@ -1298,7 +1300,7 @@ func TestModify(t *testing.T) {
func TestSet(t *testing.T) { func TestSet(t *testing.T) {
t.Parallel() t.Parallel()
addDigest := digest.FromString("new digest") addDigest := digest.FromString("new digest")
addDesc := types.Descriptor{ addDesc := descriptor.Descriptor{
Digest: addDigest, Digest: addDigest,
Size: 42, Size: 42,
Annotations: map[string]string{ Annotations: map[string]string{
@ -1318,21 +1320,21 @@ func TestSet(t *testing.T) {
{ {
name: "Docker Schema 1", name: "Docker Schema 1",
opts: []Opts{ opts: []Opts{
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeDocker1ManifestSigned, MediaType: mediatype.Docker1ManifestSigned,
Digest: digestDockerSchema1Signed, Digest: digestDockerSchema1Signed,
Size: int64(len(rawDockerSchema1Signed)), Size: int64(len(rawDockerSchema1Signed)),
}), }),
WithRaw(rawDockerSchema1Signed), WithRaw(rawDockerSchema1Signed),
}, },
expectImage: true, expectImage: true,
expectErr: types.ErrUnsupportedMediaType, expectErr: errs.ErrUnsupportedMediaType,
}, },
{ {
name: "Docker Schema 2 Manifest", name: "Docker Schema 2 Manifest",
opts: []Opts{ opts: []Opts{
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeDocker2Manifest, MediaType: mediatype.Docker2Manifest,
Digest: digestDockerSchema2, Digest: digestDockerSchema2,
Size: int64(len(rawDockerSchema2)), Size: int64(len(rawDockerSchema2)),
}), }),
@ -1344,8 +1346,8 @@ func TestSet(t *testing.T) {
{ {
name: "Docker Schema 2 List", name: "Docker Schema 2 List",
opts: []Opts{ opts: []Opts{
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeDocker2ManifestList, MediaType: mediatype.Docker2ManifestList,
Digest: digestDockerSchema2List, Digest: digestDockerSchema2List,
Size: int64(len(rawDockerSchema2List)), Size: int64(len(rawDockerSchema2List)),
}), }),
@ -1358,8 +1360,8 @@ func TestSet(t *testing.T) {
name: "OCI Image", name: "OCI Image",
opts: []Opts{ opts: []Opts{
WithRaw(rawOCIImage), WithRaw(rawOCIImage),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Digest: digestOCIImage, Digest: digestOCIImage,
Size: int64(len(rawOCIImage)), Size: int64(len(rawOCIImage)),
}), }),
@ -1371,8 +1373,8 @@ func TestSet(t *testing.T) {
name: "OCI Index", name: "OCI Index",
opts: []Opts{ opts: []Opts{
WithRaw(rawOCIIndex), WithRaw(rawOCIIndex),
WithDesc(types.Descriptor{ WithDesc(descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Digest: digestOCIIndex, Digest: digestOCIIndex,
Size: int64(len(rawOCIIndex)), Size: int64(len(rawOCIIndex)),
}), }),

View File

@ -14,16 +14,18 @@ import (
digest "github.com/opencontainers/go-digest" digest "github.com/opencontainers/go-digest"
"github.com/regclient/regclient/internal/units" "github.com/regclient/regclient/internal/units"
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/errs"
"github.com/regclient/regclient/types/mediatype"
v1 "github.com/regclient/regclient/types/oci/v1" v1 "github.com/regclient/regclient/types/oci/v1"
"github.com/regclient/regclient/types/platform" "github.com/regclient/regclient/types/platform"
) )
const ( const (
// MediaTypeOCI1Manifest OCI v1 manifest media type // MediaTypeOCI1Manifest OCI v1 manifest media type
MediaTypeOCI1Manifest = types.MediaTypeOCI1Manifest MediaTypeOCI1Manifest = mediatype.OCI1Manifest
// MediaTypeOCI1ManifestList OCI v1 manifest list media type // MediaTypeOCI1ManifestList OCI v1 manifest list media type
MediaTypeOCI1ManifestList = types.MediaTypeOCI1ManifestList MediaTypeOCI1ManifestList = mediatype.OCI1ManifestList
) )
type oci1Manifest struct { type oci1Manifest struct {
@ -43,72 +45,72 @@ type oci1Artifact struct {
func (m *oci1Manifest) GetAnnotations() (map[string]string, error) { func (m *oci1Manifest) GetAnnotations() (map[string]string, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Annotations, nil return m.Annotations, nil
} }
func (m *oci1Manifest) GetConfig() (types.Descriptor, error) { func (m *oci1Manifest) GetConfig() (descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return types.Descriptor{}, types.ErrManifestNotSet return descriptor.Descriptor{}, errs.ErrManifestNotSet
} }
return m.Config, nil return m.Config, nil
} }
func (m *oci1Manifest) GetConfigDigest() (digest.Digest, error) { func (m *oci1Manifest) GetConfigDigest() (digest.Digest, error) {
if !m.manifSet { if !m.manifSet {
return digest.Digest(""), types.ErrManifestNotSet return digest.Digest(""), errs.ErrManifestNotSet
} }
return m.Config.Digest, nil return m.Config.Digest, nil
} }
func (m *oci1Index) GetAnnotations() (map[string]string, error) { func (m *oci1Index) GetAnnotations() (map[string]string, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Annotations, nil return m.Annotations, nil
} }
func (m *oci1Index) GetConfig() (types.Descriptor, error) { func (m *oci1Index) GetConfig() (descriptor.Descriptor, error) {
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return descriptor.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Index) GetConfigDigest() (digest.Digest, error) { func (m *oci1Index) GetConfigDigest() (digest.Digest, error) {
return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Artifact) GetAnnotations() (map[string]string, error) { func (m *oci1Artifact) GetAnnotations() (map[string]string, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Annotations, nil return m.Annotations, nil
} }
func (m *oci1Artifact) GetConfig() (types.Descriptor, error) { func (m *oci1Artifact) GetConfig() (descriptor.Descriptor, error) {
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return descriptor.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Artifact) GetConfigDigest() (digest.Digest, error) { func (m *oci1Artifact) GetConfigDigest() (digest.Digest, error) {
return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return "", fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Manifest) GetManifestList() ([]types.Descriptor, error) { func (m *oci1Manifest) GetManifestList() ([]descriptor.Descriptor, error) {
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return []descriptor.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Index) GetManifestList() ([]types.Descriptor, error) { func (m *oci1Index) GetManifestList() ([]descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Manifests, nil return m.Manifests, nil
} }
func (m *oci1Artifact) GetManifestList() ([]types.Descriptor, error) { func (m *oci1Artifact) GetManifestList() ([]descriptor.Descriptor, error) {
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return []descriptor.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Manifest) GetLayers() ([]types.Descriptor, error) { func (m *oci1Manifest) GetLayers() ([]descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Layers, nil return m.Layers, nil
} }
func (m *oci1Index) GetLayers() ([]types.Descriptor, error) { func (m *oci1Index) GetLayers() ([]descriptor.Descriptor, error) {
return []types.Descriptor{}, fmt.Errorf("layers are not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return []descriptor.Descriptor{}, fmt.Errorf("layers are not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Artifact) GetLayers() ([]types.Descriptor, error) { func (m *oci1Artifact) GetLayers() ([]descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Blobs, nil return m.Blobs, nil
} }
@ -123,28 +125,28 @@ func (m *oci1Artifact) GetOrig() interface{} {
return m.ArtifactManifest return m.ArtifactManifest
} }
func (m *oci1Manifest) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) { func (m *oci1Manifest) GetPlatformDesc(p *platform.Platform) (*descriptor.Descriptor, error) {
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Index) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) { func (m *oci1Index) GetPlatformDesc(p *platform.Platform) (*descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
if p == nil { if p == nil {
return nil, fmt.Errorf("invalid input, platform is nil%.0w", types.ErrNotFound) return nil, fmt.Errorf("invalid input, platform is nil%.0w", errs.ErrNotFound)
} }
d, err := types.DescriptorListSearch(m.Manifests, types.MatchOpt{Platform: p}) d, err := descriptor.DescriptorListSearch(m.Manifests, descriptor.MatchOpt{Platform: p})
if err != nil { if err != nil {
return nil, fmt.Errorf("platform not found: %s%.0w", *p, err) return nil, fmt.Errorf("platform not found: %s%.0w", *p, err)
} }
return &d, nil return &d, nil
} }
func (m *oci1Artifact) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) { func (m *oci1Artifact) GetPlatformDesc(p *platform.Platform) (*descriptor.Descriptor, error) {
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Manifest) GetPlatformList() ([]*platform.Platform, error) { func (m *oci1Manifest) GetPlatformList() ([]*platform.Platform, error) {
return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Index) GetPlatformList() ([]*platform.Platform, error) { func (m *oci1Index) GetPlatformList() ([]*platform.Platform, error) {
dl, err := m.GetManifestList() dl, err := m.GetManifestList()
@ -154,12 +156,12 @@ func (m *oci1Index) GetPlatformList() ([]*platform.Platform, error) {
return getPlatformList(dl) return getPlatformList(dl)
} }
func (m *oci1Artifact) GetPlatformList() ([]*platform.Platform, error) { func (m *oci1Artifact) GetPlatformList() ([]*platform.Platform, error) {
return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return nil, fmt.Errorf("platform list not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Manifest) MarshalJSON() ([]byte, error) { func (m *oci1Manifest) MarshalJSON() ([]byte, error) {
if !m.manifSet { if !m.manifSet {
return []byte{}, types.ErrManifestNotSet return []byte{}, errs.ErrManifestNotSet
} }
if len(m.rawBody) > 0 { if len(m.rawBody) > 0 {
@ -168,28 +170,28 @@ func (m *oci1Manifest) MarshalJSON() ([]byte, error) {
return json.Marshal((m.Manifest)) return json.Marshal((m.Manifest))
} }
func (m *oci1Manifest) GetSubject() (*types.Descriptor, error) { func (m *oci1Manifest) GetSubject() (*descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Manifest.Subject, nil return m.Manifest.Subject, nil
} }
func (m *oci1Index) GetSubject() (*types.Descriptor, error) { func (m *oci1Index) GetSubject() (*descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.Index.Subject, nil return m.Index.Subject, nil
} }
func (m *oci1Artifact) GetSubject() (*types.Descriptor, error) { func (m *oci1Artifact) GetSubject() (*descriptor.Descriptor, error) {
if !m.manifSet { if !m.manifSet {
return nil, types.ErrManifestNotSet return nil, errs.ErrManifestNotSet
} }
return m.ArtifactManifest.Subject, nil return m.ArtifactManifest.Subject, nil
} }
func (m *oci1Index) MarshalJSON() ([]byte, error) { func (m *oci1Index) MarshalJSON() ([]byte, error) {
if !m.manifSet { if !m.manifSet {
return []byte{}, types.ErrManifestNotSet return []byte{}, errs.ErrManifestNotSet
} }
if len(m.rawBody) > 0 { if len(m.rawBody) > 0 {
@ -200,7 +202,7 @@ func (m *oci1Index) MarshalJSON() ([]byte, error) {
} }
func (m *oci1Artifact) MarshalJSON() ([]byte, error) { func (m *oci1Artifact) MarshalJSON() ([]byte, error) {
if !m.manifSet { if !m.manifSet {
return []byte{}, types.ErrManifestNotSet return []byte{}, errs.ErrManifestNotSet
} }
if len(m.rawBody) > 0 { if len(m.rawBody) > 0 {
@ -370,7 +372,7 @@ func (m *oci1Artifact) MarshalPretty() ([]byte, error) {
func (m *oci1Manifest) SetAnnotation(key, val string) error { func (m *oci1Manifest) SetAnnotation(key, val string) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
if m.Annotations == nil { if m.Annotations == nil {
m.Annotations = map[string]string{} m.Annotations = map[string]string{}
@ -384,7 +386,7 @@ func (m *oci1Manifest) SetAnnotation(key, val string) error {
} }
func (m *oci1Index) SetAnnotation(key, val string) error { func (m *oci1Index) SetAnnotation(key, val string) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
if m.Annotations == nil { if m.Annotations == nil {
m.Annotations = map[string]string{} m.Annotations = map[string]string{}
@ -398,7 +400,7 @@ func (m *oci1Index) SetAnnotation(key, val string) error {
} }
func (m *oci1Artifact) SetAnnotation(key, val string) error { func (m *oci1Artifact) SetAnnotation(key, val string) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
if m.Annotations == nil { if m.Annotations == nil {
m.Annotations = map[string]string{} m.Annotations = map[string]string{}
@ -411,21 +413,21 @@ func (m *oci1Artifact) SetAnnotation(key, val string) error {
return m.updateDesc() return m.updateDesc()
} }
func (m *oci1Artifact) SetConfig(d types.Descriptor) error { func (m *oci1Artifact) SetConfig(d descriptor.Descriptor) error {
return fmt.Errorf("set config not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType) return fmt.Errorf("set config not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
} }
func (m *oci1Manifest) SetConfig(d types.Descriptor) error { func (m *oci1Manifest) SetConfig(d descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.Config = d m.Config = d
return m.updateDesc() return m.updateDesc()
} }
func (m *oci1Artifact) SetLayers(dl []types.Descriptor) error { func (m *oci1Artifact) SetLayers(dl []descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.Blobs = dl m.Blobs = dl
return m.updateDesc() return m.updateDesc()
@ -434,7 +436,7 @@ func (m *oci1Artifact) SetLayers(dl []types.Descriptor) error {
// GetSize returns the size in bytes of all layers // GetSize returns the size in bytes of all layers
func (m *oci1Manifest) GetSize() (int64, error) { func (m *oci1Manifest) GetSize() (int64, error) {
if !m.manifSet { if !m.manifSet {
return 0, types.ErrManifestNotSet return 0, errs.ErrManifestNotSet
} }
var total int64 var total int64
for _, d := range m.Layers { for _, d := range m.Layers {
@ -446,7 +448,7 @@ func (m *oci1Manifest) GetSize() (int64, error) {
// GetSize returns the size in bytes of all layers // GetSize returns the size in bytes of all layers
func (m *oci1Artifact) GetSize() (int64, error) { func (m *oci1Artifact) GetSize() (int64, error) {
if !m.manifSet { if !m.manifSet {
return 0, types.ErrManifestNotSet return 0, errs.ErrManifestNotSet
} }
var total int64 var total int64
for _, d := range m.Blobs { for _, d := range m.Blobs {
@ -455,17 +457,17 @@ func (m *oci1Artifact) GetSize() (int64, error) {
return total, nil return total, nil
} }
func (m *oci1Manifest) SetLayers(dl []types.Descriptor) error { func (m *oci1Manifest) SetLayers(dl []descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.Layers = dl m.Layers = dl
return m.updateDesc() return m.updateDesc()
} }
func (m *oci1Index) SetManifestList(dl []types.Descriptor) error { func (m *oci1Index) SetManifestList(dl []descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.Manifests = dl m.Manifests = dl
return m.updateDesc() return m.updateDesc()
@ -474,11 +476,11 @@ func (m *oci1Index) SetManifestList(dl []types.Descriptor) error {
func (m *oci1Manifest) SetOrig(origIn interface{}) error { func (m *oci1Manifest) SetOrig(origIn interface{}) error {
orig, ok := origIn.(v1.Manifest) orig, ok := origIn.(v1.Manifest)
if !ok { if !ok {
return types.ErrUnsupportedMediaType return errs.ErrUnsupportedMediaType
} }
if orig.MediaType != types.MediaTypeOCI1Manifest { if orig.MediaType != mediatype.OCI1Manifest {
// TODO: error? // TODO: error?
orig.MediaType = types.MediaTypeOCI1Manifest orig.MediaType = mediatype.OCI1Manifest
} }
m.manifSet = true m.manifSet = true
m.Manifest = orig m.Manifest = orig
@ -489,11 +491,11 @@ func (m *oci1Manifest) SetOrig(origIn interface{}) error {
func (m *oci1Index) SetOrig(origIn interface{}) error { func (m *oci1Index) SetOrig(origIn interface{}) error {
orig, ok := origIn.(v1.Index) orig, ok := origIn.(v1.Index)
if !ok { if !ok {
return types.ErrUnsupportedMediaType return errs.ErrUnsupportedMediaType
} }
if orig.MediaType != types.MediaTypeOCI1ManifestList { if orig.MediaType != mediatype.OCI1ManifestList {
// TODO: error? // TODO: error?
orig.MediaType = types.MediaTypeOCI1ManifestList orig.MediaType = mediatype.OCI1ManifestList
} }
m.manifSet = true m.manifSet = true
m.Index = orig m.Index = orig
@ -501,23 +503,23 @@ func (m *oci1Index) SetOrig(origIn interface{}) error {
return m.updateDesc() return m.updateDesc()
} }
func (m *oci1Artifact) SetSubject(d *types.Descriptor) error { func (m *oci1Artifact) SetSubject(d *descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.ArtifactManifest.Subject = d m.ArtifactManifest.Subject = d
return m.updateDesc() return m.updateDesc()
} }
func (m *oci1Manifest) SetSubject(d *types.Descriptor) error { func (m *oci1Manifest) SetSubject(d *descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.Manifest.Subject = d m.Manifest.Subject = d
return m.updateDesc() return m.updateDesc()
} }
func (m *oci1Index) SetSubject(d *types.Descriptor) error { func (m *oci1Index) SetSubject(d *descriptor.Descriptor) error {
if !m.manifSet { if !m.manifSet {
return types.ErrManifestNotSet return errs.ErrManifestNotSet
} }
m.Index.Subject = d m.Index.Subject = d
return m.updateDesc() return m.updateDesc()
@ -526,11 +528,11 @@ func (m *oci1Index) SetSubject(d *types.Descriptor) error {
func (m *oci1Artifact) SetOrig(origIn interface{}) error { func (m *oci1Artifact) SetOrig(origIn interface{}) error {
orig, ok := origIn.(v1.ArtifactManifest) orig, ok := origIn.(v1.ArtifactManifest)
if !ok { if !ok {
return types.ErrUnsupportedMediaType return errs.ErrUnsupportedMediaType
} }
if orig.MediaType != types.MediaTypeOCI1Artifact { if orig.MediaType != mediatype.OCI1Artifact {
// TODO: error? // TODO: error?
orig.MediaType = types.MediaTypeOCI1Artifact orig.MediaType = mediatype.OCI1Artifact
} }
m.manifSet = true m.manifSet = true
m.ArtifactManifest = orig m.ArtifactManifest = orig
@ -544,8 +546,8 @@ func (m *oci1Manifest) updateDesc() error {
return err return err
} }
m.rawBody = mj m.rawBody = mj
m.desc = types.Descriptor{ m.desc = descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Manifest, MediaType: mediatype.OCI1Manifest,
Digest: digest.FromBytes(mj), Digest: digest.FromBytes(mj),
Size: int64(len(mj)), Size: int64(len(mj)),
} }
@ -557,8 +559,8 @@ func (m *oci1Index) updateDesc() error {
return err return err
} }
m.rawBody = mj m.rawBody = mj
m.desc = types.Descriptor{ m.desc = descriptor.Descriptor{
MediaType: types.MediaTypeOCI1ManifestList, MediaType: mediatype.OCI1ManifestList,
Digest: digest.FromBytes(mj), Digest: digest.FromBytes(mj),
Size: int64(len(mj)), Size: int64(len(mj)),
} }
@ -570,8 +572,8 @@ func (m *oci1Artifact) updateDesc() error {
return err return err
} }
m.rawBody = mj m.rawBody = mj
m.desc = types.Descriptor{ m.desc = descriptor.Descriptor{
MediaType: types.MediaTypeOCI1Artifact, MediaType: mediatype.OCI1Artifact,
Digest: digest.FromBytes(mj), Digest: digest.FromBytes(mj),
Size: int64(len(mj)), Size: int64(len(mj)),
} }

View File

@ -1,50 +1,91 @@
package types package types
import "strings" import (
"github.com/regclient/regclient/types/mediatype"
)
const ( const (
// MediaTypeDocker1Manifest deprecated media type for docker schema1 manifests. // MediaTypeDocker1Manifest deprecated media type for docker schema1 manifests.
MediaTypeDocker1Manifest = "application/vnd.docker.distribution.manifest.v1+json" //
// Deprecated: replace with [mediatype.Docker1Manifest].
MediaTypeDocker1Manifest = mediatype.Docker1Manifest
// MediaTypeDocker1ManifestSigned is a deprecated schema1 manifest with jws signing. // MediaTypeDocker1ManifestSigned is a deprecated schema1 manifest with jws signing.
MediaTypeDocker1ManifestSigned = "application/vnd.docker.distribution.manifest.v1+prettyjws" //
// Deprecated: replace with [mediatype.Docker1ManifestSigned].
MediaTypeDocker1ManifestSigned = mediatype.Docker1ManifestSigned
// MediaTypeDocker2Manifest is the media type when pulling manifests from a v2 registry. // MediaTypeDocker2Manifest is the media type when pulling manifests from a v2 registry.
MediaTypeDocker2Manifest = "application/vnd.docker.distribution.manifest.v2+json" //
// Deprecated: replace with [mediatype.Docker2Manifest].
MediaTypeDocker2Manifest = mediatype.Docker2Manifest
// MediaTypeDocker2ManifestList is the media type when pulling a manifest list from a v2 registry. // MediaTypeDocker2ManifestList is the media type when pulling a manifest list from a v2 registry.
MediaTypeDocker2ManifestList = "application/vnd.docker.distribution.manifest.list.v2+json" //
// Deprecated: replace with [mediatype.Docker2ManifestList].
MediaTypeDocker2ManifestList = mediatype.Docker2ManifestList
// MediaTypeDocker2ImageConfig is for the configuration json object media type. // MediaTypeDocker2ImageConfig is for the configuration json object media type.
MediaTypeDocker2ImageConfig = "application/vnd.docker.container.image.v1+json" //
// Deprecated: replace with [mediatype.Docker2ImageConfig].
MediaTypeDocker2ImageConfig = mediatype.Docker2ImageConfig
// MediaTypeOCI1Artifact EXPERIMENTAL OCI v1 artifact media type. // MediaTypeOCI1Artifact EXPERIMENTAL OCI v1 artifact media type.
MediaTypeOCI1Artifact = "application/vnd.oci.artifact.manifest.v1+json" //
// Deprecated: replace with [mediatype.OCI1Artifact].
MediaTypeOCI1Artifact = mediatype.OCI1Artifact
// MediaTypeOCI1Manifest OCI v1 manifest media type. // MediaTypeOCI1Manifest OCI v1 manifest media type.
MediaTypeOCI1Manifest = "application/vnd.oci.image.manifest.v1+json" //
// Deprecated: replace with [mediatype.OCI1Manifest].
MediaTypeOCI1Manifest = mediatype.OCI1Manifest
// MediaTypeOCI1ManifestList OCI v1 manifest list media type. // MediaTypeOCI1ManifestList OCI v1 manifest list media type.
MediaTypeOCI1ManifestList = "application/vnd.oci.image.index.v1+json" //
// Deprecated: replace with [mediatype.OCI1ManifestList].
MediaTypeOCI1ManifestList = mediatype.OCI1ManifestList
// MediaTypeOCI1ImageConfig OCI v1 configuration json object media type. // MediaTypeOCI1ImageConfig OCI v1 configuration json object media type.
MediaTypeOCI1ImageConfig = "application/vnd.oci.image.config.v1+json" //
// Deprecated: replace with [mediatype.OCI1ImageConfig].
MediaTypeOCI1ImageConfig = mediatype.OCI1ImageConfig
// MediaTypeDocker2LayerGzip is the default compressed layer for docker schema2. // MediaTypeDocker2LayerGzip is the default compressed layer for docker schema2.
MediaTypeDocker2LayerGzip = "application/vnd.docker.image.rootfs.diff.tar.gzip" //
// Deprecated: replace with [mediatype.Docker2LayerGzip].
MediaTypeDocker2LayerGzip = mediatype.Docker2LayerGzip
// MediaTypeDocker2ForeignLayer is the default compressed layer for foreign layers in docker schema2. // MediaTypeDocker2ForeignLayer is the default compressed layer for foreign layers in docker schema2.
MediaTypeDocker2ForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip" //
// Deprecated: replace with [mediatype.Docker2ForeignLayer].
MediaTypeDocker2ForeignLayer = mediatype.Docker2ForeignLayer
// MediaTypeOCI1Layer is the uncompressed layer for OCIv1. // MediaTypeOCI1Layer is the uncompressed layer for OCIv1.
MediaTypeOCI1Layer = "application/vnd.oci.image.layer.v1.tar" //
// Deprecated: replace with [mediatype.OCI1Layer].
MediaTypeOCI1Layer = mediatype.OCI1Layer
// MediaTypeOCI1LayerGzip is the gzip compressed layer for OCI v1. // MediaTypeOCI1LayerGzip is the gzip compressed layer for OCI v1.
MediaTypeOCI1LayerGzip = "application/vnd.oci.image.layer.v1.tar+gzip" //
// Deprecated: replace with [mediatype.OCI1LayerGzip].
MediaTypeOCI1LayerGzip = mediatype.OCI1LayerGzip
// MediaTypeOCI1LayerZstd is the zstd compressed layer for OCI v1. // MediaTypeOCI1LayerZstd is the zstd compressed layer for OCI v1.
MediaTypeOCI1LayerZstd = "application/vnd.oci.image.layer.v1.tar+zstd" //
// Deprecated: replace with [mediatype.OCI1LayerZstd].
MediaTypeOCI1LayerZstd = mediatype.OCI1LayerZstd
// MediaTypeOCI1ForeignLayer is the foreign layer for OCI v1. // MediaTypeOCI1ForeignLayer is the foreign layer for OCI v1.
MediaTypeOCI1ForeignLayer = "application/vnd.oci.image.layer.nondistributable.v1.tar" //
// Deprecated: replace with [mediatype.OCI1ForeignLayer].
MediaTypeOCI1ForeignLayer = mediatype.OCI1ForeignLayer
// MediaTypeOCI1ForeignLayerGzip is the gzip compressed foreign layer for OCI v1. // MediaTypeOCI1ForeignLayerGzip is the gzip compressed foreign layer for OCI v1.
MediaTypeOCI1ForeignLayerGzip = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip" //
// Deprecated: replace with [mediatype.OCI1ForeignLayerGzip].
MediaTypeOCI1ForeignLayerGzip = mediatype.OCI1ForeignLayerGzip
// MediaTypeOCI1ForeignLayerZstd is the zstd compressed foreign layer for OCI v1. // MediaTypeOCI1ForeignLayerZstd is the zstd compressed foreign layer for OCI v1.
MediaTypeOCI1ForeignLayerZstd = "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd" //
// Deprecated: replace with [mediatype.OCI1ForeignLayerZstd].
MediaTypeOCI1ForeignLayerZstd = mediatype.OCI1ForeignLayerZstd
// MediaTypeOCI1Empty is used for blobs containing the empty JSON data `{}`. // MediaTypeOCI1Empty is used for blobs containing the empty JSON data `{}`.
MediaTypeOCI1Empty = "application/vnd.oci.empty.v1+json" //
// Deprecated: replace with [mediatype.OCI1Empty].
MediaTypeOCI1Empty = mediatype.OCI1Empty
// MediaTypeBuildkitCacheConfig is used by buildkit cache images. // MediaTypeBuildkitCacheConfig is used by buildkit cache images.
MediaTypeBuildkitCacheConfig = "application/vnd.buildkit.cacheconfig.v0" //
// Deprecated: replace with [mediatype.BuildkitCacheConfig].
MediaTypeBuildkitCacheConfig = mediatype.BuildkitCacheConfig
) )
// MediaTypeBase cleans the Content-Type header to return only the lower case base media type. var (
func MediaTypeBase(orig string) string { // Base cleans the Content-Type header to return only the lower case base media type.
base, _, _ := strings.Cut(orig, ";") //
return strings.TrimSpace(strings.ToLower(base)) // Deprecated: replace with [mediatype.Base].
} MediaTypeBase = mediatype.Base
)

View File

@ -0,0 +1,51 @@
// Package mediatype defines well known media types.
package mediatype
import "strings"
const (
// Docker1Manifest deprecated media type for docker schema1 manifests.
Docker1Manifest = "application/vnd.docker.distribution.manifest.v1+json"
// Docker1ManifestSigned is a deprecated schema1 manifest with jws signing.
Docker1ManifestSigned = "application/vnd.docker.distribution.manifest.v1+prettyjws"
// Docker2Manifest is the media type when pulling manifests from a v2 registry.
Docker2Manifest = "application/vnd.docker.distribution.manifest.v2+json"
// Docker2ManifestList is the media type when pulling a manifest list from a v2 registry.
Docker2ManifestList = "application/vnd.docker.distribution.manifest.list.v2+json"
// Docker2ImageConfig is for the configuration json object media type.
Docker2ImageConfig = "application/vnd.docker.container.image.v1+json"
// OCI1Artifact EXPERIMENTAL OCI v1 artifact media type.
OCI1Artifact = "application/vnd.oci.artifact.manifest.v1+json"
// OCI1Manifest OCI v1 manifest media type.
OCI1Manifest = "application/vnd.oci.image.manifest.v1+json"
// OCI1ManifestList OCI v1 manifest list media type.
OCI1ManifestList = "application/vnd.oci.image.index.v1+json"
// OCI1ImageConfig OCI v1 configuration json object media type.
OCI1ImageConfig = "application/vnd.oci.image.config.v1+json"
// Docker2LayerGzip is the default compressed layer for docker schema2.
Docker2LayerGzip = "application/vnd.docker.image.rootfs.diff.tar.gzip"
// Docker2ForeignLayer is the default compressed layer for foreign layers in docker schema2.
Docker2ForeignLayer = "application/vnd.docker.image.rootfs.foreign.diff.tar.gzip"
// OCI1Layer is the uncompressed layer for OCIv1.
OCI1Layer = "application/vnd.oci.image.layer.v1.tar"
// OCI1LayerGzip is the gzip compressed layer for OCI v1.
OCI1LayerGzip = "application/vnd.oci.image.layer.v1.tar+gzip"
// OCI1LayerZstd is the zstd compressed layer for OCI v1.
OCI1LayerZstd = "application/vnd.oci.image.layer.v1.tar+zstd"
// OCI1ForeignLayer is the foreign layer for OCI v1.
OCI1ForeignLayer = "application/vnd.oci.image.layer.nondistributable.v1.tar"
// OCI1ForeignLayerGzip is the gzip compressed foreign layer for OCI v1.
OCI1ForeignLayerGzip = "application/vnd.oci.image.layer.nondistributable.v1.tar+gzip"
// OCI1ForeignLayerZstd is the zstd compressed foreign layer for OCI v1.
OCI1ForeignLayerZstd = "application/vnd.oci.image.layer.nondistributable.v1.tar+zstd"
// OCI1Empty is used for blobs containing the empty JSON data `{}`.
OCI1Empty = "application/vnd.oci.empty.v1+json"
// BuildkitCacheConfig is used by buildkit cache images.
BuildkitCacheConfig = "application/vnd.buildkit.cacheconfig.v0"
)
// Base cleans the Content-Type header to return only the lower case base media type.
func Base(orig string) string {
base, _, _ := strings.Cut(orig, ";")
return strings.TrimSpace(strings.ToLower(base))
}

View File

@ -1,4 +1,4 @@
package types package mediatype
import "testing" import "testing"
@ -11,19 +11,19 @@ func TestMediaTypeBase(t *testing.T) {
}{ }{
{ {
name: "OCI Index", name: "OCI Index",
orig: MediaTypeOCI1ManifestList, orig: OCI1ManifestList,
expect: MediaTypeOCI1ManifestList, expect: OCI1ManifestList,
}, },
{ {
name: "OCI Index with charset", name: "OCI Index with charset",
orig: "application/vnd.oci.image.index.v1+json; charset=utf-8", orig: "application/vnd.oci.image.index.v1+json; charset=utf-8",
expect: MediaTypeOCI1ManifestList, expect: OCI1ManifestList,
}, },
} }
for _, tc := range tt { for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
result := MediaTypeBase(tc.orig) result := Base(tc.orig)
if tc.expect != result { if tc.expect != result {
t.Errorf("invalid result: expected \"%s\", received \"%s\"", tc.expect, result) t.Errorf("invalid result: expected \"%s\", received \"%s\"", tc.expect, result)
} }

View File

@ -1,8 +1,6 @@
package v1 package v1
import ( import "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types"
)
// ArtifactManifest EXPERIMENTAL defines an OCI Artifact // ArtifactManifest EXPERIMENTAL defines an OCI Artifact
type ArtifactManifest struct { type ArtifactManifest struct {
@ -13,10 +11,10 @@ type ArtifactManifest struct {
ArtifactType string `json:"artifactType,omitempty"` ArtifactType string `json:"artifactType,omitempty"`
// Blobs is a collection of blobs referenced by this manifest. // Blobs is a collection of blobs referenced by this manifest.
Blobs []types.Descriptor `json:"blobs,omitempty"` Blobs []descriptor.Descriptor `json:"blobs,omitempty"`
// Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest. // Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.
Subject *types.Descriptor `json:"subject,omitempty"` Subject *descriptor.Descriptor `json:"subject,omitempty"`
// Annotations contains arbitrary metadata for the artifact manifest. // Annotations contains arbitrary metadata for the artifact manifest.
Annotations map[string]string `json:"annotations,omitempty"` Annotations map[string]string `json:"annotations,omitempty"`

View File

@ -1,7 +1,7 @@
package v1 package v1
import ( import (
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/oci" "github.com/regclient/regclient/types/oci"
) )
@ -22,10 +22,10 @@ type Index struct {
ArtifactType string `json:"artifactType,omitempty"` ArtifactType string `json:"artifactType,omitempty"`
// Manifests references platform specific manifests. // Manifests references platform specific manifests.
Manifests []types.Descriptor `json:"manifests"` Manifests []descriptor.Descriptor `json:"manifests"`
// Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest. // Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.
Subject *types.Descriptor `json:"subject,omitempty"` Subject *descriptor.Descriptor `json:"subject,omitempty"`
// Annotations contains arbitrary metadata for the image index. // Annotations contains arbitrary metadata for the image index.
Annotations map[string]string `json:"annotations,omitempty"` Annotations map[string]string `json:"annotations,omitempty"`

View File

@ -1,7 +1,7 @@
package v1 package v1
import ( import (
"github.com/regclient/regclient/types" "github.com/regclient/regclient/types/descriptor"
"github.com/regclient/regclient/types/oci" "github.com/regclient/regclient/types/oci"
) )
@ -22,13 +22,13 @@ type Manifest struct {
// Config references a configuration object for a container, by digest. // Config references a configuration object for a container, by digest.
// The referenced configuration object is a JSON blob that the runtime uses to set up the container. // The referenced configuration object is a JSON blob that the runtime uses to set up the container.
Config types.Descriptor `json:"config"` Config descriptor.Descriptor `json:"config"`
// Layers is an indexed list of layers referenced by the manifest. // Layers is an indexed list of layers referenced by the manifest.
Layers []types.Descriptor `json:"layers"` Layers []descriptor.Descriptor `json:"layers"`
// Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest. // Subject is an optional link from the image manifest to another manifest forming an association between the image manifest and the other manifest.
Subject *types.Descriptor `json:"subject,omitempty"` Subject *descriptor.Descriptor `json:"subject,omitempty"`
// Annotations contains arbitrary metadata for the image manifest. // Annotations contains arbitrary metadata for the image manifest.
Annotations map[string]string `json:"annotations,omitempty"` Annotations map[string]string `json:"annotations,omitempty"`

Some files were not shown because too many files have changed in this diff Show More