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:
parent
b991f53ad7
commit
eea06e2a5c
36
blob.go
36
blob.go
@ -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)
|
||||||
}
|
}
|
||||||
|
35
blob_test.go
35
blob_test.go
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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",
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
||||||
|
@ -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
119
image.go
@ -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()))
|
||||||
}
|
}
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
6
internal/cache/cache.go
vendored
6
internal/cache/cache.go
vendored
@ -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() {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
15
manifest.go
15
manifest.go
@ -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 {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -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 != "" {
|
||||||
|
17
mod/dag.go
17
mod/dag.go
@ -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)
|
||||||
|
@ -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
|
||||||
|
19
mod/mod.go
19
mod/mod.go
@ -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()
|
||||||
|
@ -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")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
)
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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{}
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
6
repo.go
6
repo.go
@ -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...)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
)
|
)
|
||||||
|
@ -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"
|
||||||
|
@ -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 := ®http.Req{
|
req := ®http.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 := ®http.Req{
|
req := ®http.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 := ®http.Req{
|
req := ®http.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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 := ®http.Req{
|
req := ®http.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 := ®http.Req{
|
req := ®http.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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -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
6
tag.go
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
|
279
types/descriptor/descriptor.go
Normal file
279
types/descriptor/descriptor.go
Normal 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
|
||||||
|
}
|
@ -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",
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
154
types/error.go
154
types/error.go
@ -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
87
types/errs/error.go
Normal 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)
|
||||||
|
)
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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)),
|
||||||
}),
|
}),
|
||||||
|
@ -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)),
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
)
|
||||||
|
51
types/mediatype/mediatype.go
Normal file
51
types/mediatype/mediatype.go
Normal 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))
|
||||||
|
}
|
@ -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)
|
||||||
}
|
}
|
@ -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"`
|
||||||
|
@ -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"`
|
||||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user