mirror of
https://github.com/regclient/regclient.git
synced 2025-04-17 11:37:11 +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/types"
|
||||
"github.com/regclient/regclient/types/blob"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"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.
|
||||
// If the blob already exists in the target, the copy is skipped.
|
||||
// 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() {
|
||||
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() {
|
||||
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
|
||||
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.
|
||||
// This method should only be used to repair a damaged registry.
|
||||
// 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() {
|
||||
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)
|
||||
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.
|
||||
// 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()
|
||||
if err == nil {
|
||||
return blob.NewReader(blob.WithDesc(d), blob.WithRef(r), blob.WithReader(bytes.NewReader(data))), nil
|
||||
}
|
||||
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)
|
||||
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.
|
||||
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() {
|
||||
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)
|
||||
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.
|
||||
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() {
|
||||
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)
|
||||
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.
|
||||
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() {
|
||||
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() {
|
||||
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)
|
||||
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.
|
||||
// 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).
|
||||
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() {
|
||||
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)
|
||||
if err != nil {
|
||||
return types.Descriptor{}, err
|
||||
return descriptor.Descriptor{}, err
|
||||
}
|
||||
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/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"
|
||||
)
|
||||
|
||||
@ -184,7 +185,7 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobGet: %v", err)
|
||||
}
|
||||
@ -204,7 +205,7 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
desc := types.Descriptor{
|
||||
desc := descriptor.Descriptor{
|
||||
Digest: d1,
|
||||
Size: int64(len(blob1)),
|
||||
Data: blob1,
|
||||
@ -228,7 +229,7 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobHead: %v", err)
|
||||
}
|
||||
@ -243,12 +244,12 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
defer br.Close()
|
||||
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)
|
||||
}
|
||||
})
|
||||
@ -258,7 +259,7 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobGet: %v", err)
|
||||
}
|
||||
@ -277,12 +278,12 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
br.Close()
|
||||
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)
|
||||
}
|
||||
})
|
||||
@ -672,7 +673,7 @@ func TestBlobPut(t *testing.T) {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobPut: %v", err)
|
||||
}
|
||||
@ -691,7 +692,7 @@ func TestBlobPut(t *testing.T) {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobPut: %v", err)
|
||||
}
|
||||
@ -710,7 +711,7 @@ func TestBlobPut(t *testing.T) {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobPut: %v", err)
|
||||
}
|
||||
@ -1163,7 +1164,7 @@ func TestBlobCopy(t *testing.T) {
|
||||
|
||||
// same repo
|
||||
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 {
|
||||
t.Fatalf("Failed to copy d1 from repo a to a: %v", err)
|
||||
}
|
||||
@ -1171,7 +1172,7 @@ func TestBlobCopy(t *testing.T) {
|
||||
|
||||
// copy blob
|
||||
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 {
|
||||
t.Fatalf("Failed to copy d1 from repo a to b: %v", err)
|
||||
}
|
||||
@ -1179,7 +1180,7 @@ func TestBlobCopy(t *testing.T) {
|
||||
|
||||
// blob exists
|
||||
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 {
|
||||
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
|
||||
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 {
|
||||
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
|
||||
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 {
|
||||
t.Fatalf("Failed to copy d3 from repo a to b: %v", err)
|
||||
}
|
||||
|
@ -14,8 +14,8 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
lua "github.com/yuin/gopher-lua"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/blob"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
@ -113,7 +113,7 @@ func (s *Sandbox) blobGet(ls *lua.LState) int {
|
||||
"ref": r.r.CommonName(),
|
||||
"digest": d,
|
||||
}).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 {
|
||||
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(),
|
||||
"digest": d,
|
||||
}).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 {
|
||||
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")
|
||||
}
|
||||
|
||||
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 {
|
||||
ls.RaiseError("Failed to put blob: %v", err)
|
||||
}
|
||||
|
@ -22,7 +22,10 @@ import (
|
||||
"github.com/regclient/regclient/pkg/template"
|
||||
"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/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -36,7 +39,7 @@ const (
|
||||
)
|
||||
|
||||
var manifestKnownTypes = []string{
|
||||
types.MediaTypeOCI1Manifest,
|
||||
mediatype.OCI1Manifest,
|
||||
}
|
||||
var artifactFileKnownTypes = []string{
|
||||
"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().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) {
|
||||
return manifestKnownTypes, cobra.ShellCompDirectiveNoFileComp
|
||||
})
|
||||
@ -263,7 +266,7 @@ func (artifactOpts *artifactCmd) runArtifactGet(cmd *cobra.Command, args []strin
|
||||
}
|
||||
|
||||
r := ref.Ref{}
|
||||
matchOpts := types.MatchOpt{
|
||||
matchOpts := descriptor.MatchOpt{
|
||||
ArtifactType: artifactOpts.filterAT,
|
||||
SortAnnotation: artifactOpts.sortAnnot,
|
||||
SortDesc: artifactOpts.sortDesc,
|
||||
@ -335,13 +338,13 @@ func (artifactOpts *artifactCmd) runArtifactGet(cmd *cobra.Command, args []strin
|
||||
if m.IsList() {
|
||||
mi, ok := m.(manifest.Indexer)
|
||||
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()
|
||||
if err != nil {
|
||||
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 {
|
||||
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)
|
||||
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
|
||||
@ -527,7 +530,7 @@ func (artifactOpts *artifactCmd) runArtifactList(cmd *cobra.Command, args []stri
|
||||
rc := artifactOpts.rootOpts.newRegClient()
|
||||
defer rc.Close(ctx, rSubject)
|
||||
|
||||
matchOpts := types.MatchOpt{
|
||||
matchOpts := descriptor.MatchOpt{
|
||||
ArtifactType: artifactOpts.filterAT,
|
||||
SortAnnotation: artifactOpts.sortAnnot,
|
||||
SortDesc: artifactOpts.sortDesc,
|
||||
@ -613,10 +616,10 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
var err error
|
||||
|
||||
switch artifactOpts.artifactMT {
|
||||
case types.MediaTypeOCI1Artifact:
|
||||
case mediatype.OCI1Artifact:
|
||||
log.Warnf("changing media-type is experimental and non-portable")
|
||||
hasConfig = false
|
||||
case "", types.MediaTypeOCI1Manifest:
|
||||
case "", mediatype.OCI1Manifest:
|
||||
hasConfig = true
|
||||
default:
|
||||
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
|
||||
if hasConfig && artifactOpts.artifactConfigMT == "" {
|
||||
if artifactOpts.artifactConfig == "" {
|
||||
artifactOpts.artifactConfigMT = types.MediaTypeOCI1Empty
|
||||
artifactOpts.artifactConfigMT = mediatype.OCI1Empty
|
||||
} else {
|
||||
if 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 != "") {
|
||||
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 !hasConfig || artifactOpts.artifactConfigMT == types.MediaTypeOCI1Empty {
|
||||
if !hasConfig || artifactOpts.artifactConfigMT == mediatype.OCI1Empty {
|
||||
log.Warnf("using default value for artifact-type is not recommended")
|
||||
artifactOpts.artifactType = defaultMTArtifact
|
||||
}
|
||||
@ -704,7 +707,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
rc := artifactOpts.rootOpts.newRegClient()
|
||||
defer rc.Close(ctx, r)
|
||||
|
||||
var subjectDesc *types.Descriptor
|
||||
var subjectDesc *descriptor.Descriptor
|
||||
if rSubject.IsSet() {
|
||||
smh, err := rc.ManifestHead(ctx, rSubject, regclient.WithManifestRequireDigest())
|
||||
if err != nil {
|
||||
@ -723,21 +726,21 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
if err != nil {
|
||||
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 {
|
||||
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
|
||||
confDesc := types.Descriptor{}
|
||||
confDesc := descriptor.Descriptor{}
|
||||
if hasConfig {
|
||||
var configBytes []byte
|
||||
var configDigest digest.Digest
|
||||
if artifactOpts.artifactConfig == "" {
|
||||
configBytes = types.EmptyData
|
||||
configDigest = types.EmptyDigest
|
||||
configBytes = descriptor.EmptyData
|
||||
configDigest = descriptor.EmptyDigest
|
||||
} else {
|
||||
var err error
|
||||
configBytes, err = os.ReadFile(artifactOpts.artifactConfig)
|
||||
@ -747,19 +750,19 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
configDigest = digest.FromBytes(configBytes)
|
||||
}
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
// save config descriptor to manifest
|
||||
confDesc = types.Descriptor{
|
||||
confDesc = descriptor.Descriptor{
|
||||
MediaType: artifactOpts.artifactConfigMT,
|
||||
Digest: configDigest,
|
||||
Size: int64(len(configBytes)),
|
||||
}
|
||||
}
|
||||
|
||||
blobs := []types.Descriptor{}
|
||||
blobs := []descriptor.Descriptor{}
|
||||
if len(artifactOpts.artifactFile) > 0 {
|
||||
// if files were passed
|
||||
for i, f := range artifactOpts.artifactFile {
|
||||
@ -804,7 +807,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
}
|
||||
d := digester.Digest()
|
||||
// add layer to manifest
|
||||
desc := types.Descriptor{
|
||||
desc := descriptor.Descriptor{
|
||||
MediaType: mt,
|
||||
Digest: d,
|
||||
Size: l,
|
||||
@ -825,7 +828,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
}
|
||||
blobs = append(blobs, desc)
|
||||
// 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 {
|
||||
_ = bRdr.Close()
|
||||
return nil
|
||||
@ -835,7 +838,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
if err != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -851,7 +854,7 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
if len(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 {
|
||||
return err
|
||||
}
|
||||
@ -860,19 +863,19 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
}
|
||||
|
||||
switch artifactOpts.artifactMT {
|
||||
case types.MediaTypeOCI1Artifact:
|
||||
case mediatype.OCI1Artifact:
|
||||
m := v1.ArtifactManifest{
|
||||
MediaType: types.MediaTypeOCI1Artifact,
|
||||
MediaType: mediatype.OCI1Artifact,
|
||||
ArtifactType: artifactOpts.artifactType,
|
||||
Blobs: blobs,
|
||||
Annotations: annotations,
|
||||
Subject: subjectDesc,
|
||||
}
|
||||
mOpts = append(mOpts, manifest.WithOrig(m))
|
||||
case "", types.MediaTypeOCI1Manifest:
|
||||
case "", mediatype.OCI1Manifest:
|
||||
m := v1.Manifest{
|
||||
Versioned: v1.ManifestSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
ArtifactType: artifactOpts.artifactType,
|
||||
Config: confDesc,
|
||||
Layers: blobs,
|
||||
@ -942,8 +945,8 @@ func (artifactOpts *artifactCmd) runArtifactPut(cmd *cobra.Command, args []strin
|
||||
// create a new index
|
||||
mii := v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
Manifests: []types.Descriptor{d},
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Manifests: []descriptor.Descriptor{d},
|
||||
}
|
||||
mi, err := manifest.New(manifest.WithOrig(mii))
|
||||
if err != nil {
|
||||
@ -981,7 +984,7 @@ func (artifactOpts *artifactCmd) runArtifactTree(cmd *cobra.Command, args []stri
|
||||
|
||||
referrerOpts := []scheme.ReferrerOpts{}
|
||||
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 {
|
||||
af := map[string]string{}
|
||||
@ -993,7 +996,7 @@ func (artifactOpts *artifactCmd) runArtifactTree(cmd *cobra.Command, args []stri
|
||||
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
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
func TestArtifactGet(t *testing.T) {
|
||||
@ -28,12 +28,12 @@ func TestArtifactGet(t *testing.T) {
|
||||
{
|
||||
name: "Invalid ref",
|
||||
args: []string{"artifact", "get", "invalid*ref"},
|
||||
expectErr: types.ErrInvalidReference,
|
||||
expectErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "Missing manifest",
|
||||
args: []string{"artifact", "get", "ocidir://../../testdata/testrepo:missing"},
|
||||
expectErr: types.ErrNotFound,
|
||||
expectErr: errs.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "By Manifest",
|
||||
@ -88,12 +88,12 @@ func TestArtifactList(t *testing.T) {
|
||||
{
|
||||
name: "Invalid ref",
|
||||
args: []string{"artifact", "list", "invalid*ref"},
|
||||
expectErr: types.ErrInvalidReference,
|
||||
expectErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "Missing manifest",
|
||||
args: []string{"artifact", "list", "ocidir://../../testdata/testrepo:missing"},
|
||||
expectErr: types.ErrNotFound,
|
||||
expectErr: errs.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "No referrers",
|
||||
@ -176,7 +176,7 @@ func TestArtifactPut(t *testing.T) {
|
||||
{
|
||||
name: "Invalid ref",
|
||||
args: []string{"artifact", "put", "invalid*ref"},
|
||||
expectErr: types.ErrInvalidReference,
|
||||
expectErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "Put artifact",
|
||||
@ -265,12 +265,12 @@ func TestArtifactTree(t *testing.T) {
|
||||
{
|
||||
name: "Invalid ref",
|
||||
args: []string{"artifact", "tree", "invalid*ref"},
|
||||
expectErr: types.ErrInvalidReference,
|
||||
expectErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "Missing manifest",
|
||||
args: []string{"artifact", "tree", "ocidir://../../testdata/testrepo:missing"},
|
||||
expectErr: types.ErrNotFound,
|
||||
expectErr: errs.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "No referrers",
|
||||
|
@ -20,7 +20,7 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/internal/diff"
|
||||
"github.com/regclient/regclient/pkg/template"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
@ -224,7 +224,7 @@ func (blobOpts *blobCmd) runBlobDelete(cmd *cobra.Command, args []string) error
|
||||
"repository": r.Repository,
|
||||
"digest": args[1],
|
||||
}).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 {
|
||||
@ -251,7 +251,7 @@ func (blobOpts *blobCmd) runBlobDiffConfig(cmd *cobra.Command, args []string) er
|
||||
if err != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -264,7 +264,7 @@ func (blobOpts *blobCmd) runBlobDiffConfig(cmd *cobra.Command, args []string) er
|
||||
if err != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -305,7 +305,7 @@ func (blobOpts *blobCmd) runBlobDiffLayer(cmd *cobra.Command, args []string) err
|
||||
if err != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -331,7 +331,7 @@ func (blobOpts *blobCmd) runBlobDiffLayer(cmd *cobra.Command, args []string) err
|
||||
if err != nil {
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -382,7 +382,7 @@ func (blobOpts *blobCmd) runBlobGet(cmd *cobra.Command, args []string) error {
|
||||
"repository": r.Repository,
|
||||
"digest": args[1],
|
||||
}).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 {
|
||||
return err
|
||||
}
|
||||
@ -424,7 +424,7 @@ func (blobOpts *blobCmd) runBlobGetFile(cmd *cobra.Command, args []string) error
|
||||
"digest": args[1],
|
||||
"filename": filename,
|
||||
}).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 {
|
||||
return err
|
||||
}
|
||||
@ -486,7 +486,7 @@ func (blobOpts *blobCmd) runBlobHead(cmd *cobra.Command, args []string) error {
|
||||
"repository": r.Repository,
|
||||
"digest": args[1],
|
||||
}).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 {
|
||||
return err
|
||||
}
|
||||
@ -518,7 +518,7 @@ func (blobOpts *blobCmd) runBlobPut(cmd *cobra.Command, args []string) error {
|
||||
"repository": r.Repository,
|
||||
"digest": blobOpts.digest,
|
||||
}).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 {
|
||||
return err
|
||||
}
|
||||
@ -556,7 +556,7 @@ func (blobOpts *blobCmd) runBlobCopy(cmd *cobra.Command, args []string) error {
|
||||
"target": rTgt.CommonName(),
|
||||
"digest": args[2],
|
||||
}).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 {
|
||||
return err
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
"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) {
|
||||
return []string{
|
||||
types.MediaTypeDocker2Manifest,
|
||||
types.MediaTypeDocker2ManifestList,
|
||||
types.MediaTypeOCI1Manifest,
|
||||
types.MediaTypeOCI1ManifestList,
|
||||
types.MediaTypeDocker1Manifest,
|
||||
types.MediaTypeDocker1ManifestSigned,
|
||||
mediatype.Docker2Manifest,
|
||||
mediatype.Docker2ManifestList,
|
||||
mediatype.OCI1Manifest,
|
||||
mediatype.OCI1ManifestList,
|
||||
mediatype.Docker1Manifest,
|
||||
mediatype.Docker1ManifestSigned,
|
||||
}, cobra.ShellCompDirectiveNoFileComp
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/regclient/regclient/pkg/template"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/blob"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
@ -842,7 +843,7 @@ func (imageOpts *imageCmd) runImageCheckBase(cmd *cobra.Command, args []string)
|
||||
if err == nil {
|
||||
log.Info("base image matches")
|
||||
return nil
|
||||
} else if errors.Is(err, types.ErrMismatch) {
|
||||
} else if errors.Is(err, errs.ErrMismatch) {
|
||||
log.WithFields(logrus.Fields{
|
||||
"err": err,
|
||||
}).Info("base image mismatch")
|
||||
@ -1200,7 +1201,7 @@ func (imageOpts *imageCmd) runImageGetFile(cmd *cobra.Command, args []string) er
|
||||
}
|
||||
th, rdr, err := btr.ReadFile(filename)
|
||||
if err != nil {
|
||||
if errors.Is(err, types.ErrFileNotFound) {
|
||||
if errors.Is(err, errs.ErrFileNotFound) {
|
||||
if err := btr.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -1244,7 +1245,7 @@ func (imageOpts *imageCmd) runImageGetFile(cmd *cobra.Command, args []string) er
|
||||
return nil
|
||||
}
|
||||
// all layers exhausted, not found or deleted
|
||||
return types.ErrNotFound
|
||||
return errs.ErrNotFound
|
||||
}
|
||||
|
||||
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)
|
||||
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()
|
||||
if err != nil {
|
||||
|
@ -10,17 +10,19 @@ import (
|
||||
|
||||
"github.com/regclient/regclient"
|
||||
"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/errs"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
var indexKnownTypes = []string{
|
||||
types.MediaTypeOCI1ManifestList,
|
||||
types.MediaTypeDocker2ManifestList,
|
||||
mediatype.OCI1ManifestList,
|
||||
mediatype.Docker2ManifestList,
|
||||
}
|
||||
|
||||
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().BoolVar(&indexOpts.incDigestTags, "digest-tags", false, "Include digest tags")
|
||||
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().StringArrayVar(&indexOpts.refs, "ref", []string{}, "References to include in new index")
|
||||
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)
|
||||
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()
|
||||
if err != nil {
|
||||
@ -199,8 +201,8 @@ func (indexOpts *indexCmd) runIndexCreate(cmd *cobra.Command, args []string) err
|
||||
ctx := cmd.Context()
|
||||
|
||||
// validate media type
|
||||
if indexOpts.mediaType != types.MediaTypeOCI1ManifestList && indexOpts.mediaType != types.MediaTypeDocker2ManifestList {
|
||||
return fmt.Errorf("unsupported manifest media type: %s%.0w", indexOpts.mediaType, types.ErrUnsupportedMediaType)
|
||||
if indexOpts.mediaType != mediatype.OCI1ManifestList && indexOpts.mediaType != mediatype.Docker2ManifestList {
|
||||
return fmt.Errorf("unsupported manifest media type: %s%.0w", indexOpts.mediaType, errs.ErrUnsupportedMediaType)
|
||||
}
|
||||
|
||||
// parse ref
|
||||
@ -231,8 +233,8 @@ func (indexOpts *indexCmd) runIndexCreate(cmd *cobra.Command, args []string) err
|
||||
}
|
||||
descList = indexDescListRmDup(descList)
|
||||
|
||||
var subj *types.Descriptor
|
||||
if indexOpts.subject != "" && indexOpts.mediaType == types.MediaTypeOCI1ManifestList {
|
||||
var subj *descriptor.Descriptor
|
||||
if indexOpts.subject != "" && indexOpts.mediaType == mediatype.OCI1ManifestList {
|
||||
var rSubj ref.Ref
|
||||
dig, err := digest.Parse(indexOpts.subject)
|
||||
if err == nil {
|
||||
@ -252,10 +254,10 @@ func (indexOpts *indexCmd) runIndexCreate(cmd *cobra.Command, args []string) err
|
||||
// build the index
|
||||
mOpts := []manifest.Opts{}
|
||||
switch indexOpts.mediaType {
|
||||
case types.MediaTypeOCI1ManifestList:
|
||||
case mediatype.OCI1ManifestList:
|
||||
m := v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
ArtifactType: indexOpts.artifactType,
|
||||
Manifests: descList,
|
||||
Subject: subj,
|
||||
@ -264,7 +266,7 @@ func (indexOpts *indexCmd) runIndexCreate(cmd *cobra.Command, args []string) err
|
||||
m.Annotations = annotations
|
||||
}
|
||||
mOpts = append(mOpts, manifest.WithOrig(m))
|
||||
case types.MediaTypeDocker2ManifestList:
|
||||
case mediatype.Docker2ManifestList:
|
||||
m := schema2.ManifestList{
|
||||
Versioned: schema2.ManifestListSchemaVersion,
|
||||
Manifests: descList,
|
||||
@ -321,7 +323,7 @@ func (indexOpts *indexCmd) runIndexDelete(cmd *cobra.Command, args []string) err
|
||||
}
|
||||
mi, ok := m.(manifest.Indexer)
|
||||
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()
|
||||
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)
|
||||
}
|
||||
|
||||
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{
|
||||
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
|
||||
descList := []types.Descriptor{}
|
||||
descList := []descriptor.Descriptor{}
|
||||
for _, dig := range indexOpts.digests {
|
||||
rDig := r.SetDigest(dig)
|
||||
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
|
||||
}
|
||||
|
||||
func indexDescListRmDup(dl []types.Descriptor) []types.Descriptor {
|
||||
func indexDescListRmDup(dl []descriptor.Descriptor) []descriptor.Descriptor {
|
||||
i := 0
|
||||
for i < len(dl)-1 {
|
||||
j := len(dl) - 1
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
"github.com/regclient/regclient"
|
||||
"github.com/regclient/regclient/internal/diff"
|
||||
"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/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -374,7 +374,7 @@ func (manifestOpts *manifestCmd) runManifestPut(cmd *cobra.Command, args []strin
|
||||
manifest.WithRaw(raw),
|
||||
}
|
||||
if manifestOpts.contentType != "" {
|
||||
opts = append(opts, manifest.WithDesc(types.Descriptor{
|
||||
opts = append(opts, manifest.WithDesc(descriptor.Descriptor{
|
||||
MediaType: manifestOpts.contentType,
|
||||
}))
|
||||
}
|
||||
@ -432,8 +432,8 @@ func getManifest(ctx context.Context, rc *regclient.RegClient, r ref.Ref, pStr s
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func getPlatformDesc(ctx context.Context, rc *regclient.RegClient, m manifest.Manifest, pStr string) (*types.Descriptor, error) {
|
||||
var desc *types.Descriptor
|
||||
func getPlatformDesc(ctx context.Context, rc *regclient.RegClient, m manifest.Manifest, pStr string) (*descriptor.Descriptor, error) {
|
||||
var desc *descriptor.Descriptor
|
||||
var err error
|
||||
if !m.IsList() {
|
||||
return desc, fmt.Errorf("%w: manifest is not a list", ErrInvalidInput)
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
func TestManifestHead(t *testing.T) {
|
||||
@ -25,12 +25,12 @@ func TestManifestHead(t *testing.T) {
|
||||
{
|
||||
name: "Invalid ref",
|
||||
args: []string{"manifest", "head", "invalid*ref"},
|
||||
expectErr: types.ErrInvalidReference,
|
||||
expectErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "Missing manifest",
|
||||
args: []string{"manifest", "head", "ocidir://../../testdata/testrepo:missing"},
|
||||
expectErr: types.ErrNotFound,
|
||||
expectErr: errs.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "Digest",
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
func TestTagList(t *testing.T) {
|
||||
@ -26,7 +26,7 @@ func TestTagList(t *testing.T) {
|
||||
{
|
||||
name: "Invalid ref",
|
||||
args: []string{"tag", "ls", "invalid*ref"},
|
||||
expectErr: types.ErrInvalidReference,
|
||||
expectErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "Missing repo",
|
||||
|
@ -10,16 +10,16 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/config"
|
||||
"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
|
||||
var rateLimitRetryMin = time.Minute * 5
|
||||
var defaultMediaTypes = []string{
|
||||
types.MediaTypeDocker2Manifest,
|
||||
types.MediaTypeDocker2ManifestList,
|
||||
types.MediaTypeOCI1Manifest,
|
||||
types.MediaTypeOCI1ManifestList,
|
||||
mediatype.Docker2Manifest,
|
||||
mediatype.Docker2ManifestList,
|
||||
mediatype.OCI1Manifest,
|
||||
mediatype.OCI1ManifestList,
|
||||
}
|
||||
|
||||
// Config is parsed configuration file for regsync
|
||||
|
@ -12,7 +12,8 @@ import (
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"github.com/regclient/regclient/internal/throttle"
|
||||
"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/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -98,12 +99,12 @@ func TestProcess(t *testing.T) {
|
||||
t.Fatalf("failed to get platform ")
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("failed to get SBOM for v2: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("failed to get signature for v2: %v", err)
|
||||
}
|
||||
@ -580,7 +581,7 @@ func TestProcess(t *testing.T) {
|
||||
},
|
||||
action: actionCopy,
|
||||
desired: []string{},
|
||||
expErr: types.ErrInvalidReference,
|
||||
expErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "InvalidTargetImage",
|
||||
@ -591,7 +592,7 @@ func TestProcess(t *testing.T) {
|
||||
},
|
||||
action: actionCopy,
|
||||
desired: []string{},
|
||||
expErr: types.ErrInvalidReference,
|
||||
expErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "InvalidSourceRepository",
|
||||
@ -602,7 +603,7 @@ func TestProcess(t *testing.T) {
|
||||
},
|
||||
action: actionCopy,
|
||||
desired: []string{},
|
||||
expErr: types.ErrInvalidReference,
|
||||
expErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "InvalidTargetRepository",
|
||||
@ -613,7 +614,7 @@ func TestProcess(t *testing.T) {
|
||||
},
|
||||
action: actionCopy,
|
||||
desired: []string{},
|
||||
expErr: types.ErrInvalidReference,
|
||||
expErr: errs.ErrInvalidReference,
|
||||
},
|
||||
{
|
||||
name: "InvalidType",
|
||||
@ -701,7 +702,7 @@ func TestProcessRef(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
expErr: types.ErrNotFound,
|
||||
expErr: errs.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "check v1",
|
||||
|
@ -26,7 +26,8 @@ import (
|
||||
"github.com/regclient/regclient/pkg/template"
|
||||
"github.com/regclient/regclient/scheme"
|
||||
"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/platform"
|
||||
"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
|
||||
func (rootOpts *rootCmd) processRef(ctx context.Context, s ConfigSync, src, tgt ref.Ref, action actionType) error {
|
||||
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)
|
||||
}
|
||||
if err != nil {
|
||||
@ -831,10 +832,10 @@ func (rootOpts *rootCmd) processRef(ctx context.Context, s ConfigSync, src, tgt
|
||||
for _, filter := range s.ReferrerFilters {
|
||||
rOpts := []scheme.ReferrerOpts{}
|
||||
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 {
|
||||
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...))
|
||||
}
|
||||
|
119
image.go
119
image.go
@ -24,8 +24,11 @@ import (
|
||||
"github.com/regclient/regclient/pkg/archive"
|
||||
"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/errs"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -46,8 +49,8 @@ type dockerTarManifest struct {
|
||||
Config string
|
||||
RepoTags []string
|
||||
Layers []string
|
||||
Parent digest.Digest `json:",omitempty"`
|
||||
LayerSources map[digest.Digest]types.Descriptor `json:",omitempty"`
|
||||
Parent digest.Digest `json:",omitempty"`
|
||||
LayerSources map[digest.Digest]descriptor.Descriptor `json:",omitempty"`
|
||||
}
|
||||
|
||||
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.
|
||||
// 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 {
|
||||
var opt imageOpt
|
||||
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)
|
||||
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()
|
||||
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 {
|
||||
opt.checkBaseRef = baseName
|
||||
} 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 {
|
||||
opt.checkBaseDigest = baseDig
|
||||
@ -283,7 +286,7 @@ func (rc *RegClient) ImageCheckBase(ctx context.Context, r ref.Ref, opts ...Imag
|
||||
"expected": expectDig.String(),
|
||||
}).Debug("base image digest changed")
|
||||
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(),
|
||||
}).Debug("image layer changed")
|
||||
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],
|
||||
}).Debug("image history changed")
|
||||
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)
|
||||
}
|
||||
// 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 {
|
||||
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.
|
||||
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 sDig digest.Digest
|
||||
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())
|
||||
entryTgt := refTgt.SetDigest(dEntry.Digest.String())
|
||||
switch dEntry.MediaType {
|
||||
case types.MediaTypeDocker1Manifest, types.MediaTypeDocker1ManifestSigned,
|
||||
types.MediaTypeDocker2Manifest, types.MediaTypeDocker2ManifestList,
|
||||
types.MediaTypeOCI1Manifest, types.MediaTypeOCI1ManifestList:
|
||||
case mediatype.Docker1Manifest, mediatype.Docker1ManifestSigned,
|
||||
mediatype.Docker2Manifest, mediatype.Docker2ManifestList,
|
||||
mediatype.OCI1Manifest, mediatype.OCI1ManifestList:
|
||||
// known manifest media type
|
||||
err = rc.imageCopyOpt(ctx, entrySrc, entryTgt, dEntry, true, parentsNew, opt)
|
||||
case types.MediaTypeDocker2ImageConfig, types.MediaTypeOCI1ImageConfig,
|
||||
types.MediaTypeDocker2LayerGzip, types.MediaTypeOCI1Layer, types.MediaTypeOCI1LayerGzip,
|
||||
types.MediaTypeBuildkitCacheConfig:
|
||||
case mediatype.Docker2ImageConfig, mediatype.OCI1ImageConfig,
|
||||
mediatype.Docker2LayerGzip, mediatype.OCI1Layer, mediatype.OCI1LayerGzip,
|
||||
mediatype.BuildkitCacheConfig:
|
||||
// known blob media type
|
||||
err = rc.imageCopyBlob(ctx, entrySrc, entryTgt, dEntry, opt, bOpt...)
|
||||
default:
|
||||
@ -626,7 +629,7 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
|
||||
return err
|
||||
}
|
||||
referrerTags = append(referrerTags, rl.Tags...)
|
||||
descList := []types.Descriptor{}
|
||||
descList := []descriptor.Descriptor{}
|
||||
if len(opt.referrerConfs) == 0 {
|
||||
descList = rl.Descriptors
|
||||
} else {
|
||||
@ -648,7 +651,7 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
|
||||
waitCount++
|
||||
go func() {
|
||||
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
|
||||
opt.mu.Lock()
|
||||
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
|
||||
waitCount++
|
||||
go func() {
|
||||
err := rc.imageCopyOpt(ctx, refTagSrc, refTagTgt, types.Descriptor{}, false, parentsNew, opt)
|
||||
if errors.Is(err, types.ErrLoopDetected) {
|
||||
err := rc.imageCopyOpt(ctx, refTagSrc, refTagTgt, descriptor.Descriptor{}, false, parentsNew, opt)
|
||||
if errors.Is(err, errs.ErrLoopDetected) {
|
||||
// if a loop is detected, push the digest tag copy back to the end
|
||||
opt.mu.Lock()
|
||||
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()
|
||||
waitCh <- nil
|
||||
@ -781,7 +784,7 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
|
||||
cd, err := mSrcImg.GetConfig()
|
||||
if err != nil {
|
||||
// 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{
|
||||
"ref": refSrc.Reference,
|
||||
"err": err,
|
||||
@ -897,7 +900,7 @@ func (rc *RegClient) imageCopyOpt(ctx context.Context, refSrc ref.Ref, refTgt re
|
||||
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{})
|
||||
if seenCB == nil {
|
||||
return err
|
||||
@ -931,7 +934,7 @@ func imageSeenOrWait(ctx context.Context, opt *imageOpt, tag string, dig digest.
|
||||
// look for loops in parents
|
||||
for _, p := range parents {
|
||||
if key == tag+":"+p.String() {
|
||||
return nil, types.ErrLoopDetected
|
||||
return nil, errs.ErrLoopDetected
|
||||
}
|
||||
}
|
||||
// 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
|
||||
func (rc *RegClient) ImageExport(ctx context.Context, r ref.Ref, outStream io.Writer, opts ...ImageOpts) error {
|
||||
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
|
||||
|
||||
@ -1026,7 +1029,7 @@ func (rc *RegClient) ImageExport(ctx context.Context, r ref.Ref, outStream io.Wr
|
||||
|
||||
// generate/write an OCI index
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -1049,7 +1052,7 @@ func (rc *RegClient) ImageExport(ctx context.Context, r ref.Ref, outStream io.Wr
|
||||
RepoTags: []string{refTag.CommonName()},
|
||||
Config: tarOCILayoutDescPath(conf),
|
||||
Layers: []string{},
|
||||
LayerSources: map[digest.Digest]types.Descriptor{},
|
||||
LayerSources: map[digest.Digest]descriptor.Descriptor{},
|
||||
}
|
||||
dl, err := mi.GetLayers()
|
||||
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
|
||||
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)
|
||||
if twd.files[tarFilename] {
|
||||
// blob has already been imported into tar, skip
|
||||
return nil
|
||||
}
|
||||
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
|
||||
// retrieve manifest
|
||||
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)
|
||||
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
|
||||
mBody, err := m.RawBody()
|
||||
@ -1112,7 +1115,7 @@ func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc
|
||||
// add config
|
||||
confD, err := mi.GetConfig()
|
||||
// ignore unsupported media type errors
|
||||
if err != nil && !errors.Is(err, types.ErrUnsupportedMediaType) {
|
||||
if err != nil && !errors.Is(err, errs.ErrUnsupportedMediaType) {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
@ -1125,7 +1128,7 @@ func (rc *RegClient) imageExportDescriptor(ctx context.Context, r ref.Ref, desc
|
||||
// loop over layers
|
||||
layerDL, err := mi.GetLayers()
|
||||
// ignore unsupported media type errors
|
||||
if err != nil && !errors.Is(err, types.ErrUnsupportedMediaType) {
|
||||
if err != nil && !errors.Is(err, errs.ErrUnsupportedMediaType) {
|
||||
return err
|
||||
}
|
||||
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
|
||||
// retrieve manifest
|
||||
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)
|
||||
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
|
||||
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.
|
||||
func (rc *RegClient) ImageImport(ctx context.Context, r ref.Ref, rs io.ReadSeeker, opts ...ImageOpts) error {
|
||||
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
|
||||
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
|
||||
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
|
||||
// add handlers for the docker manifest layers
|
||||
rc.imageImportDockerAddLayerHandlers(ctx, r, trd)
|
||||
@ -1254,7 +1257,7 @@ func (rc *RegClient) ImageImport(ctx context.Context, r ref.Ref, rs io.ReadSeeke
|
||||
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
|
||||
_, err := rc.BlobHead(ctx, r, desc)
|
||||
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)
|
||||
trd.dockerManifest.SchemaVersion = 2
|
||||
trd.dockerManifest.MediaType = types.MediaTypeDocker2Manifest
|
||||
trd.dockerManifest.Layers = make([]types.Descriptor, len(trd.dockerManifestList[index].Layers))
|
||||
trd.dockerManifest.MediaType = mediatype.Docker2Manifest
|
||||
trd.dockerManifest.Layers = make([]descriptor.Descriptor, len(trd.dockerManifestList[index].Layers))
|
||||
|
||||
// add handler for config
|
||||
trd.handlers[filepath.Clean(trd.dockerManifestList[index].Config)] = func(header *tar.Header, trd *tarReadData) error {
|
||||
// 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 {
|
||||
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 {
|
||||
trd.dockerManifest.Config = od
|
||||
} else {
|
||||
d.MediaType = types.MediaTypeDocker2ImageConfig
|
||||
d.MediaType = mediatype.Docker2ImageConfig
|
||||
trd.dockerManifest.Config = d
|
||||
}
|
||||
return nil
|
||||
@ -1343,7 +1346,7 @@ func (rc *RegClient) imageImportDockerAddLayerHandlers(ctx context.Context, r re
|
||||
return err
|
||||
}
|
||||
// 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 {
|
||||
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 {
|
||||
trd.dockerManifest.Layers[i] = od
|
||||
} else {
|
||||
d.MediaType = types.MediaTypeDocker2LayerGzip
|
||||
d.MediaType = mediatype.Docker2LayerGzip
|
||||
trd.dockerManifest.Layers[i] = d
|
||||
}
|
||||
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
|
||||
trd.manifests[m.GetDescriptor().Digest] = m
|
||||
|
||||
handleManifest := func(d types.Descriptor, child bool) {
|
||||
handleManifest := func(d descriptor.Descriptor, child bool) {
|
||||
filename := tarOCILayoutDescPath(d)
|
||||
if !trd.processed[filename] && trd.handlers[filename] == nil {
|
||||
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
|
||||
}
|
||||
switch d.MediaType {
|
||||
case types.MediaTypeDocker1Manifest, types.MediaTypeDocker1ManifestSigned,
|
||||
types.MediaTypeDocker2Manifest, types.MediaTypeDocker2ManifestList,
|
||||
types.MediaTypeOCI1Manifest, types.MediaTypeOCI1ManifestList:
|
||||
case mediatype.Docker1Manifest, mediatype.Docker1ManifestSigned,
|
||||
mediatype.Docker2Manifest, mediatype.Docker2ManifestList,
|
||||
mediatype.OCI1Manifest, mediatype.OCI1ManifestList:
|
||||
// known manifest media types
|
||||
md, err := manifest.New(manifest.WithDesc(d), manifest.WithRaw(b))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return rc.imageImportOCIHandleManifest(ctx, r, md, trd, true, child)
|
||||
case types.MediaTypeDocker2ImageConfig, types.MediaTypeOCI1ImageConfig,
|
||||
types.MediaTypeDocker2LayerGzip, types.MediaTypeOCI1Layer, types.MediaTypeOCI1LayerGzip,
|
||||
types.MediaTypeBuildkitCacheConfig:
|
||||
case mediatype.Docker2ImageConfig, mediatype.OCI1ImageConfig,
|
||||
mediatype.Docker2LayerGzip, mediatype.OCI1Layer, mediatype.OCI1LayerGzip,
|
||||
mediatype.BuildkitCacheConfig:
|
||||
// known blob media types
|
||||
return rc.imageImportBlob(ctx, r, d, trd)
|
||||
default:
|
||||
@ -1465,7 +1468,7 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
|
||||
if !push {
|
||||
mi, ok := m.(manifest.Indexer)
|
||||
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)
|
||||
dl, err := mi.GetManifestList()
|
||||
@ -1473,7 +1476,7 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
|
||||
return err
|
||||
}
|
||||
// locate the digest in the index
|
||||
var d types.Descriptor
|
||||
var d descriptor.Descriptor
|
||||
if len(dl) == 1 {
|
||||
d = dl[0]
|
||||
} 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
|
||||
mi, ok := m.(manifest.Indexer)
|
||||
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()
|
||||
if err != nil {
|
||||
@ -1529,14 +1532,14 @@ func (rc *RegClient) imageImportOCIHandleManifest(ctx context.Context, r ref.Ref
|
||||
// else if a single image/manifest
|
||||
mi, ok := m.(manifest.Imager)
|
||||
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
|
||||
cd, err := mi.GetConfig()
|
||||
if err == nil {
|
||||
filename := tarOCILayoutDescPath(cd)
|
||||
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 {
|
||||
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 {
|
||||
filename := tarOCILayoutDescPath(d)
|
||||
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 {
|
||||
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 !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
|
||||
}
|
||||
|
||||
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()))
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/config"
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
@ -72,17 +72,17 @@ func TestImageCheckBase(t *testing.T) {
|
||||
{
|
||||
name: "missing annotation",
|
||||
r: r1,
|
||||
expectErr: types.ErrMissingAnnotation,
|
||||
expectErr: errs.ErrMissingAnnotation,
|
||||
},
|
||||
{
|
||||
name: "annotation v2",
|
||||
r: r2,
|
||||
expectErr: types.ErrMismatch,
|
||||
expectErr: errs.ErrMismatch,
|
||||
},
|
||||
{
|
||||
name: "annotation v3",
|
||||
r: r3,
|
||||
expectErr: types.ErrMismatch,
|
||||
expectErr: errs.ErrMismatch,
|
||||
},
|
||||
{
|
||||
name: "manual v2, b1",
|
||||
@ -93,13 +93,13 @@ func TestImageCheckBase(t *testing.T) {
|
||||
name: "manual v2, b2",
|
||||
r: r2,
|
||||
opts: []ImageOpts{ImageWithCheckBaseRef(rb2.CommonName())},
|
||||
expectErr: types.ErrMismatch,
|
||||
expectErr: errs.ErrMismatch,
|
||||
},
|
||||
{
|
||||
name: "manual v2, b3",
|
||||
r: r2,
|
||||
opts: []ImageOpts{ImageWithCheckBaseRef(rb3.CommonName())},
|
||||
expectErr: types.ErrMismatch,
|
||||
expectErr: errs.ErrMismatch,
|
||||
},
|
||||
{
|
||||
name: "manual v3, b1",
|
||||
@ -203,7 +203,7 @@ func TestCopy(t *testing.T) {
|
||||
name: "ocidir to read-only registry",
|
||||
src: "ocidir://./testdata/testrepo:v1",
|
||||
tgt: tsROHost + "/dest-ocidir:v1",
|
||||
expectErr: types.ErrHTTPStatus,
|
||||
expectErr: errs.ErrHTTPStatus,
|
||||
},
|
||||
{
|
||||
name: "ocidir to ocidir",
|
||||
|
@ -16,7 +16,7 @@ import (
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
type charLU byte
|
||||
@ -490,7 +490,7 @@ func (b *BasicHandler) ProcessChallenge(c Challenge) error {
|
||||
func (b *BasicHandler) GenerateAuth() (string, error) {
|
||||
cred := b.credsFn(b.host)
|
||||
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))
|
||||
return fmt.Sprintf("Basic %s", auth), nil
|
||||
@ -608,14 +608,14 @@ func (b *BearerHandler) GenerateAuth() (string, error) {
|
||||
if err := b.tryPost(); err == nil {
|
||||
return fmt.Sprintf("Bearer %s", b.token.Token), nil
|
||||
} 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)
|
||||
if err := b.tryGet(); err == nil {
|
||||
return fmt.Sprintf("Bearer %s", b.token.Token), nil
|
||||
} 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
|
||||
|
@ -1,24 +1,40 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
var (
|
||||
// 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 = types.ErrInvalidChallenge
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrInvalidChallenge].
|
||||
ErrInvalidChallenge = errs.ErrInvalidChallenge
|
||||
// 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 = types.ErrNotFound
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrNotFound].
|
||||
ErrNotFound = errs.ErrNotFound
|
||||
// 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 = types.ErrParsingFailed
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrParseFailure].
|
||||
ErrParseFailure = errs.ErrParsingFailed
|
||||
// ErrUnauthorized request was not authorized
|
||||
ErrUnauthorized = types.ErrHTTPUnauthorized
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrUnauthorized].
|
||||
ErrUnauthorized = errs.ErrHTTPUnauthorized
|
||||
// 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"
|
||||
"time"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
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) {
|
||||
if c == nil {
|
||||
var val v
|
||||
return val, types.ErrNotFound
|
||||
return val, errs.ErrNotFound
|
||||
}
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
@ -119,7 +119,7 @@ func (c *Cache[k, v]) Get(key k) (v, error) {
|
||||
}
|
||||
}
|
||||
var val v
|
||||
return val, types.ErrNotFound
|
||||
return val, errs.ErrNotFound
|
||||
}
|
||||
|
||||
func (c *Cache[k, v]) prune() {
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
type Links []Link
|
||||
@ -75,7 +75,7 @@ func Parse(headers []string) (Links, error) {
|
||||
// noop
|
||||
} else {
|
||||
// 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":
|
||||
// parse tokens until space or comma
|
||||
@ -90,7 +90,7 @@ func Parse(headers []string) (Links, error) {
|
||||
endLink()
|
||||
} else {
|
||||
// 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":
|
||||
// parse tokens until quote
|
||||
@ -109,7 +109,7 @@ func Parse(headers []string) (Links, error) {
|
||||
// noop
|
||||
} else {
|
||||
// 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":
|
||||
if len(pnb) > 0 && b == '=' {
|
||||
@ -122,14 +122,14 @@ func Parse(headers []string) (Links, error) {
|
||||
// noop
|
||||
} else {
|
||||
// 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":
|
||||
if b == '=' {
|
||||
state = "parmValue"
|
||||
} else {
|
||||
// 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":
|
||||
if len(pvb) == 0 {
|
||||
@ -139,7 +139,7 @@ func Parse(headers []string) (Links, error) {
|
||||
state = "parmValueQuoted"
|
||||
} else {
|
||||
// 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 {
|
||||
if charLUs[b]&isToken != 0 {
|
||||
@ -156,7 +156,7 @@ func Parse(headers []string) (Links, error) {
|
||||
endLink()
|
||||
} else {
|
||||
// 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":
|
||||
@ -178,7 +178,7 @@ func Parse(headers []string) (Links, error) {
|
||||
case "init":
|
||||
// noop
|
||||
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{}, types.ErrNotFound
|
||||
return Link{}, errs.ErrNotFound
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
func TestParseErr(t *testing.T) {
|
||||
@ -122,7 +122,7 @@ func TestParseGet(t *testing.T) {
|
||||
}
|
||||
link, err := links.Get(tt.parm, tt.val)
|
||||
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)
|
||||
}
|
||||
return
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
type LimitRead struct {
|
||||
@ -15,7 +15,7 @@ type LimitRead struct {
|
||||
|
||||
func (lr *LimitRead) Read(p []byte) (int, error) {
|
||||
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 {
|
||||
p = p[0 : lr.Limit+1]
|
||||
@ -23,7 +23,7 @@ func (lr *LimitRead) Read(p []byte) (int, error) {
|
||||
n, err := lr.Reader.Read(p)
|
||||
lr.Limit -= int64(n)
|
||||
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
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
func TestLimitRead(t *testing.T) {
|
||||
@ -64,7 +64,7 @@ func TestLimitRead(t *testing.T) {
|
||||
limit: 9,
|
||||
src: byte10,
|
||||
try: 10,
|
||||
expectErr: types.ErrSizeLimitExceeded,
|
||||
expectErr: errs.ErrSizeLimitExceeded,
|
||||
},
|
||||
}
|
||||
for _, tc := range tt {
|
||||
|
@ -31,7 +31,7 @@ import (
|
||||
"github.com/regclient/regclient/config"
|
||||
"github.com/regclient/regclient/internal/auth"
|
||||
"github.com/regclient/regclient/internal/throttle"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/warning"
|
||||
)
|
||||
|
||||
@ -266,7 +266,7 @@ func (resp *clientResp) Next() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return types.ErrAllRequestsFailed
|
||||
return errs.ErrAllRequestsFailed
|
||||
}
|
||||
if curHost >= len(hosts) {
|
||||
curHost = 0
|
||||
@ -295,14 +295,14 @@ func (resp *clientResp) Next() error {
|
||||
var err error
|
||||
if !okAPI {
|
||||
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 {
|
||||
var disableHead bool
|
||||
disableHead, err = strconv.ParseBool(h.config.APIOpts["disableHead"])
|
||||
if err == nil && disableHead {
|
||||
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")
|
||||
select {
|
||||
case <-resp.ctx.Done():
|
||||
return types.ErrCanceled
|
||||
return errs.ErrCanceled
|
||||
case <-time.After(sleepTime):
|
||||
}
|
||||
}
|
||||
@ -402,7 +402,7 @@ func (resp *clientResp) Next() error {
|
||||
// add auth headers
|
||||
err = hAuth.UpdateRequest(httpReq)
|
||||
if err != nil {
|
||||
if errors.Is(err, types.ErrHTTPUnauthorized) {
|
||||
if errors.Is(err, errs.ErrHTTPUnauthorized) {
|
||||
dropHost = true
|
||||
} else {
|
||||
backoff = true
|
||||
@ -453,7 +453,7 @@ func (resp *clientResp) Next() error {
|
||||
err = fmt.Errorf("authentication handler unavailable")
|
||||
}
|
||||
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{
|
||||
"URL": u.String(),
|
||||
"Err": err,
|
||||
@ -535,7 +535,7 @@ func (resp *clientResp) Next() error {
|
||||
}
|
||||
}
|
||||
// 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
|
||||
}
|
||||
err = loopErr
|
||||
@ -556,7 +556,7 @@ func (resp *clientResp) Read(b []byte) (int, error) {
|
||||
return 0, io.EOF
|
||||
}
|
||||
if resp.resp == nil {
|
||||
return 0, types.ErrNotFound
|
||||
return 0, errs.ErrNotFound
|
||||
}
|
||||
// perform the read
|
||||
i, err := resp.reader.Read(b)
|
||||
@ -595,7 +595,7 @@ func (resp *clientResp) Read(b []byte) (int, error) {
|
||||
}).Warn("Digest mismatch")
|
||||
_ = resp.backoffSet()
|
||||
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())
|
||||
}
|
||||
}
|
||||
@ -612,7 +612,7 @@ func (resp *clientResp) Close() error {
|
||||
resp.throttle = nil
|
||||
}
|
||||
if resp.resp == nil {
|
||||
return types.ErrNotFound
|
||||
return errs.ErrNotFound
|
||||
}
|
||||
if !resp.done {
|
||||
resp.backoffClear()
|
||||
@ -695,7 +695,7 @@ func (resp *clientResp) backoffSet() error {
|
||||
ch.backoffUntil = time.Now().Add(sleepTime)
|
||||
|
||||
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
|
||||
@ -831,15 +831,15 @@ func (ch *clientHost) AuthCreds() func(h string) auth.Cred {
|
||||
func HTTPError(statusCode int) error {
|
||||
switch statusCode {
|
||||
case 401:
|
||||
return fmt.Errorf("%w [http %d]", types.ErrHTTPUnauthorized, statusCode)
|
||||
return fmt.Errorf("%w [http %d]", errs.ErrHTTPUnauthorized, statusCode)
|
||||
case 403:
|
||||
return fmt.Errorf("%w [http %d]", types.ErrHTTPUnauthorized, statusCode)
|
||||
return fmt.Errorf("%w [http %d]", errs.ErrHTTPUnauthorized, statusCode)
|
||||
case 404:
|
||||
return fmt.Errorf("%w [http %d]", types.ErrNotFound, statusCode)
|
||||
return fmt.Errorf("%w [http %d]", errs.ErrNotFound, statusCode)
|
||||
case 429:
|
||||
return fmt.Errorf("%w [http %d]", types.ErrHTTPRateLimit, statusCode)
|
||||
return fmt.Errorf("%w [http %d]", errs.ErrHTTPRateLimit, statusCode)
|
||||
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/internal/auth"
|
||||
"github.com/regclient/regclient/internal/reqresp"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/warning"
|
||||
)
|
||||
|
||||
@ -893,7 +893,7 @@ func TestRegHttp(t *testing.T) {
|
||||
body, err := io.ReadAll(resp)
|
||||
if err == nil {
|
||||
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)
|
||||
}
|
||||
err = resp.Close()
|
||||
@ -926,7 +926,7 @@ func TestRegHttp(t *testing.T) {
|
||||
body, err := io.ReadAll(resp)
|
||||
if err == nil {
|
||||
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)
|
||||
}
|
||||
err = resp.Close()
|
||||
@ -1064,8 +1064,8 @@ func TestRegHttp(t *testing.T) {
|
||||
if err == nil {
|
||||
resp.Close()
|
||||
t.Fatalf("unexpected success with bad password")
|
||||
} else if !errors.Is(err, auth.ErrUnauthorized) {
|
||||
t.Errorf("expected error %v, received error %v", auth.ErrUnauthorized, err)
|
||||
} else if !errors.Is(err, errs.ErrHTTPUnauthorized) {
|
||||
t.Errorf("expected error %v, received error %v", errs.ErrHTTPUnauthorized, err)
|
||||
}
|
||||
})
|
||||
t.Run("Bad auth", func(t *testing.T) {
|
||||
@ -1086,8 +1086,8 @@ func TestRegHttp(t *testing.T) {
|
||||
if err == nil {
|
||||
resp.Close()
|
||||
t.Fatalf("unexpected success with bad auth header")
|
||||
} else if !errors.Is(err, types.ErrParsingFailed) {
|
||||
t.Errorf("expected error %v, received error %v", types.ErrParsingFailed, err)
|
||||
} else if !errors.Is(err, errs.ErrParsingFailed) {
|
||||
t.Errorf("expected error %v, received error %v", errs.ErrParsingFailed, err)
|
||||
}
|
||||
})
|
||||
t.Run("Missing auth", func(t *testing.T) {
|
||||
@ -1108,8 +1108,8 @@ func TestRegHttp(t *testing.T) {
|
||||
if err == nil {
|
||||
resp.Close()
|
||||
t.Fatalf("unexpected success with missing auth header")
|
||||
} else if !errors.Is(err, types.ErrEmptyChallenge) {
|
||||
t.Errorf("expected error %v, received error %v", types.ErrEmptyChallenge, err)
|
||||
} else if !errors.Is(err, errs.ErrEmptyChallenge) {
|
||||
t.Errorf("expected error %v, received error %v", errs.ErrEmptyChallenge, err)
|
||||
}
|
||||
})
|
||||
// test repoauth
|
||||
@ -1408,8 +1408,8 @@ func TestRegHttp(t *testing.T) {
|
||||
if err == nil {
|
||||
resp.Close()
|
||||
t.Fatalf("unexpected success on get for missing manifest")
|
||||
} else if !errors.Is(err, types.ErrNotFound) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", types.ErrNotFound, err)
|
||||
} else if !errors.Is(err, errs.ErrNotFound) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", errs.ErrNotFound, err)
|
||||
}
|
||||
})
|
||||
t.Run("Forbidden", func(t *testing.T) {
|
||||
@ -1430,8 +1430,8 @@ func TestRegHttp(t *testing.T) {
|
||||
if err == nil {
|
||||
resp.Close()
|
||||
t.Fatalf("unexpected success on get for missing manifest")
|
||||
} else if !errors.Is(err, types.ErrHTTPUnauthorized) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", types.ErrHTTPUnauthorized, err)
|
||||
} else if !errors.Is(err, errs.ErrHTTPUnauthorized) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", errs.ErrHTTPUnauthorized, err)
|
||||
}
|
||||
})
|
||||
t.Run("Bad GW", func(t *testing.T) {
|
||||
@ -1452,8 +1452,8 @@ func TestRegHttp(t *testing.T) {
|
||||
if err == nil {
|
||||
resp.Close()
|
||||
t.Fatalf("unexpected success on get for missing manifest")
|
||||
} else if !errors.Is(err, types.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", types.ErrHTTPStatus, err)
|
||||
} else if !errors.Is(err, errs.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", errs.ErrHTTPStatus, err)
|
||||
}
|
||||
})
|
||||
t.Run("GW Timeout", func(t *testing.T) {
|
||||
@ -1474,8 +1474,8 @@ func TestRegHttp(t *testing.T) {
|
||||
if err == nil {
|
||||
resp.Close()
|
||||
t.Fatalf("unexpected success on get for missing manifest")
|
||||
} else if !errors.Is(err, types.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", types.ErrHTTPStatus, err)
|
||||
} else if !errors.Is(err, errs.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", errs.ErrHTTPStatus, err)
|
||||
}
|
||||
})
|
||||
t.Run("Server error", func(t *testing.T) {
|
||||
@ -1496,8 +1496,8 @@ func TestRegHttp(t *testing.T) {
|
||||
if err == nil {
|
||||
resp.Close()
|
||||
t.Fatalf("unexpected success on get for missing manifest")
|
||||
} else if !errors.Is(err, types.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", types.ErrHTTPStatus, err)
|
||||
} else if !errors.Is(err, errs.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", errs.ErrHTTPStatus, err)
|
||||
}
|
||||
})
|
||||
// test context expire during retries
|
||||
|
@ -4,7 +4,7 @@ package strparse
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
// 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":
|
||||
procKV()
|
||||
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
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
func TestSplitCSKV(t *testing.T) {
|
||||
@ -60,22 +60,22 @@ func TestSplitCSKV(t *testing.T) {
|
||||
{
|
||||
name: "errEscapeKey",
|
||||
str: "a\\",
|
||||
err: types.ErrParsingFailed,
|
||||
err: errs.ErrParsingFailed,
|
||||
},
|
||||
{
|
||||
name: "errEscapeVal",
|
||||
str: "a=x\\",
|
||||
err: types.ErrParsingFailed,
|
||||
err: errs.ErrParsingFailed,
|
||||
},
|
||||
{
|
||||
name: "errQuoteKey",
|
||||
str: "a\"",
|
||||
err: types.ErrParsingFailed,
|
||||
err: errs.ErrParsingFailed,
|
||||
},
|
||||
{
|
||||
name: "errQuoteVal",
|
||||
str: "a=b\"",
|
||||
err: types.ErrParsingFailed,
|
||||
err: errs.ErrParsingFailed,
|
||||
},
|
||||
}
|
||||
for _, tc := range tt {
|
||||
|
15
manifest.go
15
manifest.go
@ -5,13 +5,14 @@ import (
|
||||
"fmt"
|
||||
|
||||
"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/ref"
|
||||
)
|
||||
|
||||
type manifestOpt struct {
|
||||
d types.Descriptor
|
||||
d descriptor.Descriptor
|
||||
schemeOpts []scheme.ManifestOpts
|
||||
requireDigest bool
|
||||
}
|
||||
@ -44,7 +45,7 @@ func WithManifestChild() ManifestOpts {
|
||||
|
||||
// WithManifestDesc includes the descriptor for ManifestGet.
|
||||
// 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) {
|
||||
opts.d = d
|
||||
}
|
||||
@ -62,7 +63,7 @@ func WithManifestRequireDigest() ManifestOpts {
|
||||
// All tags pointing to the manifest will be deleted.
|
||||
func (rc *RegClient) ManifestDelete(ctx context.Context, r ref.Ref, opts ...ManifestOpts) error {
|
||||
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{}}
|
||||
for _, fn := range opts {
|
||||
@ -78,7 +79,7 @@ func (rc *RegClient) ManifestDelete(ctx context.Context, r ref.Ref, opts ...Mani
|
||||
// ManifestGet retrieves a manifest.
|
||||
func (rc *RegClient) ManifestGet(ctx context.Context, r ref.Ref, opts ...ManifestOpts) (manifest.Manifest, error) {
|
||||
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{}}
|
||||
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).
|
||||
func (rc *RegClient) ManifestHead(ctx context.Context, r ref.Ref, opts ...ManifestOpts) (manifest.Manifest, error) {
|
||||
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{}}
|
||||
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.
|
||||
func (rc *RegClient) ManifestPut(ctx context.Context, r ref.Ref, m manifest.Manifest, opts ...ManifestOpts) error {
|
||||
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{}}
|
||||
for _, fn := range opts {
|
||||
|
@ -18,9 +18,11 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/config"
|
||||
"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/errs"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
@ -35,14 +37,14 @@ func TestManifest(t *testing.T) {
|
||||
digest1 := digest.FromString("example1")
|
||||
digest2 := digest.FromString("example2")
|
||||
m := schema2.Manifest{
|
||||
Config: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2ImageConfig,
|
||||
Config: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2ImageConfig,
|
||||
Size: 8,
|
||||
Digest: digest1,
|
||||
},
|
||||
Layers: []types.Descriptor{
|
||||
Layers: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeDocker2LayerGzip,
|
||||
MediaType: mediatype.Docker2LayerGzip,
|
||||
Size: 8,
|
||||
Digest: digest2,
|
||||
},
|
||||
@ -67,7 +69,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -83,7 +85,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -99,7 +101,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
},
|
||||
@ -114,7 +116,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -130,7 +132,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"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,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -223,7 +225,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mGet.GetDescriptor().Digest != mDigest {
|
||||
@ -239,7 +241,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mHead.GetDescriptor().Digest != mDigest {
|
||||
@ -255,7 +257,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mHead.GetDescriptor().Digest != mDigest {
|
||||
@ -270,8 +272,8 @@ func TestManifest(t *testing.T) {
|
||||
mNohead, err := rc.ManifestHead(ctx, noheadRef)
|
||||
if err == nil {
|
||||
t.Errorf("Unexpected successful head on \"no head\" registry: %v", mNohead)
|
||||
} else if !errors.Is(err, types.ErrUnsupportedAPI) {
|
||||
t.Errorf("Expected error, expected %v, received %v", types.ErrUnsupportedAPI, err)
|
||||
} else if !errors.Is(err, errs.ErrUnsupportedAPI) {
|
||||
t.Errorf("Expected error, expected %v, received %v", errs.ErrUnsupportedAPI, err)
|
||||
}
|
||||
})
|
||||
t.Run("Get No Head", func(t *testing.T) {
|
||||
@ -283,7 +285,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mNohead.GetDescriptor().Digest != mDigest {
|
||||
@ -306,8 +308,8 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("Failed creating getRef: %v", err)
|
||||
}
|
||||
d := types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
d := descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(mLen),
|
||||
Digest: mDigest,
|
||||
Data: mBody,
|
||||
@ -329,8 +331,8 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating getRef: %v", err)
|
||||
}
|
||||
d := types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
d := descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(mLen),
|
||||
Digest: mDigest,
|
||||
Data: []byte("invalid data"),
|
||||
@ -346,8 +348,8 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating missingRef: %v", err)
|
||||
}
|
||||
d := types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
d := descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(mLen),
|
||||
Digest: mDigest,
|
||||
Data: []byte("invalid data"),
|
||||
@ -363,8 +365,8 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Failed creating missingRef: %v", err)
|
||||
}
|
||||
d := types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
d := descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(mLen),
|
||||
Digest: missingDigest,
|
||||
Data: []byte("invalid data"),
|
||||
@ -381,11 +383,11 @@ func TestManifest(t *testing.T) {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
_, 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)
|
||||
}
|
||||
_, 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)
|
||||
}
|
||||
})
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -97,7 +97,7 @@ func WithConfigTimestamp(optTime OptTime) Opts {
|
||||
}
|
||||
// offset startHistory from base image history
|
||||
if !optTime.BaseRef.IsZero() {
|
||||
var d types.Descriptor
|
||||
var d descriptor.Descriptor
|
||||
for {
|
||||
mOpts := []regclient.ManifestOpts{}
|
||||
if d.Digest != "" {
|
||||
|
17
mod/dag.go
17
mod/dag.go
@ -11,8 +11,9 @@ import (
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
"github.com/regclient/regclient"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/blob"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -39,8 +40,8 @@ type dagConfig struct {
|
||||
type dagManifest struct {
|
||||
mod changes
|
||||
top bool // indicates the top level manifest (needed for manifest lists)
|
||||
origDesc types.Descriptor
|
||||
newDesc types.Descriptor
|
||||
origDesc descriptor.Descriptor
|
||||
newDesc descriptor.Descriptor
|
||||
m manifest.Manifest
|
||||
config *dagOCIConfig
|
||||
layers []*dagLayer
|
||||
@ -50,19 +51,19 @@ type dagManifest struct {
|
||||
|
||||
type dagOCIConfig struct {
|
||||
modified bool
|
||||
newDesc types.Descriptor
|
||||
newDesc descriptor.Descriptor
|
||||
oc blob.OCIConfig
|
||||
}
|
||||
|
||||
type dagLayer struct {
|
||||
mod changes
|
||||
newDesc types.Descriptor
|
||||
newDesc descriptor.Descriptor
|
||||
ucDigest digest.Digest // uncompressed descriptor
|
||||
desc types.Descriptor
|
||||
desc descriptor.Descriptor
|
||||
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
|
||||
getOpts := []regclient.ManifestOpts{}
|
||||
if d.Digest != "" {
|
||||
@ -92,7 +93,7 @@ func dagGet(ctx context.Context, rc *regclient.RegClient, rSrc ref.Ref, d types.
|
||||
// pull config
|
||||
doc := dagOCIConfig{}
|
||||
cd, err := mi.GetConfig()
|
||||
if err != nil && !errors.Is(err, types.ErrUnsupportedMediaType) {
|
||||
if err != nil && !errors.Is(err, errs.ErrUnsupportedMediaType) {
|
||||
return nil, err
|
||||
} else if err == nil && inListStr(cd.MediaType, mtWLConfig) {
|
||||
oc, err := rc.BlobGetOCIConfig(ctx, rSrc, cd)
|
||||
|
@ -10,7 +10,9 @@ import (
|
||||
"github.com/regclient/regclient"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/docker/schema2"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
@ -180,7 +182,7 @@ func WithAnnotationPromoteCommon() Opts {
|
||||
}
|
||||
mAnnot, ok := child.m.(manifest.Annotator)
|
||||
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()
|
||||
if err != nil {
|
||||
@ -289,7 +291,7 @@ func WithManifestToDocker() Opts {
|
||||
changed := false
|
||||
om := dm.m.GetOrig()
|
||||
if dm.m.IsList() {
|
||||
if dm.m.GetDescriptor().MediaType != types.MediaTypeDocker2ManifestList {
|
||||
if dm.m.GetDescriptor().MediaType != mediatype.Docker2ManifestList {
|
||||
ociM, err := manifest.OCIIndexFromAny(om)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -307,22 +309,22 @@ func WithManifestToDocker() Opts {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dm.m.GetDescriptor().MediaType != types.MediaTypeDocker2Manifest {
|
||||
if dm.m.GetDescriptor().MediaType != mediatype.Docker2Manifest {
|
||||
changed = true
|
||||
}
|
||||
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 {
|
||||
ociM.Config.MediaType = types.MediaTypeDocker2ImageConfig
|
||||
if ociM.Config.MediaType == mediatype.OCI1ImageConfig {
|
||||
ociM.Config.MediaType = mediatype.Docker2ImageConfig
|
||||
changed = true
|
||||
}
|
||||
for i, l := range ociM.Layers {
|
||||
if l.MediaType == types.MediaTypeOCI1LayerGzip {
|
||||
ociM.Layers[i].MediaType = types.MediaTypeDocker2LayerGzip
|
||||
if l.MediaType == mediatype.OCI1LayerGzip {
|
||||
ociM.Layers[i].MediaType = mediatype.Docker2LayerGzip
|
||||
changed = true
|
||||
} else if l.MediaType == types.MediaTypeOCI1ForeignLayerGzip {
|
||||
ociM.Layers[i].MediaType = types.MediaTypeDocker2ForeignLayer
|
||||
} else if l.MediaType == mediatype.OCI1ForeignLayerGzip {
|
||||
ociM.Layers[i].MediaType = mediatype.Docker2ForeignLayer
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
@ -365,7 +367,7 @@ func WithManifestToOCI() Opts {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dm.m.GetDescriptor().MediaType != types.MediaTypeOCI1ManifestList {
|
||||
if dm.m.GetDescriptor().MediaType != mediatype.OCI1ManifestList {
|
||||
changed = true
|
||||
om = ociM
|
||||
}
|
||||
@ -374,19 +376,19 @@ func WithManifestToOCI() Opts {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if dm.m.GetDescriptor().MediaType != types.MediaTypeOCI1Manifest {
|
||||
if dm.m.GetDescriptor().MediaType != mediatype.OCI1Manifest {
|
||||
changed = true
|
||||
}
|
||||
if ociM.Config.MediaType == types.MediaTypeDocker2ImageConfig {
|
||||
ociM.Config.MediaType = types.MediaTypeOCI1ImageConfig
|
||||
if ociM.Config.MediaType == mediatype.Docker2ImageConfig {
|
||||
ociM.Config.MediaType = mediatype.OCI1ImageConfig
|
||||
changed = true
|
||||
}
|
||||
for i, l := range ociM.Layers {
|
||||
if l.MediaType == types.MediaTypeDocker2LayerGzip {
|
||||
ociM.Layers[i].MediaType = types.MediaTypeOCI1LayerGzip
|
||||
if l.MediaType == mediatype.Docker2LayerGzip {
|
||||
ociM.Layers[i].MediaType = mediatype.OCI1LayerGzip
|
||||
changed = true
|
||||
} else if l.MediaType == types.MediaTypeDocker2ForeignLayer {
|
||||
ociM.Layers[i].MediaType = types.MediaTypeOCI1ForeignLayerGzip
|
||||
} else if l.MediaType == mediatype.Docker2ForeignLayer {
|
||||
ociM.Layers[i].MediaType = mediatype.OCI1ForeignLayerGzip
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
@ -514,14 +516,14 @@ func WithExternalURLsRm() Opts {
|
||||
ociOM.Layers[i].URLs = []string{}
|
||||
mt := ociOM.Layers[i].MediaType
|
||||
switch mt {
|
||||
case types.MediaTypeDocker2ForeignLayer:
|
||||
mt = types.MediaTypeDocker2LayerGzip
|
||||
case types.MediaTypeOCI1ForeignLayer:
|
||||
mt = types.MediaTypeOCI1Layer
|
||||
case types.MediaTypeOCI1ForeignLayerGzip:
|
||||
mt = types.MediaTypeOCI1LayerGzip
|
||||
case types.MediaTypeOCI1ForeignLayerZstd:
|
||||
mt = types.MediaTypeOCI1LayerZstd
|
||||
case mediatype.Docker2ForeignLayer:
|
||||
mt = mediatype.Docker2LayerGzip
|
||||
case mediatype.OCI1ForeignLayer:
|
||||
mt = mediatype.OCI1Layer
|
||||
case mediatype.OCI1ForeignLayerGzip:
|
||||
mt = mediatype.OCI1LayerGzip
|
||||
case mediatype.OCI1ForeignLayerZstd:
|
||||
mt = mediatype.OCI1LayerZstd
|
||||
}
|
||||
ociOM.Layers[i].MediaType = mt
|
||||
changed = true
|
||||
@ -572,11 +574,11 @@ func WithRebase() Opts {
|
||||
}
|
||||
baseName, ok := annot[types.AnnotationBaseImageName]
|
||||
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]
|
||||
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)
|
||||
if err != nil {
|
||||
@ -712,15 +714,15 @@ func rebaseAddStep(dc *dagConfig, rBaseOld, rBaseNew ref.Ref) error {
|
||||
|
||||
// validate current base
|
||||
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 {
|
||||
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) {
|
||||
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
|
||||
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].CreatedBy != confOCIOld.History[i].CreatedBy ||
|
||||
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 {
|
||||
historyLayers++
|
||||
}
|
||||
}
|
||||
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) {
|
||||
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 {
|
||||
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
|
||||
|
19
mod/mod.go
19
mod/mod.go
@ -14,7 +14,8 @@ import (
|
||||
|
||||
"github.com/regclient/regclient"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -33,14 +34,14 @@ type OptTime struct {
|
||||
var (
|
||||
// whitelist of tar media types
|
||||
mtWLTar = []string{
|
||||
types.MediaTypeDocker2LayerGzip,
|
||||
types.MediaTypeOCI1Layer,
|
||||
types.MediaTypeOCI1LayerGzip,
|
||||
types.MediaTypeOCI1LayerZstd,
|
||||
mediatype.Docker2LayerGzip,
|
||||
mediatype.OCI1Layer,
|
||||
mediatype.OCI1LayerGzip,
|
||||
mediatype.OCI1LayerZstd,
|
||||
}
|
||||
mtWLConfig = []string{
|
||||
types.MediaTypeDocker2ImageConfig,
|
||||
types.MediaTypeOCI1ImageConfig,
|
||||
mediatype.Docker2ImageConfig,
|
||||
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?
|
||||
|
||||
// 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 {
|
||||
return rSrc, err
|
||||
}
|
||||
@ -143,7 +144,7 @@ func Apply(ctx context.Context, rc *regclient.RegClient, rSrc ref.Ref, opts ...O
|
||||
var gw *gzip.Writer
|
||||
digRaw := digest.Canonical.Digester() // raw/compressed 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())
|
||||
gw = gzip.NewWriter(cw)
|
||||
defer gw.Close()
|
||||
|
@ -18,8 +18,9 @@ import (
|
||||
"github.com/regclient/regclient/config"
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"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/mediatype"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
@ -739,7 +740,7 @@ func TestMod(t *testing.T) {
|
||||
WithRebase(),
|
||||
},
|
||||
ref: "ocidir://testrepo:v1",
|
||||
wantErr: types.ErrMissingAnnotation,
|
||||
wantErr: errs.ErrMissingAnnotation,
|
||||
},
|
||||
{
|
||||
name: "Rebase refs",
|
||||
@ -755,7 +756,7 @@ func TestMod(t *testing.T) {
|
||||
WithRebaseRefs(rb2, rb3),
|
||||
},
|
||||
ref: "ocidir://testrepo:v3",
|
||||
wantErr: types.ErrMismatch,
|
||||
wantErr: errs.ErrMismatch,
|
||||
},
|
||||
{
|
||||
name: "Rebase mismatch",
|
||||
@ -763,7 +764,7 @@ func TestMod(t *testing.T) {
|
||||
WithRebaseRefs(rb3, rb2),
|
||||
},
|
||||
ref: "ocidir://testrepo:v3",
|
||||
wantErr: types.ErrMismatch,
|
||||
wantErr: errs.ErrMismatch,
|
||||
},
|
||||
{
|
||||
name: "Rebase and backdate",
|
||||
@ -852,12 +853,12 @@ func TestMod(t *testing.T) {
|
||||
func TestInList(t *testing.T) {
|
||||
t.Parallel()
|
||||
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.Run("mismatch", func(t *testing.T) {
|
||||
if inListStr(types.MediaTypeDocker2LayerGzip, mtWLConfig) {
|
||||
if inListStr(mediatype.Docker2LayerGzip, mtWLConfig) {
|
||||
t.Errorf("found docker layer in config whitelist")
|
||||
}
|
||||
})
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"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/referrer"
|
||||
)
|
||||
@ -14,7 +14,7 @@ import (
|
||||
// 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) {
|
||||
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)
|
||||
if err != nil {
|
||||
|
@ -8,12 +8,32 @@ import (
|
||||
topBlob "github.com/regclient/regclient/types/blob"
|
||||
)
|
||||
|
||||
type Blob = topBlob.Blob
|
||||
type OCIConfig = topBlob.OCIConfig
|
||||
type Common = topBlob.Common
|
||||
type Reader = topBlob.Reader
|
||||
type (
|
||||
// Blob specifies a generic blob.
|
||||
//
|
||||
// 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 (
|
||||
// NewOCIConfig
|
||||
//
|
||||
// Deprecated: replace with [blob.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"
|
||||
)
|
||||
|
||||
type ConfigHost = config.Host
|
||||
type TLSConf = config.TLSConf
|
||||
type (
|
||||
// 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 (
|
||||
// TLSUndefined
|
||||
//
|
||||
// Deprecated: replace with [config.TLSUndefined].
|
||||
TLSUndefined = config.TLSUndefined
|
||||
TLSEnabled = config.TLSEnabled
|
||||
TLSInsecure = config.TLSInsecure
|
||||
TLSDisabled = config.TLSDisabled
|
||||
// TLSEnabled
|
||||
//
|
||||
// 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"
|
||||
)
|
||||
|
||||
type TLSConf = topConfig.TLSConf
|
||||
type Host = topConfig.Host
|
||||
|
||||
const (
|
||||
TLSUndefined = topConfig.TLSUndefined
|
||||
TLSEnabled = topConfig.TLSEnabled
|
||||
TLSInsecure = topConfig.TLSInsecure
|
||||
TLSDisabled = topConfig.TLSDisabled
|
||||
DockerRegistry = topConfig.DockerRegistry
|
||||
DockerRegistryAuth = topConfig.DockerRegistryAuth
|
||||
DockerRegistryDNS = topConfig.DockerRegistryDNS
|
||||
type (
|
||||
// TLSConf defines the TLS enumerated values.
|
||||
//
|
||||
// Deprecated: replace with [config.TLSConf].
|
||||
TLSConf = topConfig.TLSConf
|
||||
// Host defines a registry configuration.
|
||||
//
|
||||
// Deprecated: replace with [config.Host].
|
||||
Host = topConfig.Host
|
||||
)
|
||||
|
||||
var HostNew = topConfig.HostNew
|
||||
var HostNewName = topConfig.HostNewName
|
||||
const (
|
||||
// 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
|
||||
|
||||
import (
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAPINotFound = types.ErrAPINotFound
|
||||
ErrCanceled = types.ErrCanceled
|
||||
// ErrAPINotFound
|
||||
//
|
||||
// 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
|
||||
ErrHttpStatus = types.ErrHTTPStatus
|
||||
ErrMissingDigest = types.ErrMissingDigest
|
||||
ErrMissingLocation = types.ErrMissingLocation
|
||||
ErrMissingName = types.ErrMissingName
|
||||
ErrMissingTag = types.ErrMissingTag
|
||||
ErrMissingTagOrDigest = types.ErrMissingTagOrDigest
|
||||
ErrMountReturnedLocation = types.ErrMountReturnedLocation
|
||||
ErrNotFound = types.ErrNotFound
|
||||
ErrNotImplemented = types.ErrNotImplemented
|
||||
ErrParsingFailed = types.ErrParsingFailed
|
||||
ErrRateLimit = types.ErrHTTPRateLimit
|
||||
ErrUnavailable = types.ErrUnavailable
|
||||
ErrUnauthorized = types.ErrHTTPUnauthorized
|
||||
ErrUnsupportedAPI = types.ErrUnsupportedAPI
|
||||
ErrUnsupportedConfigVersion = types.ErrUnsupportedConfigVersion
|
||||
ErrUnsupportedMediaType = types.ErrUnsupportedMediaType
|
||||
// ErrHttpStatus
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrHttpStatus].
|
||||
ErrHttpStatus = errs.ErrHTTPStatus
|
||||
// ErrMissingDigest
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrMissingDigest].
|
||||
ErrMissingDigest = errs.ErrMissingDigest
|
||||
// ErrMissingLocation
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrMissingLocation].
|
||||
ErrMissingLocation = errs.ErrMissingLocation
|
||||
// ErrMissingName
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrMissingName].
|
||||
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"
|
||||
|
||||
topTypes "github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
topManifest "github.com/regclient/regclient/types/manifest"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
const (
|
||||
MediaTypeDocker1Manifest = topTypes.MediaTypeDocker1Manifest
|
||||
MediaTypeDocker1ManifestSigned = topTypes.MediaTypeDocker1ManifestSigned
|
||||
MediaTypeDocker2Manifest = topTypes.MediaTypeDocker2Manifest
|
||||
MediaTypeDocker2ManifestList = topTypes.MediaTypeDocker2ManifestList
|
||||
MediaTypeDocker2ImageConfig = topTypes.MediaTypeDocker2ImageConfig
|
||||
MediaTypeOCI1Manifest = topTypes.MediaTypeOCI1Manifest
|
||||
MediaTypeOCI1ManifestList = topTypes.MediaTypeOCI1ManifestList
|
||||
MediaTypeOCI1ImageConfig = topTypes.MediaTypeOCI1ImageConfig
|
||||
MediaTypeDocker2Layer = topTypes.MediaTypeDocker2LayerGzip
|
||||
MediaTypeOCI1Layer = topTypes.MediaTypeOCI1Layer
|
||||
MediaTypeOCI1LayerGzip = topTypes.MediaTypeOCI1LayerGzip
|
||||
MediaTypeBuildkitCacheConfig = topTypes.MediaTypeBuildkitCacheConfig
|
||||
// MediaTypeDocker1Manifest
|
||||
//
|
||||
// Deprecated: replace with [mediatype.Docker1Manifest].
|
||||
MediaTypeDocker1Manifest = mediatype.Docker1Manifest
|
||||
// MediaTypeDocker1ManifestSigned
|
||||
//
|
||||
// Deprecated: replace with [mediatype.Docker1ManifestSigned].
|
||||
MediaTypeDocker1ManifestSigned = mediatype.Docker1ManifestSigned
|
||||
// MediaTypeDocker2Manifest
|
||||
//
|
||||
// Deprecated: replace with [mediatype.Docker2Manifest].
|
||||
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 (
|
||||
ErrNotFound = topTypes.ErrNotFound
|
||||
ErrNotImplemented = topTypes.ErrNotImplemented
|
||||
ErrUnavailable = topTypes.ErrUnavailable
|
||||
ErrUnsupportedMediaType = topTypes.ErrUnsupported
|
||||
// ErrNotFound
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrNotFound].
|
||||
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) {
|
||||
return topManifest.New(
|
||||
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) {
|
||||
return topManifest.New(
|
||||
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) {
|
||||
return topManifest.New(topManifest.WithOrig(orig))
|
||||
}
|
||||
|
@ -5,19 +5,55 @@
|
||||
|
||||
package regclient
|
||||
|
||||
import "github.com/regclient/regclient/types"
|
||||
import "github.com/regclient/regclient/types/mediatype"
|
||||
|
||||
var (
|
||||
MediaTypeDocker1Manifest = types.MediaTypeDocker1Manifest
|
||||
MediaTypeDocker1ManifestSigned = types.MediaTypeDocker1ManifestSigned
|
||||
MediaTypeDocker2Manifest = types.MediaTypeDocker2Manifest
|
||||
MediaTypeDocker2ManifestList = types.MediaTypeDocker2ManifestList
|
||||
MediaTypeDocker2ImageConfig = types.MediaTypeDocker2ImageConfig
|
||||
MediaTypeOCI1Manifest = types.MediaTypeOCI1Manifest
|
||||
MediaTypeOCI1ManifestList = types.MediaTypeOCI1ManifestList
|
||||
MediaTypeOCI1ImageConfig = types.MediaTypeOCI1ImageConfig
|
||||
MediaTypeDocker2Layer = types.MediaTypeDocker2LayerGzip
|
||||
MediaTypeOCI1Layer = types.MediaTypeOCI1Layer
|
||||
MediaTypeOCI1LayerGzip = types.MediaTypeOCI1LayerGzip
|
||||
MediaTypeBuildkitCacheConfig = types.MediaTypeBuildkitCacheConfig
|
||||
// MediaTypeDocker1Manifest
|
||||
//
|
||||
// Deprecated: replace with [mediatype.Docker1Manifest].
|
||||
MediaTypeDocker1Manifest = mediatype.Docker1Manifest
|
||||
// MediaTypeDocker1ManifestSigned
|
||||
//
|
||||
// Deprecated: replace with [mediatype.Docker1ManifestSigned]
|
||||
MediaTypeDocker1ManifestSigned = mediatype.Docker1ManifestSigned
|
||||
// MediaTypeDocker2Manifest
|
||||
//
|
||||
// Deprecated: replace with [mediatype.Docker2Manifest].
|
||||
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 (
|
||||
// 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"
|
||||
)
|
||||
|
||||
type RegClient = *rcTop.RegClient
|
||||
type Client = *rcTop.RegClient
|
||||
type Opt = rcTop.Opt
|
||||
type ImageOpts = rcTop.ImageOpts
|
||||
type RepoList = *repo.RepoList
|
||||
type RepoDockerList = repo.RepoRegistryList
|
||||
type RepoOpts = scheme.RepoOpts // RepoOpts is a breaking change (struct to func opts)
|
||||
type TagList = *tag.List
|
||||
type TagDockerList = tag.DockerList
|
||||
type TagOpts = scheme.TagOpts
|
||||
type (
|
||||
// RegClient is used to access OCI distribution-spec registries.
|
||||
//
|
||||
// Deprecated: replace with [regclient.RegClient]
|
||||
RegClient = *rcTop.RegClient
|
||||
// Client is used to access OCI distribution-spec registries.
|
||||
//
|
||||
// Deprecated: replace with [regclient.RegClient]
|
||||
Client = *rcTop.RegClient
|
||||
// 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 (
|
||||
NewRegClient = rcTop.New
|
||||
WithCertDir = rcTop.WithCertDir
|
||||
WithDockerCerts = rcTop.WithDockerCerts
|
||||
WithDockerCreds = rcTop.WithDockerCreds
|
||||
WithConfigHosts = rcTop.WithConfigHosts
|
||||
WithConfigHost = rcTop.WithConfigHost
|
||||
WithBlobSize = rcTop.WithBlobSize
|
||||
WithLog = rcTop.WithLog
|
||||
WithRetryDelay = rcTop.WithRetryDelay
|
||||
WithRetryLimit = rcTop.WithRetryLimit
|
||||
WithUserAgent = rcTop.WithUserAgent
|
||||
// NewRegClient creates a new regclient instance.
|
||||
//
|
||||
// Deprecated: replace with [regclient.New].
|
||||
NewRegClient = rcTop.New
|
||||
// WithCertDir adds a path of certificates to trust similar to Docker's /etc/docker/certs.d.
|
||||
//
|
||||
// Deprecated: replace with [regclient.WithCertDir].
|
||||
WithCertDir = rcTop.WithCertDir
|
||||
// WithDockerCerts adds certificates trusted by docker in /etc/docker/certs.d.
|
||||
//
|
||||
// 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
|
||||
ImageWithDigestTags = rcTop.ImageWithDigestTags
|
||||
ImageWithPlatforms = rcTop.ImageWithPlatforms
|
||||
WithRepoLast = scheme.WithRepoLast
|
||||
WithRepoLimit = scheme.WithRepoLimit
|
||||
TagOptLast = scheme.WithTagLast
|
||||
TagOptLimit = scheme.WithTagLimit
|
||||
// ImageWithDigestTags looks for "sha-<digest>.*" tags in the repo to copy with any manifest in ImageCopy.
|
||||
//
|
||||
// Deprecated: replace with [regclient.ImageWithDigestTags].
|
||||
ImageWithDigestTags = rcTop.ImageWithDigestTags
|
||||
// ImageWithPlatform requests specific platforms from a manifest list in ImageCheckBase.
|
||||
//
|
||||
// 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"
|
||||
)
|
||||
|
||||
// TemplateFuncs adds functions to a template.
|
||||
//
|
||||
// Deprecated: replace with [gotemplate.FuncMap].
|
||||
var TemplateFuncs = gotemplate.FuncMap{}
|
||||
|
@ -6,35 +6,113 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
topTypes "github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrAllRequestsFailed = topTypes.ErrAllRequestsFailed
|
||||
ErrAPINotFound = topTypes.ErrAPINotFound
|
||||
ErrBackoffLimit = topTypes.ErrBackoffLimit
|
||||
ErrCanceled = topTypes.ErrCanceled
|
||||
ErrDigestMismatch = topTypes.ErrDigestMismatch
|
||||
ErrEmptyChallenge = topTypes.ErrEmptyChallenge
|
||||
// ErrAllRequestsFailed
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrAllRequestsFailed].
|
||||
ErrAllRequestsFailed = errs.ErrAllRequestsFailed
|
||||
// ErrAPINotFound
|
||||
//
|
||||
// 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
|
||||
ErrHttpStatus = topTypes.ErrHTTPStatus
|
||||
ErrInvalidChallenge = topTypes.ErrInvalidChallenge
|
||||
ErrMissingDigest = topTypes.ErrMissingDigest
|
||||
ErrMissingLocation = topTypes.ErrMissingLocation
|
||||
ErrMissingName = topTypes.ErrMissingName
|
||||
ErrMissingTag = topTypes.ErrMissingTag
|
||||
ErrMissingTagOrDigest = topTypes.ErrMissingTagOrDigest
|
||||
ErrMountReturnedLocation = topTypes.ErrMountReturnedLocation
|
||||
ErrNoNewChallenge = topTypes.ErrNoNewChallenge
|
||||
ErrNotFound = topTypes.ErrNotFound
|
||||
ErrNotImplemented = topTypes.ErrNotImplemented
|
||||
ErrParsingFailed = topTypes.ErrParsingFailed
|
||||
ErrRateLimit = topTypes.ErrHTTPRateLimit
|
||||
ErrRetryNeeded = topTypes.ErrRetryNeeded
|
||||
ErrUnavailable = topTypes.ErrUnavailable
|
||||
ErrUnauthorized = topTypes.ErrHTTPUnauthorized
|
||||
ErrUnsupported = topTypes.ErrUnsupported
|
||||
ErrUnsupportedAPI = topTypes.ErrUnsupportedAPI
|
||||
ErrUnsupportedConfigVersion = topTypes.ErrUnsupportedConfigVersion
|
||||
ErrUnsupportedMediaType = topTypes.ErrUnsupportedMediaType
|
||||
// ErrHttpStatus
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrHttpStatus].
|
||||
ErrHttpStatus = errs.ErrHTTPStatus
|
||||
// ErrInvalidChallenge
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrInvalidChallenge].
|
||||
ErrInvalidChallenge = errs.ErrInvalidChallenge
|
||||
// ErrMissingDigest
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrMissingDigest].
|
||||
ErrMissingDigest = errs.ErrMissingDigest
|
||||
// ErrMissingLocation
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrMissingLocation].
|
||||
ErrMissingLocation = errs.ErrMissingLocation
|
||||
// ErrMissingName
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrMissingName].
|
||||
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
|
||||
|
||||
import (
|
||||
topTypes "github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
)
|
||||
|
||||
const (
|
||||
MediaTypeDocker1Manifest = topTypes.MediaTypeDocker1Manifest
|
||||
MediaTypeDocker1ManifestSigned = topTypes.MediaTypeDocker1ManifestSigned
|
||||
MediaTypeDocker2Manifest = topTypes.MediaTypeDocker2Manifest
|
||||
MediaTypeDocker2ManifestList = topTypes.MediaTypeDocker2ManifestList
|
||||
MediaTypeDocker2ImageConfig = topTypes.MediaTypeDocker2ImageConfig
|
||||
MediaTypeOCI1Manifest = topTypes.MediaTypeOCI1Manifest
|
||||
MediaTypeOCI1ManifestList = topTypes.MediaTypeOCI1ManifestList
|
||||
MediaTypeOCI1ImageConfig = topTypes.MediaTypeOCI1ImageConfig
|
||||
MediaTypeDocker2Layer = topTypes.MediaTypeDocker2LayerGzip
|
||||
MediaTypeOCI1Layer = topTypes.MediaTypeOCI1Layer
|
||||
MediaTypeOCI1LayerGzip = topTypes.MediaTypeOCI1LayerGzip
|
||||
MediaTypeBuildkitCacheConfig = topTypes.MediaTypeBuildkitCacheConfig
|
||||
// MediaTypeDocker1Manifest
|
||||
//
|
||||
// Deprecated: replaced by [mediatype.Docker1Manifest].
|
||||
MediaTypeDocker1Manifest = mediatype.Docker1Manifest
|
||||
// MediaTypeDocker1ManifestSigned
|
||||
//
|
||||
// Deprecated: replaced by [mediatype.Docker1ManifestSigned]
|
||||
MediaTypeDocker1ManifestSigned = mediatype.Docker1ManifestSigned
|
||||
// MediaTypeDocker2Manifest
|
||||
//
|
||||
// Deprecated: replaced by [mediatype.Docker2Manifest].
|
||||
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
|
||||
//
|
||||
// Deprecated: replace with [types.RateLimit].
|
||||
type RateLimit = topTypes.RateLimit
|
||||
|
@ -9,6 +9,12 @@ import (
|
||||
"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
|
||||
|
||||
// NewRef create a new [Ref].
|
||||
//
|
||||
// Deprecated: replace with [ref.New].
|
||||
var NewRef = ref.New
|
||||
|
6
repo.go
6
repo.go
@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/regclient/regclient/scheme"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"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) {
|
||||
i := strings.Index(hostname, "/")
|
||||
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")
|
||||
if err != nil {
|
||||
@ -27,7 +27,7 @@ func (rc *RegClient) RepoList(ctx context.Context, hostname string, opts ...sche
|
||||
}
|
||||
rl, ok := schemeAPI.(repoLister)
|
||||
if !ok {
|
||||
return nil, types.ErrNotImplemented
|
||||
return nil, errs.ErrNotImplemented
|
||||
}
|
||||
return rl.RepoList(ctx, hostname, opts...)
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
func TestRepoList(t *testing.T) {
|
||||
@ -27,7 +27,7 @@ func TestRepoList(t *testing.T) {
|
||||
WithRetryDelay(delayInit, delayMax),
|
||||
)
|
||||
_, err := rc.RepoList(ctx, "registry.example.com/path")
|
||||
if !errors.Is(err, types.ErrParsingFailed) {
|
||||
t.Errorf("RepoList unexpected error on hostname with a path: expected %v, received %v", types.ErrParsingFailed, err)
|
||||
if !errors.Is(err, errs.ErrParsingFailed) {
|
||||
t.Errorf("RepoList unexpected error on hostname with a path: expected %v, received %v", errs.ErrParsingFailed, err)
|
||||
}
|
||||
}
|
||||
|
@ -5,14 +5,14 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/regclient/regclient/scheme"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
func (rc *RegClient) schemeGet(scheme string) (scheme.API, error) {
|
||||
s, ok := rc.schemes[scheme]
|
||||
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
|
||||
}
|
||||
|
@ -16,21 +16,22 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/blob"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
// BlobDelete removes a blob from the repository.
|
||||
// This method does not verify that blobs are unused.
|
||||
// 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())
|
||||
return o.fs.Remove(file)
|
||||
}
|
||||
|
||||
// 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())
|
||||
fd, err := o.fs.Open(file)
|
||||
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
|
||||
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())
|
||||
fd, err := o.fs.Open(file)
|
||||
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
|
||||
func (o *OCIDir) BlobMount(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d types.Descriptor) error {
|
||||
return types.ErrUnsupported
|
||||
func (o *OCIDir) BlobMount(ctx context.Context, refSrc ref.Ref, refTgt ref.Ref, d descriptor.Descriptor) error {
|
||||
return errs.ErrUnsupported
|
||||
}
|
||||
|
||||
// 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)
|
||||
err := t.Acquire(ctx)
|
||||
if err != nil {
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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/ref"
|
||||
)
|
||||
@ -151,7 +151,7 @@ func TestBlob(t *testing.T) {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
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 {
|
||||
t.Errorf("blob put: %v", err)
|
||||
return
|
||||
|
@ -18,8 +18,9 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"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/mediatype"
|
||||
"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()
|
||||
|
||||
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{}
|
||||
@ -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 {
|
||||
// attempt to delete the referrer, but ignore if the referrer entry wasn't found
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -114,7 +115,7 @@ func (o *OCIDir) manifestGet(ctx context.Context, r ref.Ref) (manifest.Manifest,
|
||||
}
|
||||
}
|
||||
if desc.Digest == "" {
|
||||
return nil, types.ErrNotFound
|
||||
return nil, errs.ErrNotFound
|
||||
}
|
||||
file := path.Join(r.Path, "blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded())
|
||||
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 == "" {
|
||||
return nil, types.ErrNotFound
|
||||
return nil, errs.ErrNotFound
|
||||
}
|
||||
// verify underlying file exists
|
||||
file := path.Join(r.Path, "blobs", desc.Digest.Algorithm().String(), desc.Digest.Encoded())
|
||||
fi, err := rwfs.Stat(o.fs, file)
|
||||
if err != nil || fi.IsDir() {
|
||||
return nil, types.ErrNotFound
|
||||
return nil, errs.ErrNotFound
|
||||
}
|
||||
// if missing, set media type on desc
|
||||
if desc.MediaType == "" {
|
||||
@ -185,9 +186,9 @@ func (o *OCIDir) ManifestHead(ctx context.Context, r ref.Ref) (manifest.Manifest
|
||||
desc.MediaType = mt.MediaType
|
||||
desc.Size = int64(len(raw))
|
||||
} else if mt.SchemaVersion == 1 && len(mt.Signatures) > 0 {
|
||||
desc.MediaType = types.MediaTypeDocker1ManifestSigned
|
||||
desc.MediaType = mediatype.Docker1ManifestSigned
|
||||
} else if mt.SchemaVersion == 1 {
|
||||
desc.MediaType = types.MediaTypeDocker1Manifest
|
||||
desc.MediaType = mediatype.Docker1Manifest
|
||||
desc.Size = int64(len(raw))
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,8 @@ import (
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
@ -44,8 +44,8 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("manifest get: %v", err)
|
||||
}
|
||||
if manifest.GetMediaType(ml) != types.MediaTypeOCI1ManifestList {
|
||||
t.Errorf("manifest mt, expected %s, received %s", types.MediaTypeOCI1ManifestList, manifest.GetMediaType(ml))
|
||||
if manifest.GetMediaType(ml) != mediatype.OCI1ManifestList {
|
||||
t.Errorf("manifest mt, expected %s, received %s", mediatype.OCI1ManifestList, manifest.GetMediaType(ml))
|
||||
}
|
||||
if !ml.IsList() {
|
||||
t.Errorf("expected manifest list")
|
||||
|
@ -15,7 +15,9 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"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"
|
||||
"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
|
||||
}
|
||||
|
||||
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 {
|
||||
o.mu.Lock()
|
||||
defer o.mu.Unlock()
|
||||
@ -331,14 +333,14 @@ func (o *OCIDir) refMod(r ref.Ref) {
|
||||
func indexCreate() v1.Index {
|
||||
i := v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
Manifests: []types.Descriptor{},
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Manifests: []descriptor.Descriptor{},
|
||||
Annotations: map[string]string{},
|
||||
}
|
||||
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 == "" {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
if index.Manifests == nil {
|
||||
index.Manifests = []types.Descriptor{}
|
||||
index.Manifests = []descriptor.Descriptor{}
|
||||
}
|
||||
pos := -1
|
||||
// search for existing
|
||||
|
@ -8,7 +8,9 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"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"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
@ -61,29 +63,29 @@ func TestIndex(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("failed to generate ref: %v", err)
|
||||
}
|
||||
descNoTag := types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
descNoTag := descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: dig1,
|
||||
}
|
||||
descA := types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
descA := descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: dig2,
|
||||
Annotations: map[string]string{
|
||||
aOCIRefName: "tag-a",
|
||||
},
|
||||
}
|
||||
descB := types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
descB := descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: dig2,
|
||||
Annotations: map[string]string{
|
||||
aOCIRefName: "tag-b",
|
||||
},
|
||||
}
|
||||
descC := types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
descC := descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: dig3,
|
||||
Annotations: map[string]string{
|
||||
@ -94,23 +96,23 @@ func TestIndex(t *testing.T) {
|
||||
name string
|
||||
index v1.Index
|
||||
get ref.Ref
|
||||
expectGet types.Descriptor
|
||||
expectGet descriptor.Descriptor
|
||||
expectGetErr error
|
||||
set ref.Ref
|
||||
setDesc types.Descriptor
|
||||
setDesc descriptor.Descriptor
|
||||
expectLen int
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
get: rA,
|
||||
expectGetErr: types.ErrNotFound,
|
||||
expectGetErr: errs.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "no tag",
|
||||
index: v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
Manifests: []types.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Manifests: []descriptor.Descriptor{
|
||||
descNoTag,
|
||||
},
|
||||
},
|
||||
@ -124,8 +126,8 @@ func TestIndex(t *testing.T) {
|
||||
name: "tag a",
|
||||
index: v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
Manifests: []types.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Manifests: []descriptor.Descriptor{
|
||||
descNoTag,
|
||||
descA,
|
||||
},
|
||||
@ -140,8 +142,8 @@ func TestIndex(t *testing.T) {
|
||||
name: "tag b",
|
||||
index: v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
Manifests: []types.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Manifests: []descriptor.Descriptor{
|
||||
descNoTag,
|
||||
descB,
|
||||
},
|
||||
@ -156,8 +158,8 @@ func TestIndex(t *testing.T) {
|
||||
name: "tag c",
|
||||
index: v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
Manifests: []types.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Manifests: []descriptor.Descriptor{
|
||||
descA,
|
||||
descC,
|
||||
},
|
||||
|
@ -6,8 +6,9 @@ import (
|
||||
"fmt"
|
||||
|
||||
"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/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"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)
|
||||
if err != nil {
|
||||
if errors.Is(err, types.ErrNotFound) {
|
||||
if errors.Is(err, errs.ErrNotFound) {
|
||||
// empty list, initialize a new manifest
|
||||
rl.Manifest, err = manifest.New(manifest.WithOrig(v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
}))
|
||||
if err != nil {
|
||||
return rl, err
|
||||
@ -98,7 +99,7 @@ func (o *OCIDir) referrerDelete(ctx context.Context, r ref.Ref, m manifest.Manif
|
||||
// get refers field
|
||||
mSubject, ok := m.(manifest.Subjecter)
|
||||
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()
|
||||
if err != nil {
|
||||
@ -106,7 +107,7 @@ func (o *OCIDir) referrerDelete(ctx context.Context, r ref.Ref, m manifest.Manif
|
||||
}
|
||||
// validate/set subject descriptor
|
||||
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
|
||||
@ -142,7 +143,7 @@ func (o *OCIDir) referrerPut(ctx context.Context, r ref.Ref, m manifest.Manifest
|
||||
// get subject field
|
||||
mSubject, ok := m.(manifest.Subjecter)
|
||||
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()
|
||||
if err != nil {
|
||||
@ -150,7 +151,7 @@ func (o *OCIDir) referrerPut(ctx context.Context, r ref.Ref, m manifest.Manifest
|
||||
}
|
||||
// validate/set subject descriptor
|
||||
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
|
||||
|
@ -11,8 +11,9 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"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/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -75,15 +76,15 @@ func TestReferrer(t *testing.T) {
|
||||
}
|
||||
artifactA := v1.Manifest{
|
||||
Versioned: v1.ManifestSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
Config: types.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Config: descriptor.Descriptor{
|
||||
MediaType: aType,
|
||||
Size: 8,
|
||||
Digest: digest1,
|
||||
},
|
||||
Layers: []types.Descriptor{
|
||||
Layers: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1LayerGzip,
|
||||
MediaType: mediatype.OCI1LayerGzip,
|
||||
Size: 8,
|
||||
Digest: digest2,
|
||||
},
|
||||
@ -104,11 +105,11 @@ func TestReferrer(t *testing.T) {
|
||||
timeAnnot: "2021-02-03T04:05:06Z",
|
||||
}
|
||||
artifactB := v1.ArtifactManifest{
|
||||
MediaType: types.MediaTypeOCI1Artifact,
|
||||
MediaType: mediatype.OCI1Artifact,
|
||||
ArtifactType: bType,
|
||||
Blobs: []types.Descriptor{
|
||||
Blobs: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1LayerGzip,
|
||||
MediaType: mediatype.OCI1LayerGzip,
|
||||
Size: 8,
|
||||
Digest: digest2,
|
||||
},
|
||||
@ -125,11 +126,11 @@ func TestReferrer(t *testing.T) {
|
||||
t.Fatalf("failed extracting raw body from artifact: %v", err)
|
||||
}
|
||||
artifactC := v1.ArtifactManifest{
|
||||
MediaType: types.MediaTypeOCI1Artifact,
|
||||
MediaType: mediatype.OCI1Artifact,
|
||||
ArtifactType: cType,
|
||||
Blobs: []types.Descriptor{
|
||||
Blobs: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1LayerGzip,
|
||||
MediaType: mediatype.OCI1LayerGzip,
|
||||
Size: 8,
|
||||
Digest: digest2,
|
||||
},
|
||||
@ -182,7 +183,7 @@ func TestReferrer(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
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))
|
||||
}
|
||||
// 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].Digest != artifactAM.GetDescriptor().Digest ||
|
||||
rl.Descriptors[0].ArtifactType != aType ||
|
||||
@ -198,7 +199,7 @@ func TestReferrer(t *testing.T) {
|
||||
t.Errorf("returned descriptor A mismatch: %v", rl.Descriptors[0])
|
||||
}
|
||||
// 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].Digest != artifactBM.GetDescriptor().Digest ||
|
||||
rl.Descriptors[1].ArtifactType != bType ||
|
||||
@ -208,7 +209,7 @@ func TestReferrer(t *testing.T) {
|
||||
if len(rl.Tags) != 1 || rl.Tags[0] != tagRef {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList reverse: %v", err)
|
||||
}
|
||||
@ -226,14 +227,14 @@ func TestReferrer(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
if len(rl.Descriptors) != 1 {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
@ -246,21 +247,21 @@ func TestReferrer(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
if len(rl.Descriptors) != 1 {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
if len(rl.Descriptors) > 0 {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
|
@ -8,7 +8,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"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/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 {
|
||||
if r.Tag == "" {
|
||||
return types.ErrMissingTag
|
||||
return errs.ErrMissingTag
|
||||
}
|
||||
// get index
|
||||
index, err := o.readIndex(r, true)
|
||||
@ -38,7 +39,7 @@ func (o *OCIDir) tagDelete(ctx context.Context, r ref.Ref) error {
|
||||
}
|
||||
}
|
||||
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
|
||||
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(
|
||||
tag.WithRaw(ib),
|
||||
tag.WithRef(r),
|
||||
tag.WithMT(types.MediaTypeOCI1ManifestList),
|
||||
tag.WithMT(mediatype.OCI1ManifestList),
|
||||
tag.WithLayoutIndex(index),
|
||||
tag.WithTags(tl),
|
||||
)
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/regclient/regclient/internal/rwfs"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
@ -50,7 +50,7 @@ func TestTag(t *testing.T) {
|
||||
exTags := []string{"broken", "v0.3"}
|
||||
rCp.Tag = "missing"
|
||||
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)
|
||||
}
|
||||
rCp.Tag = "latest"
|
||||
|
@ -19,8 +19,9 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/regclient/regclient/internal/reghttp"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/blob"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
@ -29,7 +30,7 @@ var (
|
||||
)
|
||||
|
||||
// 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{
|
||||
Host: r.Registry,
|
||||
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
|
||||
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
|
||||
req := ®http.Req{
|
||||
Host: r.Registry,
|
||||
@ -99,7 +100,7 @@ func (reg *Reg) BlobGet(ctx context.Context, r ref.Ref, d types.Descriptor) (blo
|
||||
b := blob.NewReader(
|
||||
blob.WithRef(r),
|
||||
blob.WithReader(resp),
|
||||
blob.WithDesc(types.Descriptor{
|
||||
blob.WithDesc(descriptor.Descriptor{
|
||||
Digest: d.Digest,
|
||||
}),
|
||||
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
|
||||
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
|
||||
req := ®http.Req{
|
||||
Host: r.Registry,
|
||||
@ -156,7 +157,7 @@ func (reg *Reg) BlobHead(ctx context.Context, r ref.Ref, d types.Descriptor) (bl
|
||||
|
||||
b := blob.NewReader(
|
||||
blob.WithRef(r),
|
||||
blob.WithDesc(types.Descriptor{
|
||||
blob.WithDesc(descriptor.Descriptor{
|
||||
Digest: d.Digest,
|
||||
}),
|
||||
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
|
||||
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)
|
||||
// if mount fails and returns an upload location, cancel that upload
|
||||
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.
|
||||
// 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).
|
||||
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 err error
|
||||
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 {
|
||||
return d, nil
|
||||
}
|
||||
if err != types.ErrMountReturnedLocation {
|
||||
if err != errs.ErrMountReturnedLocation {
|
||||
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.
|
||||
location := resp.HTTPResponse().Header.Get("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{
|
||||
"location": location,
|
||||
@ -307,7 +308,7 @@ func (reg *Reg) blobGetUploadURL(ctx context.Context, r ref.Ref) (*url.URL, erro
|
||||
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
|
||||
query := url.Values{}
|
||||
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,
|
||||
}).Warn("Mount location header failed to parse")
|
||||
} else {
|
||||
return putURL, uuid, types.ErrMountReturnedLocation
|
||||
return putURL, uuid, errs.ErrMountReturnedLocation
|
||||
}
|
||||
}
|
||||
// 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))
|
||||
}
|
||||
|
||||
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
|
||||
if putURL.RawQuery != "" {
|
||||
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 {
|
||||
rdrSeek, ok := rdr.(io.ReadSeeker)
|
||||
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)
|
||||
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
|
||||
@ -445,7 +446,7 @@ func (reg *Reg) blobPutUploadFull(ctx context.Context, r ref.Ref, d types.Descri
|
||||
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)
|
||||
bufSize := host.BlobChunk
|
||||
if bufSize <= 0 {
|
||||
@ -534,7 +535,7 @@ func (reg *Reg) blobPutUploadChunked(ctx context.Context, r ref.Ref, d types.Des
|
||||
NoMirrors: true,
|
||||
}
|
||||
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)
|
||||
}
|
||||
err = resp.Close()
|
||||
@ -596,10 +597,10 @@ func (reg *Reg) blobPutUploadChunked(ctx context.Context, r ref.Ref, d types.Des
|
||||
// compute digest
|
||||
dOut := digester.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 {
|
||||
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.Size = chunkStart
|
||||
|
@ -19,7 +19,8 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/config"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -237,7 +238,7 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobGet: %v", err)
|
||||
}
|
||||
@ -256,7 +257,7 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobHead: %v", err)
|
||||
}
|
||||
@ -272,7 +273,7 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running external BlobGet: %v", err)
|
||||
}
|
||||
@ -291,7 +292,7 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running external BlobHead: %v", err)
|
||||
}
|
||||
@ -306,12 +307,12 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
defer br.Close()
|
||||
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)
|
||||
}
|
||||
})
|
||||
@ -321,7 +322,7 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobGet: %v", err)
|
||||
}
|
||||
@ -340,12 +341,12 @@ func TestBlobGet(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
defer br.Close()
|
||||
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)
|
||||
}
|
||||
})
|
||||
@ -1196,7 +1197,7 @@ func TestBlobPut(t *testing.T) {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobPut: %v", err)
|
||||
}
|
||||
@ -1215,7 +1216,7 @@ func TestBlobPut(t *testing.T) {
|
||||
}
|
||||
br := bytes.NewReader(blob2)
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobPut: %v", err)
|
||||
}
|
||||
@ -1236,12 +1237,12 @@ func TestBlobPut(t *testing.T) {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("Blob put succeeded on a gateway timeout")
|
||||
}
|
||||
if !errors.Is(err, types.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected err, expected %v, received %v", types.ErrHTTPStatus, err)
|
||||
if !errors.Is(err, errs.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected err, expected %v, received %v", errs.ErrHTTPStatus, err)
|
||||
}
|
||||
})
|
||||
|
||||
@ -1252,9 +1253,9 @@ func TestBlobPut(t *testing.T) {
|
||||
}
|
||||
br := bytes.NewReader(blob2)
|
||||
mt := "application/vnd.example.test"
|
||||
_, err = reg.BlobPut(ctx, r, types.Descriptor{MediaType: mt, Digest: d2Bad, Size: int64(len(blob2))}, br)
|
||||
if err == nil || !errors.Is(err, types.ErrDigestMismatch) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", types.ErrDigestMismatch, err)
|
||||
_, err = reg.BlobPut(ctx, r, descriptor.Descriptor{MediaType: mt, Digest: d2Bad, Size: int64(len(blob2))}, br)
|
||||
if err == nil || !errors.Is(err, errs.ErrDigestMismatch) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", errs.ErrDigestMismatch, err)
|
||||
}
|
||||
})
|
||||
|
||||
@ -1265,9 +1266,9 @@ func TestBlobPut(t *testing.T) {
|
||||
}
|
||||
br := bytes.NewReader(blob2)
|
||||
mt := "application/vnd.example.test"
|
||||
_, err = reg.BlobPut(ctx, r, types.Descriptor{MediaType: mt, Digest: d2, Size: int64(len(blob2) - 2)}, br)
|
||||
if err == nil || !errors.Is(err, types.ErrMismatch) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", types.ErrMismatch, err)
|
||||
_, err = reg.BlobPut(ctx, r, descriptor.Descriptor{MediaType: mt, Digest: d2, Size: int64(len(blob2) - 2)}, br)
|
||||
if err == nil || !errors.Is(err, errs.ErrMismatch) {
|
||||
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)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobPut: %v", err)
|
||||
}
|
||||
@ -1295,7 +1296,7 @@ func TestBlobPut(t *testing.T) {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobPut: %v", err)
|
||||
}
|
||||
@ -1314,7 +1315,7 @@ func TestBlobPut(t *testing.T) {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobPut: %v", err)
|
||||
}
|
||||
@ -1333,7 +1334,7 @@ func TestBlobPut(t *testing.T) {
|
||||
t.Fatalf("Failed creating ref: %v", err)
|
||||
}
|
||||
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 {
|
||||
t.Fatalf("Failed running BlobPut: %v", err)
|
||||
}
|
||||
|
@ -13,8 +13,9 @@ import (
|
||||
"github.com/regclient/regclient/internal/limitread"
|
||||
"github.com/regclient/regclient/internal/reghttp"
|
||||
"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/mediatype"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
@ -22,7 +23,7 @@ import (
|
||||
// This will implicitly delete all tags pointing to that manifest.
|
||||
func (reg *Reg) ManifestDelete(ctx context.Context, r ref.Ref, opts ...scheme.ManifestOpts) error {
|
||||
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{}
|
||||
@ -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 {
|
||||
// attempt to delete the referrer, but ignore if the referrer entry wasn't found
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -88,19 +89,19 @@ func (reg *Reg) ManifestGet(ctx context.Context, r ref.Ref) (manifest.Manifest,
|
||||
} else if r.Tag != "" {
|
||||
tagOrDigest = r.Tag
|
||||
} 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
|
||||
headers := http.Header{
|
||||
"Accept": []string{
|
||||
types.MediaTypeOCI1ManifestList,
|
||||
types.MediaTypeOCI1Manifest,
|
||||
types.MediaTypeDocker2ManifestList,
|
||||
types.MediaTypeDocker2Manifest,
|
||||
types.MediaTypeDocker1ManifestSigned,
|
||||
types.MediaTypeDocker1Manifest,
|
||||
types.MediaTypeOCI1Artifact,
|
||||
mediatype.OCI1ManifestList,
|
||||
mediatype.OCI1Manifest,
|
||||
mediatype.Docker2ManifestList,
|
||||
mediatype.Docker2Manifest,
|
||||
mediatype.Docker1ManifestSigned,
|
||||
mediatype.Docker1Manifest,
|
||||
mediatype.OCI1Artifact,
|
||||
},
|
||||
}
|
||||
req := ®http.Req{
|
||||
@ -126,7 +127,7 @@ func (reg *Reg) ManifestGet(ctx context.Context, r ref.Ref) (manifest.Manifest,
|
||||
// limit length
|
||||
size, _ := strconv.Atoi(resp.HTTPResponse().Header.Get("Content-Length"))
|
||||
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{
|
||||
Reader: resp,
|
||||
@ -165,19 +166,19 @@ func (reg *Reg) ManifestHead(ctx context.Context, r ref.Ref) (manifest.Manifest,
|
||||
} else if r.Tag != "" {
|
||||
tagOrDigest = r.Tag
|
||||
} 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
|
||||
headers := http.Header{
|
||||
"Accept": []string{
|
||||
types.MediaTypeOCI1ManifestList,
|
||||
types.MediaTypeOCI1Manifest,
|
||||
types.MediaTypeDocker2ManifestList,
|
||||
types.MediaTypeDocker2Manifest,
|
||||
types.MediaTypeDocker1ManifestSigned,
|
||||
types.MediaTypeDocker1Manifest,
|
||||
types.MediaTypeOCI1Artifact,
|
||||
mediatype.OCI1ManifestList,
|
||||
mediatype.OCI1Manifest,
|
||||
mediatype.Docker2ManifestList,
|
||||
mediatype.Docker2Manifest,
|
||||
mediatype.Docker1ManifestSigned,
|
||||
mediatype.Docker1Manifest,
|
||||
mediatype.OCI1Artifact,
|
||||
},
|
||||
}
|
||||
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{
|
||||
"ref": r.Reference,
|
||||
}).Warn("Manifest put requires a tag")
|
||||
return types.ErrMissingTag
|
||||
return errs.ErrMissingTag
|
||||
}
|
||||
|
||||
// create the request body
|
||||
@ -232,7 +233,7 @@ func (reg *Reg) ManifestPut(ctx context.Context, r ref.Ref, m manifest.Manifest,
|
||||
|
||||
// limit length
|
||||
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
|
||||
|
@ -18,9 +18,11 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/config"
|
||||
"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/errs"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
@ -37,14 +39,14 @@ func TestManifest(t *testing.T) {
|
||||
digest1 := digest.FromString("example1")
|
||||
digest2 := digest.FromString("example2")
|
||||
m := schema2.Manifest{
|
||||
Config: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2ImageConfig,
|
||||
Config: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2ImageConfig,
|
||||
Size: 8,
|
||||
Digest: digest1,
|
||||
},
|
||||
Layers: []types.Descriptor{
|
||||
Layers: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeDocker2LayerGzip,
|
||||
MediaType: mediatype.Docker2LayerGzip,
|
||||
Size: 8,
|
||||
Digest: digest2,
|
||||
},
|
||||
@ -68,7 +70,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -84,7 +86,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -100,7 +102,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
},
|
||||
@ -115,7 +117,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
},
|
||||
@ -130,7 +132,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -146,7 +148,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen+defaultManifestMaxPull)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -162,7 +164,7 @@ func TestManifest(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen+10)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -184,7 +186,7 @@ func TestManifest(t *testing.T) {
|
||||
Method: "PUT",
|
||||
Path: "/v2" + repoPath + "/manifests/" + putTag,
|
||||
Headers: http.Header{
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -254,7 +256,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mGet.GetDescriptor().Digest != mDigest {
|
||||
@ -270,7 +272,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mHead.GetDescriptor().Digest != mDigest {
|
||||
@ -285,8 +287,8 @@ func TestManifest(t *testing.T) {
|
||||
mNohead, err := reg.ManifestHead(ctx, noheadRef)
|
||||
if err == nil {
|
||||
t.Errorf("Unexpected successful head on \"no head\" registry: %v", mNohead)
|
||||
} else if !errors.Is(err, types.ErrUnsupportedAPI) {
|
||||
t.Errorf("Expected error, expected %v, received %v", types.ErrUnsupportedAPI, err)
|
||||
} else if !errors.Is(err, errs.ErrUnsupportedAPI) {
|
||||
t.Errorf("Expected error, expected %v, received %v", errs.ErrUnsupportedAPI, err)
|
||||
}
|
||||
})
|
||||
t.Run("Get No Head", func(t *testing.T) {
|
||||
@ -298,7 +300,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mNohead.GetDescriptor().Digest != mDigest {
|
||||
@ -324,7 +326,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mGet.GetDescriptor().Digest != mDigest {
|
||||
@ -340,7 +342,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mHead.GetDescriptor().Digest != mDigest {
|
||||
@ -356,7 +358,7 @@ func TestManifest(t *testing.T) {
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
if mGet.GetDescriptor().Digest != mDigest {
|
||||
@ -381,8 +383,8 @@ func TestManifest(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Fatalf("ManifestGet did not fail")
|
||||
}
|
||||
if !errors.Is(err, types.ErrSizeLimitExceeded) {
|
||||
t.Fatalf("unexpected error, expected %v, received %v", types.ErrSizeLimitExceeded, err)
|
||||
if !errors.Is(err, errs.ErrSizeLimitExceeded) {
|
||||
t.Fatalf("unexpected error, expected %v, received %v", errs.ErrSizeLimitExceeded, err)
|
||||
}
|
||||
})
|
||||
t.Run("Read beyond size", func(t *testing.T) {
|
||||
@ -394,8 +396,8 @@ func TestManifest(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Fatalf("ManifestGet did not fail")
|
||||
}
|
||||
if !errors.Is(err, types.ErrShortRead) && !errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
t.Fatalf("unexpected error, expected %v, received %v", types.ErrShortRead, err)
|
||||
if !errors.Is(err, errs.ErrShortRead) && !errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
t.Fatalf("unexpected error, expected %v, received %v", errs.ErrShortRead, err)
|
||||
}
|
||||
})
|
||||
|
||||
@ -431,8 +433,8 @@ func TestManifest(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Fatalf("put manifest did not fail")
|
||||
}
|
||||
if !errors.Is(err, types.ErrSizeLimitExceeded) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", types.ErrSizeLimitExceeded, err)
|
||||
if !errors.Is(err, errs.ErrSizeLimitExceeded) {
|
||||
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/internal/reqresp"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
@ -146,8 +146,8 @@ func TestPing(t *testing.T) {
|
||||
result, err := reg.Ping(ctx, r)
|
||||
if err == nil {
|
||||
t.Fatalf("ping did not fail")
|
||||
} else if !errors.Is(err, types.ErrHTTPUnauthorized) {
|
||||
t.Fatalf("unexpected error, expected %v, received %v", types.ErrHTTPUnauthorized, err)
|
||||
} else if !errors.Is(err, errs.ErrHTTPUnauthorized) {
|
||||
t.Fatalf("unexpected error, expected %v, received %v", errs.ErrHTTPUnauthorized, err)
|
||||
}
|
||||
if result.Header == nil {
|
||||
t.Errorf("headers missing")
|
||||
@ -163,8 +163,8 @@ func TestPing(t *testing.T) {
|
||||
result, err := reg.Ping(ctx, r)
|
||||
if err == nil {
|
||||
t.Fatalf("ping did not fail")
|
||||
} else if !errors.Is(err, types.ErrNotFound) {
|
||||
t.Fatalf("unexpected error, expected %v, received %v", types.ErrNotFound, err)
|
||||
} else if !errors.Is(err, errs.ErrNotFound) {
|
||||
t.Fatalf("unexpected error, expected %v, received %v", errs.ErrNotFound, err)
|
||||
}
|
||||
if result.Header == nil {
|
||||
t.Errorf("headers missing")
|
||||
|
@ -10,8 +10,9 @@ import (
|
||||
"github.com/regclient/regclient/internal/httplink"
|
||||
"github.com/regclient/regclient/internal/reghttp"
|
||||
"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/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"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)
|
||||
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.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)
|
||||
if err != nil {
|
||||
if errors.Is(err, types.ErrNotFound) {
|
||||
if errors.Is(err, errs.ErrNotFound) {
|
||||
// empty list, initialize a new manifest
|
||||
rl.Manifest, err = manifest.New(manifest.WithOrig(v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
}))
|
||||
if err != nil {
|
||||
return rl, err
|
||||
@ -253,7 +254,7 @@ func (reg *Reg) referrerDelete(ctx context.Context, r ref.Ref, m manifest.Manife
|
||||
// get subject field
|
||||
mSubject, ok := m.(manifest.Subjecter)
|
||||
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()
|
||||
if err != nil {
|
||||
@ -261,7 +262,7 @@ func (reg *Reg) referrerDelete(ctx context.Context, r ref.Ref, m manifest.Manife
|
||||
}
|
||||
// validate/set subject descriptor
|
||||
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
|
||||
@ -302,7 +303,7 @@ func (reg *Reg) referrerPut(ctx context.Context, r ref.Ref, m manifest.Manifest)
|
||||
// get subject field
|
||||
mSubject, ok := m.(manifest.Subjecter)
|
||||
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()
|
||||
if err != nil {
|
||||
@ -310,7 +311,7 @@ func (reg *Reg) referrerPut(ctx context.Context, r ref.Ref, m manifest.Manifest)
|
||||
}
|
||||
// validate/set subject descriptor
|
||||
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
|
||||
|
@ -17,9 +17,10 @@ import (
|
||||
"github.com/regclient/regclient/config"
|
||||
"github.com/regclient/regclient/internal/reqresp"
|
||||
"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/manifest"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -43,14 +44,14 @@ func TestReferrer(t *testing.T) {
|
||||
// manifest being referenced
|
||||
m := schema2.Manifest{
|
||||
Versioned: schema2.ManifestSchemaVersion,
|
||||
Config: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2ImageConfig,
|
||||
Config: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2ImageConfig,
|
||||
Size: 8,
|
||||
Digest: digest1,
|
||||
},
|
||||
Layers: []types.Descriptor{
|
||||
Layers: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeDocker2LayerGzip,
|
||||
MediaType: mediatype.Docker2LayerGzip,
|
||||
Size: 8,
|
||||
Digest: digest2,
|
||||
},
|
||||
@ -65,9 +66,9 @@ func TestReferrer(t *testing.T) {
|
||||
// manifest list
|
||||
mList := schema2.ManifestList{
|
||||
Versioned: schema2.ManifestListSchemaVersion,
|
||||
Manifests: []types.Descriptor{
|
||||
Manifests: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Digest: mDigest,
|
||||
Size: int64(mLen),
|
||||
Platform: &platform.Platform{
|
||||
@ -76,7 +77,7 @@ func TestReferrer(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Digest: digest.FromString("missing"),
|
||||
Size: int64(1234),
|
||||
Platform: &platform.Platform{
|
||||
@ -98,22 +99,22 @@ func TestReferrer(t *testing.T) {
|
||||
}
|
||||
artifact := v1.Manifest{
|
||||
Versioned: v1.ManifestSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
Config: types.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Config: descriptor.Descriptor{
|
||||
MediaType: configMTA,
|
||||
Size: 8,
|
||||
Digest: digest1,
|
||||
},
|
||||
Layers: []types.Descriptor{
|
||||
Layers: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1LayerGzip,
|
||||
MediaType: mediatype.OCI1LayerGzip,
|
||||
Size: 8,
|
||||
Digest: digest2,
|
||||
},
|
||||
},
|
||||
Annotations: artifactAnnot,
|
||||
Subject: &types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
Subject: &descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(mLen),
|
||||
Digest: mDigest,
|
||||
},
|
||||
@ -131,18 +132,18 @@ func TestReferrer(t *testing.T) {
|
||||
extraAnnot: extraValue2,
|
||||
}
|
||||
artifact2 := v1.ArtifactManifest{
|
||||
MediaType: types.MediaTypeOCI1Artifact,
|
||||
MediaType: mediatype.OCI1Artifact,
|
||||
ArtifactType: configMTB,
|
||||
Blobs: []types.Descriptor{
|
||||
Blobs: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1LayerGzip,
|
||||
MediaType: mediatype.OCI1LayerGzip,
|
||||
Size: 8,
|
||||
Digest: digest2,
|
||||
},
|
||||
},
|
||||
Annotations: artifact2Annot,
|
||||
Subject: &types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
Subject: &descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(mLen),
|
||||
Digest: mDigest,
|
||||
},
|
||||
@ -159,7 +160,7 @@ func TestReferrer(t *testing.T) {
|
||||
// empty response
|
||||
emptyReply := v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
}
|
||||
emptyBody, err := json.Marshal(emptyReply)
|
||||
if err != nil {
|
||||
@ -170,10 +171,10 @@ func TestReferrer(t *testing.T) {
|
||||
// a response
|
||||
replyA := v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
Manifests: []types.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Manifests: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
ArtifactType: configMTA,
|
||||
Size: int64(len(artifactBody)),
|
||||
Digest: artifactM.GetDescriptor().Digest,
|
||||
@ -190,10 +191,10 @@ func TestReferrer(t *testing.T) {
|
||||
// a response
|
||||
replyB := v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
Manifests: []types.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Manifests: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1Artifact,
|
||||
MediaType: mediatype.OCI1Artifact,
|
||||
ArtifactType: configMTB,
|
||||
Size: int64(len(artifact2Body)),
|
||||
Digest: artifact2M.GetDescriptor().Digest,
|
||||
@ -210,17 +211,17 @@ func TestReferrer(t *testing.T) {
|
||||
// full response
|
||||
replyBoth := v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
Manifests: []types.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Manifests: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
ArtifactType: configMTA,
|
||||
Size: int64(len(artifactBody)),
|
||||
Digest: artifactM.GetDescriptor().Digest,
|
||||
Annotations: artifactAnnot,
|
||||
},
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1Artifact,
|
||||
MediaType: mediatype.OCI1Artifact,
|
||||
ArtifactType: configMTB,
|
||||
Size: int64(len(artifact2Body)),
|
||||
Digest: artifact2M.GetDescriptor().Digest,
|
||||
@ -249,7 +250,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
},
|
||||
@ -264,7 +265,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": []string{mDigest.String()},
|
||||
},
|
||||
Body: mBody,
|
||||
@ -280,7 +281,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mlLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2ManifestList},
|
||||
"Content-Type": []string{mediatype.Docker2ManifestList},
|
||||
"Docker-Content-Digest": []string{mlDigest.String()},
|
||||
},
|
||||
},
|
||||
@ -295,7 +296,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", mlLen)},
|
||||
"Content-Type": []string{types.MediaTypeDocker2ManifestList},
|
||||
"Content-Type": []string{mediatype.Docker2ManifestList},
|
||||
"Docker-Content-Digest": []string{mlDigest.String()},
|
||||
},
|
||||
Body: mlBody,
|
||||
@ -312,7 +313,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", len(artifactBody))},
|
||||
"Content-Type": []string{types.MediaTypeOCI1Manifest},
|
||||
"Content-Type": []string{mediatype.OCI1Manifest},
|
||||
"Docker-Content-Digest": []string{string(artifactDigest)},
|
||||
},
|
||||
Body: artifactBody,
|
||||
@ -329,7 +330,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", len(artifact2Body))},
|
||||
"Content-Type": []string{types.MediaTypeOCI1Artifact},
|
||||
"Content-Type": []string{mediatype.OCI1Artifact},
|
||||
"Docker-Content-Digest": []string{string(artifact2Digest)},
|
||||
},
|
||||
Body: artifact2Body,
|
||||
@ -420,7 +421,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", replyALen)},
|
||||
"Content-Type": []string{types.MediaTypeOCI1ManifestList},
|
||||
"Content-Type": []string{mediatype.OCI1ManifestList},
|
||||
"Docker-Content-Digest": []string{replyADig.String()},
|
||||
},
|
||||
Body: replyABody,
|
||||
@ -437,7 +438,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", replyBothLen)},
|
||||
"Content-Type": []string{types.MediaTypeOCI1ManifestList},
|
||||
"Content-Type": []string{mediatype.OCI1ManifestList},
|
||||
"Docker-Content-Digest": []string{replyBothDig.String()},
|
||||
},
|
||||
Body: replyBothBody,
|
||||
@ -528,7 +529,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", replyALen)},
|
||||
"Content-Type": []string{types.MediaTypeOCI1ManifestList},
|
||||
"Content-Type": []string{mediatype.OCI1ManifestList},
|
||||
"Docker-Content-Digest": []string{replyADig.String()},
|
||||
},
|
||||
Body: replyABody,
|
||||
@ -545,7 +546,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", replyBothLen)},
|
||||
"Content-Type": []string{types.MediaTypeOCI1ManifestList},
|
||||
"Content-Type": []string{mediatype.OCI1ManifestList},
|
||||
"Docker-Content-Digest": []string{replyBothDig.String()},
|
||||
},
|
||||
Body: replyBothBody,
|
||||
@ -646,7 +647,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", emptyLen)},
|
||||
"Content-Type": []string{types.MediaTypeOCI1ManifestList},
|
||||
"Content-Type": []string{mediatype.OCI1ManifestList},
|
||||
"Docker-Content-Digest": []string{emptyDigest.String()},
|
||||
},
|
||||
Body: emptyBody,
|
||||
@ -663,7 +664,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", replyALen)},
|
||||
"Content-Type": []string{types.MediaTypeOCI1ManifestList},
|
||||
"Content-Type": []string{mediatype.OCI1ManifestList},
|
||||
"Docker-Content-Digest": []string{replyADig.String()},
|
||||
},
|
||||
Body: replyABody,
|
||||
@ -683,7 +684,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", replyBLen)},
|
||||
"Content-Type": []string{types.MediaTypeOCI1ManifestList},
|
||||
"Content-Type": []string{mediatype.OCI1ManifestList},
|
||||
"Docker-Content-Digest": []string{replyBDig.String()},
|
||||
},
|
||||
Body: replyBBody,
|
||||
@ -700,7 +701,7 @@ func TestReferrer(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", replyALen)},
|
||||
"Content-Type": []string{types.MediaTypeOCI1ManifestList},
|
||||
"Content-Type": []string{mediatype.OCI1ManifestList},
|
||||
"Docker-Content-Digest": []string{replyADig.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 {
|
||||
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].Digest != artifactM.GetDescriptor().Digest ||
|
||||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
|
||||
@ -870,7 +871,7 @@ func TestReferrer(t *testing.T) {
|
||||
if len(rl.Descriptors) < 1 {
|
||||
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].Digest != artifactM.GetDescriptor().Digest ||
|
||||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
|
||||
@ -892,7 +893,7 @@ func TestReferrer(t *testing.T) {
|
||||
if len(rl.Descriptors) < 1 {
|
||||
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].Digest != artifactM.GetDescriptor().Digest ||
|
||||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
|
||||
@ -938,14 +939,14 @@ func TestReferrer(t *testing.T) {
|
||||
if len(rl.Descriptors) != 2 {
|
||||
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].Digest != artifactM.GetDescriptor().Digest ||
|
||||
rl.Descriptors[0].ArtifactType != configMTA ||
|
||||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
|
||||
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].Digest != artifact2M.GetDescriptor().Digest ||
|
||||
rl.Descriptors[1].ArtifactType != configMTB ||
|
||||
@ -968,14 +969,14 @@ func TestReferrer(t *testing.T) {
|
||||
if len(rl.Descriptors) != 2 {
|
||||
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].Digest != artifactM.GetDescriptor().Digest ||
|
||||
rl.Descriptors[0].ArtifactType != configMTA ||
|
||||
!mapStringStringEq(rl.Descriptors[0].Annotations, artifactAnnot) {
|
||||
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].Digest != artifact2M.GetDescriptor().Digest ||
|
||||
rl.Descriptors[1].ArtifactType != configMTB ||
|
||||
@ -992,14 +993,14 @@ func TestReferrer(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
if len(rl.Descriptors) != 1 {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
@ -1012,21 +1013,21 @@ func TestReferrer(t *testing.T) {
|
||||
if err != nil {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
if len(rl.Descriptors) != 1 {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
if len(rl.Descriptors) > 0 {
|
||||
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 {
|
||||
t.Fatalf("Failed running ReferrerList: %v", err)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/internal/reghttp"
|
||||
"github.com/regclient/regclient/scheme"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
"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")
|
||||
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(
|
||||
repo.WithMT(mt),
|
||||
repo.WithRaw(respBody),
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
"github.com/regclient/regclient/config"
|
||||
"github.com/regclient/regclient/internal/reqresp"
|
||||
"github.com/regclient/regclient/scheme"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
)
|
||||
|
||||
func TestRepo(t *testing.T) {
|
||||
@ -227,8 +227,8 @@ func TestRepo(t *testing.T) {
|
||||
_, err := reg.RepoList(ctx, host)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected success listing repos on disabled registry")
|
||||
} else if !errors.Is(err, types.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected error: expected %v, received %v", types.ErrHTTPStatus, err)
|
||||
} else if !errors.Is(err, errs.ErrHTTPStatus) {
|
||||
t.Errorf("unexpected error: expected %v, received %v", errs.ErrHTTPStatus, err)
|
||||
}
|
||||
})
|
||||
// test with unknown media-type header
|
||||
@ -238,8 +238,8 @@ func TestRepo(t *testing.T) {
|
||||
_, err := reg.RepoList(ctx, host)
|
||||
if err == nil {
|
||||
t.Errorf("unexpected success listing repos on unknown-mt registry")
|
||||
} else if !errors.Is(err, types.ErrUnsupportedMediaType) {
|
||||
t.Errorf("unexpected error: expected %v, received %v", types.ErrUnsupportedMediaType, err)
|
||||
} else if !errors.Is(err, errs.ErrUnsupportedMediaType) {
|
||||
t.Errorf("unexpected error: expected %v, received %v", errs.ErrUnsupportedMediaType, err)
|
||||
}
|
||||
})
|
||||
// test with parsing errors
|
||||
|
@ -22,9 +22,11 @@ import (
|
||||
"github.com/regclient/regclient/internal/httplink"
|
||||
"github.com/regclient/regclient/internal/reghttp"
|
||||
"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/errs"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -37,7 +39,7 @@ import (
|
||||
func (reg *Reg) TagDelete(ctx context.Context, r ref.Ref) error {
|
||||
var tempManifest manifest.Manifest
|
||||
if r.Tag == "" {
|
||||
return types.ErrMissingTag
|
||||
return errs.ErrMissingTag
|
||||
}
|
||||
|
||||
// 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
|
||||
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)
|
||||
}
|
||||
if err != nil {
|
||||
@ -102,7 +104,7 @@ func (reg *Reg) TagDelete(ctx context.Context, r ref.Ref) error {
|
||||
RootFS: v1.RootFS{
|
||||
Type: "layers",
|
||||
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
|
||||
switch manifest.GetMediaType(curManifest) {
|
||||
case types.MediaTypeOCI1Manifest, types.MediaTypeOCI1ManifestList:
|
||||
case mediatype.OCI1Manifest, mediatype.OCI1ManifestList:
|
||||
tempManifest, err = manifest.New(manifest.WithOrig(v1.Manifest{
|
||||
Versioned: v1.ManifestSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
Config: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ImageConfig,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Config: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ImageConfig,
|
||||
Digest: confDigest,
|
||||
Size: int64(len(confB)),
|
||||
},
|
||||
Layers: []types.Descriptor{
|
||||
Layers: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeOCI1Layer,
|
||||
Size: int64(len(types.EmptyData)),
|
||||
Digest: types.EmptyDigest,
|
||||
MediaType: mediatype.OCI1Layer,
|
||||
Size: int64(len(descriptor.EmptyData)),
|
||||
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
|
||||
tempManifest, err = manifest.New(manifest.WithOrig(schema2.Manifest{
|
||||
Versioned: schema2.ManifestSchemaVersion,
|
||||
Config: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2ImageConfig,
|
||||
Config: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2ImageConfig,
|
||||
Digest: confDigest,
|
||||
Size: int64(len(confB)),
|
||||
},
|
||||
Layers: []types.Descriptor{
|
||||
Layers: []descriptor.Descriptor{
|
||||
{
|
||||
MediaType: types.MediaTypeDocker2LayerGzip,
|
||||
Size: int64(len(types.EmptyData)),
|
||||
Digest: types.EmptyDigest,
|
||||
MediaType: mediatype.Docker2LayerGzip,
|
||||
Size: int64(len(descriptor.EmptyData)),
|
||||
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")
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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/internal/reqresp"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -188,7 +189,7 @@ func TestTag(t *testing.T) {
|
||||
Status: http.StatusOK,
|
||||
Headers: http.Header{
|
||||
"Content-Length": {fmt.Sprintf("%d", len(delFallbackManifest))},
|
||||
"Content-Type": {types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": {mediatype.Docker2Manifest},
|
||||
"Docker-Content-Digest": {delFallbackDigest.String()},
|
||||
},
|
||||
},
|
||||
@ -229,7 +230,7 @@ func TestTag(t *testing.T) {
|
||||
Method: "PUT",
|
||||
Path: "/v2" + repoPath + "/manifests/" + delFallbackTag,
|
||||
Headers: http.Header{
|
||||
"Content-Type": {types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": {mediatype.Docker2Manifest},
|
||||
},
|
||||
},
|
||||
RespEntry: reqresp.RespEntry{
|
||||
@ -347,8 +348,8 @@ func TestTag(t *testing.T) {
|
||||
_, err = reg.TagList(ctx, listRef)
|
||||
if err == nil {
|
||||
t.Fatalf("tag listing succeeded on missing repo")
|
||||
} else if !errors.Is(err, types.ErrNotFound) {
|
||||
t.Fatalf("unexpected error: expected %v, received %v", types.ErrNotFound, err)
|
||||
} else if !errors.Is(err, errs.ErrNotFound) {
|
||||
t.Fatalf("unexpected error: expected %v, received %v", errs.ErrNotFound, err)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/regclient/regclient/internal/throttle"
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/blob"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/manifest"
|
||||
"github.com/regclient/regclient/types/ping"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -18,15 +18,15 @@ import (
|
||||
// API is used to interface between different methods to store images.
|
||||
type API interface {
|
||||
// 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(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(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(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(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(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].
|
||||
type ReferrerConfig struct {
|
||||
MatchOpt types.MatchOpt // filter/sort results
|
||||
Platform string // get referrers for a specific platform
|
||||
MatchOpt descriptor.MatchOpt // filter/sort results
|
||||
Platform string // get referrers for a specific platform
|
||||
}
|
||||
|
||||
// ReferrerOpts is used to set options on referrer APIs.
|
||||
type ReferrerOpts func(*ReferrerConfig)
|
||||
|
||||
// WithReferrerMatchOpt filters results using [types.MatchOpt].
|
||||
func WithReferrerMatchOpt(mo types.MatchOpt) ReferrerOpts {
|
||||
// WithReferrerMatchOpt filters results using [descriptor.MatchOpt].
|
||||
func WithReferrerMatchOpt(mo descriptor.MatchOpt) ReferrerOpts {
|
||||
return func(config *ReferrerConfig) {
|
||||
config.MatchOpt = mo
|
||||
}
|
||||
@ -167,7 +167,7 @@ func ReferrerFilter(config ReferrerConfig, rlIn referrer.ReferrerList) referrer.
|
||||
Manifest: rlIn.Manifest,
|
||||
Annotations: rlIn.Annotations,
|
||||
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"
|
||||
|
||||
"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/tag"
|
||||
)
|
||||
@ -18,7 +18,7 @@ import (
|
||||
// 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 {
|
||||
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)
|
||||
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
|
||||
func (rc *RegClient) TagList(ctx context.Context, r ref.Ref, opts ...scheme.TagOpts) (*tag.List, error) {
|
||||
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)
|
||||
if err != nil {
|
||||
|
@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
@ -15,7 +15,7 @@ import (
|
||||
// Blob interface is used for returning blobs.
|
||||
type Blob interface {
|
||||
// GetDescriptor returns the descriptor associated with the blob.
|
||||
GetDescriptor() types.Descriptor
|
||||
GetDescriptor() descriptor.Descriptor
|
||||
// RawBody returns the raw content of the blob.
|
||||
RawBody() ([]byte, error)
|
||||
// RawHeaders returns the headers received from the registry.
|
||||
@ -38,7 +38,7 @@ type Blob interface {
|
||||
}
|
||||
|
||||
type blobConfig struct {
|
||||
desc types.Descriptor
|
||||
desc descriptor.Descriptor
|
||||
header http.Header
|
||||
image *v1.Image
|
||||
r ref.Ref
|
||||
@ -51,7 +51,7 @@ type blobConfig struct {
|
||||
type Opts func(*blobConfig)
|
||||
|
||||
// WithDesc specifies the descriptor associated with the blob.
|
||||
func WithDesc(d types.Descriptor) Opts {
|
||||
func WithDesc(d descriptor.Descriptor) Opts {
|
||||
return func(bc *blobConfig) {
|
||||
bc.desc = d
|
||||
}
|
||||
|
@ -12,7 +12,9 @@ import (
|
||||
|
||||
"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"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
@ -53,19 +55,19 @@ var (
|
||||
`)
|
||||
exLen = int64(len(exBlob))
|
||||
exDigest = digest.FromBytes(exBlob)
|
||||
exMT = types.MediaTypeDocker2ImageConfig
|
||||
exMT = mediatype.Docker2ImageConfig
|
||||
exHeaders = http.Header{
|
||||
"Content-Type": {types.MediaTypeDocker2ImageConfig},
|
||||
"Content-Type": {mediatype.Docker2ImageConfig},
|
||||
"Content-Length": {fmt.Sprintf("%d", exLen)},
|
||||
"Docker-Content-Digest": {exDigest.String()},
|
||||
}
|
||||
exHeadersShort = http.Header{
|
||||
"Content-Type": {types.MediaTypeDocker2ImageConfig},
|
||||
"Content-Type": {mediatype.Docker2ImageConfig},
|
||||
"Content-Length": {fmt.Sprintf("%d", exLen-5)},
|
||||
"Docker-Content-Digest": {exDigest.String()},
|
||||
}
|
||||
exHeadersLong = http.Header{
|
||||
"Content-Type": {types.MediaTypeDocker2ImageConfig},
|
||||
"Content-Type": {mediatype.Docker2ImageConfig},
|
||||
"Content-Length": {fmt.Sprintf("%d", exLen+5)},
|
||||
"Docker-Content-Digest": {exDigest.String()},
|
||||
}
|
||||
@ -76,7 +78,7 @@ var (
|
||||
ContentLength: exLen,
|
||||
Body: io.NopCloser(bytes.NewReader(exBlob)),
|
||||
}
|
||||
exDesc = types.Descriptor{
|
||||
exDesc = descriptor.Descriptor{
|
||||
MediaType: exMT,
|
||||
Digest: exDigest,
|
||||
Size: exLen,
|
||||
@ -111,7 +113,7 @@ func TestCommon(t *testing.T) {
|
||||
name: "descriptor",
|
||||
opts: []Opts{
|
||||
WithReader(bytes.NewReader(exBlob)),
|
||||
WithDesc(types.Descriptor{
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: exMT,
|
||||
Digest: exDigest,
|
||||
Size: exLen,
|
||||
@ -160,7 +162,7 @@ func TestCommon(t *testing.T) {
|
||||
eHeaders: exHeadersShort,
|
||||
eLen: exLen,
|
||||
eMT: exMT,
|
||||
eErr: types.ErrSizeLimitExceeded,
|
||||
eErr: errs.ErrSizeLimitExceeded,
|
||||
},
|
||||
{
|
||||
name: "short read",
|
||||
@ -174,7 +176,7 @@ func TestCommon(t *testing.T) {
|
||||
eHeaders: exHeadersLong,
|
||||
eLen: exLen,
|
||||
eMT: exMT,
|
||||
eErr: types.ErrShortRead,
|
||||
eErr: errs.ErrShortRead,
|
||||
},
|
||||
}
|
||||
for _, tc := range tt {
|
||||
@ -296,8 +298,8 @@ func TestReader(t *testing.T) {
|
||||
if err == nil {
|
||||
t.Fatalf("readall did not fail")
|
||||
}
|
||||
if !errors.Is(err, types.ErrSizeLimitExceeded) {
|
||||
t.Errorf("unexpected error on readall, expected %v, received %v", types.ErrSizeLimitExceeded, err)
|
||||
if !errors.Is(err, errs.ErrSizeLimitExceeded) {
|
||||
t.Errorf("unexpected error on readall, expected %v, received %v", errs.ErrSizeLimitExceeded, err)
|
||||
}
|
||||
})
|
||||
|
||||
@ -305,7 +307,7 @@ func TestReader(t *testing.T) {
|
||||
// create blob
|
||||
b := NewReader(
|
||||
WithReader(bytes.NewReader(exBlob)),
|
||||
WithDesc(types.Descriptor{
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: exMT,
|
||||
Digest: exDigest,
|
||||
Size: exLen,
|
||||
@ -357,7 +359,7 @@ func TestOCI(t *testing.T) {
|
||||
fromJSON []byte
|
||||
wantRaw []byte
|
||||
wantJSON []byte
|
||||
wantDesc types.Descriptor
|
||||
wantDesc descriptor.Descriptor
|
||||
}{
|
||||
{
|
||||
name: "RawBody",
|
||||
@ -383,7 +385,7 @@ func TestOCI(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithImage(ociConfig),
|
||||
},
|
||||
wantDesc: types.Descriptor{MediaType: types.MediaTypeOCI1ImageConfig},
|
||||
wantDesc: descriptor.Descriptor{MediaType: mediatype.OCI1ImageConfig},
|
||||
},
|
||||
{
|
||||
name: "Config with Docker Desc",
|
||||
@ -391,7 +393,7 @@ func TestOCI(t *testing.T) {
|
||||
WithImage(ociConfig),
|
||||
WithDesc(exDesc),
|
||||
},
|
||||
wantDesc: types.Descriptor{MediaType: exMT},
|
||||
wantDesc: descriptor.Descriptor{MediaType: exMT},
|
||||
},
|
||||
}
|
||||
|
||||
@ -440,7 +442,7 @@ func TestOCI(t *testing.T) {
|
||||
// create blob
|
||||
oc := NewOCIConfig(
|
||||
WithRawBody(exBlob),
|
||||
WithDesc(types.Descriptor{
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: exMT,
|
||||
Digest: exDigest,
|
||||
Size: exLen,
|
||||
@ -493,8 +495,8 @@ func TestTarReader(t *testing.T) {
|
||||
{
|
||||
name: "good desc",
|
||||
opts: []Opts{
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Layer,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Layer,
|
||||
Size: fhSize,
|
||||
Digest: dig,
|
||||
}),
|
||||
@ -503,8 +505,8 @@ func TestTarReader(t *testing.T) {
|
||||
{
|
||||
name: "bad desc",
|
||||
opts: []Opts{
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Layer,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Layer,
|
||||
Size: fhSize,
|
||||
Digest: digest.FromString("bad digest"),
|
||||
}),
|
||||
@ -573,7 +575,7 @@ func TestReadFile(t *testing.T) {
|
||||
{
|
||||
name: "layer2",
|
||||
filename: "layer2.txt",
|
||||
expectErr: types.ErrFileDeleted,
|
||||
expectErr: errs.ErrFileDeleted,
|
||||
},
|
||||
{
|
||||
name: "layer3",
|
||||
@ -583,12 +585,12 @@ func TestReadFile(t *testing.T) {
|
||||
{
|
||||
name: "opaque dir",
|
||||
filename: "exdir/test.txt",
|
||||
expectErr: types.ErrFileDeleted,
|
||||
expectErr: errs.ErrFileDeleted,
|
||||
},
|
||||
{
|
||||
name: "missing",
|
||||
filename: "missing.txt",
|
||||
expectErr: types.ErrFileNotFound,
|
||||
expectErr: errs.ErrFileNotFound,
|
||||
},
|
||||
{
|
||||
name: "invalid",
|
||||
@ -607,7 +609,7 @@ func TestReadFile(t *testing.T) {
|
||||
if err != nil {
|
||||
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()
|
||||
th, rdr, err := btr.ReadFile(tc.filename)
|
||||
if tc.expectErr != nil {
|
||||
@ -649,12 +651,12 @@ func TestReadFile(t *testing.T) {
|
||||
if err != nil {
|
||||
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")
|
||||
if err == nil {
|
||||
t.Errorf("ReadFile did not fail")
|
||||
} else if !errors.Is(err, types.ErrDigestMismatch) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", types.ErrDigestMismatch, err)
|
||||
} else if !errors.Is(err, errs.ErrDigestMismatch) {
|
||||
t.Errorf("unexpected error, expected %v, received %v", errs.ErrDigestMismatch, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"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.
|
||||
type BCommon struct {
|
||||
r ref.Ref
|
||||
desc types.Descriptor
|
||||
desc descriptor.Descriptor
|
||||
blobSet bool
|
||||
rawHeader http.Header
|
||||
resp *http.Response
|
||||
}
|
||||
|
||||
// GetDescriptor returns the descriptor associated with the blob.
|
||||
func (c *BCommon) GetDescriptor() types.Descriptor {
|
||||
func (c *BCommon) GetDescriptor() descriptor.Descriptor {
|
||||
return c.desc
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
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.Size = int64(len(bc.rawBody))
|
||||
if bc.desc.MediaType == "" {
|
||||
bc.desc.MediaType = types.MediaTypeOCI1ImageConfig
|
||||
bc.desc.MediaType = mediatype.OCI1ImageConfig
|
||||
}
|
||||
}
|
||||
b := BOCIConfig{
|
||||
@ -91,7 +91,7 @@ func (oc *BOCIConfig) SetConfig(image v1.Image) {
|
||||
oc.image = image
|
||||
oc.rawBody, _ = json.Marshal(oc.image)
|
||||
if oc.desc.MediaType == "" {
|
||||
oc.desc.MediaType = types.MediaTypeOCI1ImageConfig
|
||||
oc.desc.MediaType = mediatype.OCI1ImageConfig
|
||||
}
|
||||
oc.desc.Digest = digest.FromBytes(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))
|
||||
copy(oc.rawBody, data)
|
||||
if oc.desc.MediaType == "" {
|
||||
oc.desc.MediaType = types.MediaTypeOCI1ImageConfig
|
||||
oc.desc.MediaType = mediatype.OCI1ImageConfig
|
||||
}
|
||||
oc.desc.Digest = digest.FromBytes(oc.rawBody)
|
||||
oc.desc.Size = int64(len(oc.rawBody))
|
||||
|
@ -12,7 +12,8 @@ import (
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
"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.
|
||||
@ -45,7 +46,7 @@ func NewReader(opts ...Opts) *BReader {
|
||||
if bc.header != nil {
|
||||
// extract fields from header if descriptor not passed
|
||||
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 {
|
||||
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 {
|
||||
r.desc.Size = r.readBytes
|
||||
} 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 {
|
||||
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
|
||||
if r.desc.Digest == "" {
|
||||
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
|
||||
|
@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/regclient/regclient/internal/limitread"
|
||||
"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.
|
||||
@ -98,7 +98,7 @@ func (tr *BTarReader) RawBody() ([]byte, error) {
|
||||
dig := tr.digester.Digest()
|
||||
tr.digester = nil
|
||||
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
|
||||
}
|
||||
@ -150,18 +150,18 @@ func (tr *BTarReader) ReadFile(filename string) (*tar.Header, io.Reader, error)
|
||||
}
|
||||
// EOF encountered
|
||||
if whiteout {
|
||||
return nil, nil, types.ErrFileDeleted
|
||||
return nil, nil, errs.ErrFileDeleted
|
||||
}
|
||||
if tr.digester != nil {
|
||||
_, _ = io.Copy(io.Discard, tr.reader) // process/digest any trailing bytes from reader
|
||||
dig := tr.digester.Digest()
|
||||
tr.digester = nil
|
||||
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
|
||||
}
|
||||
return nil, nil, types.ErrFileNotFound
|
||||
return nil, nil, errs.ErrFileNotFound
|
||||
}
|
||||
|
||||
func tarCmpWhiteout(whFile, tgtFile string) bool {
|
||||
|
@ -1,272 +1,27 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
import "github.com/regclient/regclient/types/descriptor"
|
||||
|
||||
// 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/platform"
|
||||
type (
|
||||
// Descriptor is used in manifests to refer to content by media type, size, and digest.
|
||||
//
|
||||
// Deprecated: replace with [descriptor.Descriptor].
|
||||
Descriptor = descriptor.Descriptor
|
||||
// MatchOpt defines conditions for a match descriptor.
|
||||
//
|
||||
// Deprecated: replace with [descriptor.MatchOpt].
|
||||
MatchOpt = descriptor.MatchOpt
|
||||
)
|
||||
|
||||
// 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 = []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
|
||||
}
|
||||
var (
|
||||
// EmptyData is the content of the empty JSON descriptor. See [mediatype.OCI1Empty].
|
||||
//
|
||||
// Deprecated: replace with [descriptor.EmptyData].
|
||||
EmptyData = descriptor.EmptyData
|
||||
// EmptyDigest is the digest of the empty JSON descriptor. See [mediatype.OCI1Empty].
|
||||
//
|
||||
// Deprecated: replace with [descriptor.EmptyDigest].
|
||||
EmptyDigest = descriptor.EmptyDigest
|
||||
DescriptorListFilter = descriptor.DescriptorListFilter
|
||||
DescriptorListSearch = descriptor.DescriptorListSearch
|
||||
)
|
||||
|
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 (
|
||||
"bytes"
|
||||
@ -9,6 +9,8 @@ import (
|
||||
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
)
|
||||
|
||||
@ -23,36 +25,36 @@ func TestDescriptorData(t *testing.T) {
|
||||
{
|
||||
name: "No Data",
|
||||
d: Descriptor{
|
||||
MediaType: MediaTypeDocker2LayerGzip,
|
||||
MediaType: mediatype.Docker2LayerGzip,
|
||||
Size: 941,
|
||||
Digest: digest.Digest("sha256:f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14"),
|
||||
},
|
||||
wantErr: ErrParsingFailed,
|
||||
wantErr: errs.ErrParsingFailed,
|
||||
},
|
||||
{
|
||||
name: "Bad Digest",
|
||||
d: Descriptor{
|
||||
MediaType: MediaTypeOCI1LayerGzip,
|
||||
MediaType: mediatype.OCI1LayerGzip,
|
||||
Size: 10,
|
||||
Digest: digest.Digest("sha256:e4a380728755139f156563e8b795581d5915dcc947fe937c524c6d52fd604b99"),
|
||||
Data: []byte("example data"),
|
||||
},
|
||||
wantErr: ErrParsingFailed,
|
||||
wantErr: errs.ErrParsingFailed,
|
||||
},
|
||||
{
|
||||
name: "Bad Size",
|
||||
d: Descriptor{
|
||||
MediaType: MediaTypeOCI1LayerGzip,
|
||||
MediaType: mediatype.OCI1LayerGzip,
|
||||
Size: 1000,
|
||||
Digest: digest.Digest("sha256:44752f37272e944fd2c913a35342eaccdd1aaf189bae50676b301ab213fc5061"),
|
||||
Data: []byte("example data"),
|
||||
},
|
||||
wantErr: ErrParsingFailed,
|
||||
wantErr: errs.ErrParsingFailed,
|
||||
},
|
||||
{
|
||||
name: "Good data",
|
||||
d: Descriptor{
|
||||
MediaType: MediaTypeOCI1LayerGzip,
|
||||
MediaType: mediatype.OCI1LayerGzip,
|
||||
Size: 12,
|
||||
Digest: digest.Digest("sha256:44752f37272e944fd2c913a35342eaccdd1aaf189bae50676b301ab213fc5061"),
|
||||
Data: []byte("example data"),
|
||||
@ -98,7 +100,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "empty d1",
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -108,7 +110,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "empty d2",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -118,12 +120,12 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "same simple manifest",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -133,12 +135,12 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "converting OCI media type",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -148,12 +150,12 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "different media type",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2ManifestList,
|
||||
MediaType: mediatype.Docker2ManifestList,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -163,12 +165,12 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "different size",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 4321,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -178,12 +180,12 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "different digest",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digB,
|
||||
},
|
||||
@ -193,7 +195,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "annotation eq",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Annotations: map[string]string{
|
||||
@ -202,7 +204,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
},
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Annotations: map[string]string{
|
||||
@ -216,7 +218,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "annotation diff",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Annotations: map[string]string{
|
||||
@ -225,7 +227,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
},
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Annotations: map[string]string{
|
||||
@ -239,7 +241,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "annotation missing",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Annotations: map[string]string{
|
||||
@ -248,7 +250,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
},
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -258,7 +260,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "urls eq",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
URLs: []string{
|
||||
@ -267,7 +269,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
},
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
URLs: []string{
|
||||
@ -281,7 +283,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "urls diff",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
URLs: []string{
|
||||
@ -290,7 +292,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
},
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
URLs: []string{
|
||||
@ -304,7 +306,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "urls missing",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
URLs: []string{
|
||||
@ -313,7 +315,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
},
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -323,7 +325,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "platform eq",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Platform: &platform.Platform{
|
||||
@ -332,7 +334,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
},
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Platform: &platform.Platform{
|
||||
@ -346,7 +348,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "platform diff",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Platform: &platform.Platform{
|
||||
@ -355,7 +357,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
},
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Platform: &platform.Platform{
|
||||
@ -369,7 +371,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "platform missing",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
Platform: &platform.Platform{
|
||||
@ -378,7 +380,7 @@ func TestDescriptorEq(t *testing.T) {
|
||||
},
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -388,13 +390,13 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "artifactType eq",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
ArtifactType: "application/vnd.example.test",
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
ArtifactType: "application/vnd.example.test",
|
||||
@ -405,13 +407,13 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "artifactType diff",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
ArtifactType: "application/vnd.example.test",
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
ArtifactType: "application/vnd.example.test2",
|
||||
@ -422,13 +424,13 @@ func TestDescriptorEq(t *testing.T) {
|
||||
{
|
||||
name: "artifactType missing",
|
||||
d1: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
ArtifactType: "application/vnd.example.test",
|
||||
},
|
||||
d2: Descriptor{
|
||||
MediaType: MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: 1234,
|
||||
Digest: digA,
|
||||
},
|
||||
@ -463,7 +465,7 @@ func TestDataJSON(t *testing.T) {
|
||||
"digest": "sha256:f6e2d7fa40092cf3d9817bf6ff54183d68d108a47fdf5a5e476c612626c80e14",
|
||||
"size": 941
|
||||
}`),
|
||||
wantErr: ErrParsingFailed,
|
||||
wantErr: errs.ErrParsingFailed,
|
||||
},
|
||||
{
|
||||
name: "Bad Data",
|
||||
@ -483,7 +485,7 @@ func TestDataJSON(t *testing.T) {
|
||||
"size": 10,
|
||||
"data": "ZXhhbXBsZSBkYXRh"
|
||||
}`),
|
||||
wantErr: ErrParsingFailed,
|
||||
wantErr: errs.ErrParsingFailed,
|
||||
},
|
||||
{
|
||||
name: "Bad Size",
|
||||
@ -493,7 +495,7 @@ func TestDataJSON(t *testing.T) {
|
||||
"size": 1000,
|
||||
"data": "ZXhhbXBsZSBkYXRh"
|
||||
}`),
|
||||
wantErr: ErrParsingFailed,
|
||||
wantErr: errs.ErrParsingFailed,
|
||||
},
|
||||
{
|
||||
name: "Good data",
|
||||
@ -538,7 +540,7 @@ func TestDataJSON(t *testing.T) {
|
||||
func TestDescriptorSearch(t *testing.T) {
|
||||
t.Parallel()
|
||||
dAMD64 := Descriptor{
|
||||
MediaType: MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 12345,
|
||||
Digest: EmptyDigest,
|
||||
Platform: &platform.Platform{
|
||||
@ -547,7 +549,7 @@ func TestDescriptorSearch(t *testing.T) {
|
||||
},
|
||||
}
|
||||
dAMD64Win := Descriptor{
|
||||
MediaType: MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 12345,
|
||||
Digest: EmptyDigest,
|
||||
Platform: &platform.Platform{
|
||||
@ -556,7 +558,7 @@ func TestDescriptorSearch(t *testing.T) {
|
||||
},
|
||||
}
|
||||
dARM64 := Descriptor{
|
||||
MediaType: MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 12345,
|
||||
Digest: EmptyDigest,
|
||||
Platform: &platform.Platform{
|
||||
@ -565,7 +567,7 @@ func TestDescriptorSearch(t *testing.T) {
|
||||
},
|
||||
}
|
||||
dAnnotations := Descriptor{
|
||||
MediaType: MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 12345,
|
||||
Digest: EmptyDigest,
|
||||
Platform: &platform.Platform{
|
||||
@ -579,7 +581,7 @@ func TestDescriptorSearch(t *testing.T) {
|
||||
},
|
||||
}
|
||||
dAnnotations2 := Descriptor{
|
||||
MediaType: MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 12345,
|
||||
Digest: EmptyDigest,
|
||||
Platform: &platform.Platform{
|
||||
@ -593,7 +595,7 @@ func TestDescriptorSearch(t *testing.T) {
|
||||
},
|
||||
}
|
||||
dArtifact := Descriptor{
|
||||
MediaType: MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 12345,
|
||||
Digest: EmptyDigest,
|
||||
ArtifactType: "application/example.artifact",
|
||||
@ -603,7 +605,7 @@ func TestDescriptorSearch(t *testing.T) {
|
||||
},
|
||||
}
|
||||
dArtifact2 := Descriptor{
|
||||
MediaType: MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 12345,
|
||||
Digest: EmptyDigest,
|
||||
ArtifactType: "application/example.artifact",
|
||||
@ -614,7 +616,7 @@ func TestDescriptorSearch(t *testing.T) {
|
||||
},
|
||||
}
|
||||
dArtifact3 := Descriptor{
|
||||
MediaType: MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 12345,
|
||||
Digest: EmptyDigest,
|
||||
ArtifactType: "application/example.artifact",
|
||||
@ -642,7 +644,7 @@ func TestDescriptorSearch(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
err: ErrNotFound,
|
||||
err: errs.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "amd64",
|
||||
@ -701,7 +703,7 @@ func TestDescriptorSearch(t *testing.T) {
|
||||
Architecture: "amd64",
|
||||
},
|
||||
},
|
||||
err: ErrNotFound,
|
||||
err: errs.ErrNotFound,
|
||||
},
|
||||
{
|
||||
name: "artifact",
|
@ -10,20 +10,20 @@ import (
|
||||
"github.com/docker/libtrust"
|
||||
"github.com/opencontainers/go-digest"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/docker"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
)
|
||||
|
||||
var (
|
||||
// ManifestSchemaVersion provides a pre-initialized version structure schema1 manifests.
|
||||
ManifestSchemaVersion = docker.Versioned{
|
||||
SchemaVersion: 1,
|
||||
MediaType: types.MediaTypeDocker1Manifest,
|
||||
MediaType: mediatype.Docker1Manifest,
|
||||
}
|
||||
// ManifestSignedSchemaVersion provides a pre-initialized version structure schema1 signed manifests.
|
||||
ManifestSignedSchemaVersion = docker.Versioned{
|
||||
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.
|
||||
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.
|
||||
|
@ -1,14 +1,15 @@
|
||||
package schema2
|
||||
|
||||
import (
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/docker"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
)
|
||||
|
||||
// ManifestSchemaVersion is a pre-configured versioned field for manifests
|
||||
var ManifestSchemaVersion = docker.Versioned{
|
||||
SchemaVersion: 2,
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
}
|
||||
|
||||
// Manifest defines a schema2 manifest.
|
||||
@ -16,11 +17,11 @@ type Manifest struct {
|
||||
docker.Versioned
|
||||
|
||||
// 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
|
||||
// configuration.
|
||||
Layers []types.Descriptor `json:"layers"`
|
||||
Layers []descriptor.Descriptor `json:"layers"`
|
||||
|
||||
// Annotations contains arbitrary metadata for the image index.
|
||||
// Note, this is not a defined docker schema2 field.
|
||||
|
@ -1,14 +1,15 @@
|
||||
package schema2
|
||||
|
||||
import (
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/docker"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
)
|
||||
|
||||
// ManifestListSchemaVersion is a pre-configured versioned field for manifest lists
|
||||
var ManifestListSchemaVersion = docker.Versioned{
|
||||
SchemaVersion: 2,
|
||||
MediaType: types.MediaTypeDocker2ManifestList,
|
||||
MediaType: mediatype.Docker2ManifestList,
|
||||
}
|
||||
|
||||
// ManifestList references manifests for various platforms.
|
||||
@ -16,7 +17,7 @@ type ManifestList struct {
|
||||
docker.Versioned
|
||||
|
||||
// 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.
|
||||
// Note, this is not a defined docker schema2 field.
|
||||
|
154
types/error.go
154
types/error.go
@ -1,86 +1,150 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
)
|
||||
import "github.com/regclient/regclient/types/errs"
|
||||
|
||||
var (
|
||||
// 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 = errors.New("API not found")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrAPINotFound].
|
||||
ErrAPINotFound = errs.ErrAPINotFound
|
||||
// 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 = errors.New("context was canceled")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrCanceled].
|
||||
ErrCanceled = errs.ErrCanceled
|
||||
// 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 = errors.New("empty challenge header")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrEmptyChallenge].
|
||||
ErrEmptyChallenge = errs.ErrEmptyChallenge
|
||||
// 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 = 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 = 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 = 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 = errors.New("invalid reference")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrInvalidReference].
|
||||
ErrInvalidReference = errs.ErrInvalidReference
|
||||
// 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 = errors.New("manifest not set")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrManifestNotSet].
|
||||
ErrManifestNotSet = errs.ErrManifestNotSet
|
||||
// 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 = errors.New("digest missing from image reference")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrMissingDigest].
|
||||
ErrMissingDigest = errs.ErrMissingDigest
|
||||
// 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 = errors.New("name missing")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrMissingName].
|
||||
ErrMissingName = errs.ErrMissingName
|
||||
// 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 = 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 = 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 = 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 = errors.New("no new challenge")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrNoNewChallenge].
|
||||
ErrNoNewChallenge = errs.ErrNoNewChallenge
|
||||
// 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 = errors.New("not implemented")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrNotImplemented].
|
||||
ErrNotImplemented = errs.ErrNotImplemented
|
||||
// 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 = errors.New("parsing failed")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrParsingFailed].
|
||||
ErrParsingFailed = errs.ErrParsingFailed
|
||||
// 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 = errors.New("short read")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrShortRead].
|
||||
ErrShortRead = errs.ErrShortRead
|
||||
// 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 = errors.New("unavailable")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrUnavailable].
|
||||
ErrUnavailable = errs.ErrUnavailable
|
||||
// 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 = 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 = errors.New("unsupported config version")
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrUnsupportedConfigVersion].
|
||||
ErrUnsupportedConfigVersion = errs.ErrUnsupportedConfigVersion
|
||||
// ErrUnsupportedMediaType returned when media type is unknown or unsupported
|
||||
ErrUnsupportedMediaType = errors.New("unsupported media type")
|
||||
)
|
||||
|
||||
// custom HTTP errors extend the ErrHTTPStatus error
|
||||
var (
|
||||
//
|
||||
// Deprecated: replace with [errs.ErrUnsupportedMediaType].
|
||||
ErrUnsupportedMediaType = errs.ErrUnsupportedMediaType
|
||||
// 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 = 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"
|
||||
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
)
|
||||
|
||||
type common struct {
|
||||
r ref.Ref
|
||||
desc types.Descriptor
|
||||
desc descriptor.Descriptor
|
||||
manifSet bool
|
||||
ratelimit types.RateLimit
|
||||
rawHeader http.Header
|
||||
@ -30,7 +32,7 @@ func (m *common) GetDigest() digest.Digest {
|
||||
}
|
||||
|
||||
// GetDescriptor returns the descriptor
|
||||
func (m *common) GetDescriptor() types.Descriptor {
|
||||
func (m *common) GetDescriptor() descriptor.Descriptor {
|
||||
return m.desc
|
||||
}
|
||||
|
||||
@ -74,7 +76,7 @@ func (m *common) IsSet() bool {
|
||||
// RawBody returns the raw body from the manifest if available.
|
||||
func (m *common) RawBody() ([]byte, error) {
|
||||
if len(m.rawBody) == 0 {
|
||||
return m.rawBody, types.ErrManifestNotSet
|
||||
return m.rawBody, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.rawBody, nil
|
||||
}
|
||||
|
@ -12,8 +12,10 @@ import (
|
||||
|
||||
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/errs"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
)
|
||||
|
||||
@ -33,47 +35,47 @@ type docker1SignedManifest struct {
|
||||
schema1.SignedManifest
|
||||
}
|
||||
|
||||
func (m *docker1Manifest) GetConfig() (types.Descriptor, error) {
|
||||
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker1Manifest) GetConfig() (descriptor.Descriptor, error) {
|
||||
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) {
|
||||
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) {
|
||||
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker1SignedManifest) GetConfig() (descriptor.Descriptor, error) {
|
||||
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) {
|
||||
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) {
|
||||
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker1Manifest) GetManifestList() ([]descriptor.Descriptor, error) {
|
||||
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) {
|
||||
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker1SignedManifest) GetManifestList() ([]descriptor.Descriptor, error) {
|
||||
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 {
|
||||
return []types.Descriptor{}, types.ErrManifestNotSet
|
||||
return []descriptor.Descriptor{}, errs.ErrManifestNotSet
|
||||
}
|
||||
|
||||
var dl []types.Descriptor
|
||||
var dl []descriptor.Descriptor
|
||||
for _, sd := range m.FSLayers {
|
||||
dl = append(dl, types.Descriptor{
|
||||
dl = append(dl, descriptor.Descriptor{
|
||||
Digest: sd.BlobSum,
|
||||
})
|
||||
}
|
||||
return dl, nil
|
||||
}
|
||||
func (m *docker1SignedManifest) GetLayers() ([]types.Descriptor, error) {
|
||||
func (m *docker1SignedManifest) GetLayers() ([]descriptor.Descriptor, error) {
|
||||
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 {
|
||||
dl = append(dl, types.Descriptor{
|
||||
dl = append(dl, descriptor.Descriptor{
|
||||
Digest: sd.BlobSum,
|
||||
})
|
||||
}
|
||||
@ -87,31 +89,31 @@ func (m *docker1SignedManifest) GetOrig() interface{} {
|
||||
return m.SignedManifest
|
||||
}
|
||||
|
||||
func (m *docker1Manifest) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) {
|
||||
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
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, errs.ErrUnsupportedMediaType)
|
||||
}
|
||||
func (m *docker1SignedManifest) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) {
|
||||
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
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, errs.ErrUnsupportedMediaType)
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
if !m.manifSet {
|
||||
return []byte{}, types.ErrManifestNotSet
|
||||
return []byte{}, errs.ErrManifestNotSet
|
||||
}
|
||||
|
||||
if len(m.rawBody) > 0 {
|
||||
@ -123,7 +125,7 @@ func (m *docker1Manifest) MarshalJSON() ([]byte, error) {
|
||||
|
||||
func (m *docker1SignedManifest) MarshalJSON() ([]byte, error) {
|
||||
if !m.manifSet {
|
||||
return []byte{}, types.ErrManifestNotSet
|
||||
return []byte{}, errs.ErrManifestNotSet
|
||||
}
|
||||
|
||||
return m.SignedManifest.MarshalJSON()
|
||||
@ -168,30 +170,30 @@ func (m *docker1SignedManifest) MarshalPretty() ([]byte, error) {
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
func (m *docker1Manifest) SetConfig(d types.Descriptor) error {
|
||||
return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker1Manifest) SetConfig(d descriptor.Descriptor) error {
|
||||
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 {
|
||||
return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker1SignedManifest) SetConfig(d descriptor.Descriptor) error {
|
||||
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 {
|
||||
return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker1Manifest) SetLayers(dl []descriptor.Descriptor) error {
|
||||
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 {
|
||||
return fmt.Errorf("set methods not supported for for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker1SignedManifest) SetLayers(dl []descriptor.Descriptor) error {
|
||||
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 {
|
||||
orig, ok := origIn.(schema1.Manifest)
|
||||
if !ok {
|
||||
return types.ErrUnsupportedMediaType
|
||||
return errs.ErrUnsupportedMediaType
|
||||
}
|
||||
if orig.MediaType != types.MediaTypeDocker1Manifest {
|
||||
if orig.MediaType != mediatype.Docker1Manifest {
|
||||
// TODO: error?
|
||||
orig.MediaType = types.MediaTypeDocker1Manifest
|
||||
orig.MediaType = mediatype.Docker1Manifest
|
||||
}
|
||||
mj, err := json.Marshal(orig)
|
||||
if err != nil {
|
||||
@ -199,8 +201,8 @@ func (m *docker1Manifest) SetOrig(origIn interface{}) error {
|
||||
}
|
||||
m.manifSet = true
|
||||
m.rawBody = mj
|
||||
m.desc = types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker1Manifest,
|
||||
m.desc = descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker1Manifest,
|
||||
Digest: digest.FromBytes(mj),
|
||||
Size: int64(len(mj)),
|
||||
}
|
||||
@ -212,11 +214,11 @@ func (m *docker1Manifest) SetOrig(origIn interface{}) error {
|
||||
func (m *docker1SignedManifest) SetOrig(origIn interface{}) error {
|
||||
orig, ok := origIn.(schema1.SignedManifest)
|
||||
if !ok {
|
||||
return types.ErrUnsupportedMediaType
|
||||
return errs.ErrUnsupportedMediaType
|
||||
}
|
||||
if orig.MediaType != types.MediaTypeDocker1ManifestSigned {
|
||||
if orig.MediaType != mediatype.Docker1ManifestSigned {
|
||||
// TODO: error?
|
||||
orig.MediaType = types.MediaTypeDocker1ManifestSigned
|
||||
orig.MediaType = mediatype.Docker1ManifestSigned
|
||||
}
|
||||
mj, err := json.Marshal(orig)
|
||||
if err != nil {
|
||||
@ -224,8 +226,8 @@ func (m *docker1SignedManifest) SetOrig(origIn interface{}) error {
|
||||
}
|
||||
m.manifSet = true
|
||||
m.rawBody = mj
|
||||
m.desc = types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker1ManifestSigned,
|
||||
m.desc = descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker1ManifestSigned,
|
||||
Digest: digest.FromBytes(mj),
|
||||
Size: int64(len(mj)),
|
||||
}
|
||||
|
@ -14,16 +14,18 @@ import (
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
|
||||
"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/errs"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
)
|
||||
|
||||
const (
|
||||
// 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 = types.MediaTypeDocker2ManifestList
|
||||
MediaTypeDocker2ManifestList = mediatype.Docker2ManifestList
|
||||
)
|
||||
|
||||
type docker2Manifest struct {
|
||||
@ -37,53 +39,53 @@ type docker2ManifestList struct {
|
||||
|
||||
func (m *docker2Manifest) GetAnnotations() (map[string]string, error) {
|
||||
if !m.manifSet {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Annotations, nil
|
||||
}
|
||||
func (m *docker2Manifest) GetConfig() (types.Descriptor, error) {
|
||||
func (m *docker2Manifest) GetConfig() (descriptor.Descriptor, error) {
|
||||
if !m.manifSet {
|
||||
return types.Descriptor{}, types.ErrManifestNotSet
|
||||
return descriptor.Descriptor{}, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Config, nil
|
||||
}
|
||||
func (m *docker2Manifest) GetConfigDigest() (digest.Digest, error) {
|
||||
if !m.manifSet {
|
||||
return digest.Digest(""), types.ErrManifestNotSet
|
||||
return digest.Digest(""), errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Config.Digest, nil
|
||||
}
|
||||
func (m *docker2ManifestList) GetAnnotations() (map[string]string, error) {
|
||||
if !m.manifSet {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Annotations, nil
|
||||
}
|
||||
func (m *docker2ManifestList) GetConfig() (types.Descriptor, error) {
|
||||
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker2ManifestList) GetConfig() (descriptor.Descriptor, error) {
|
||||
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) {
|
||||
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) {
|
||||
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker2Manifest) GetManifestList() ([]descriptor.Descriptor, error) {
|
||||
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 {
|
||||
return []types.Descriptor{}, types.ErrManifestNotSet
|
||||
return []descriptor.Descriptor{}, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Manifests, nil
|
||||
}
|
||||
|
||||
func (m *docker2Manifest) GetLayers() ([]types.Descriptor, error) {
|
||||
func (m *docker2Manifest) GetLayers() ([]descriptor.Descriptor, error) {
|
||||
if !m.manifSet {
|
||||
return []types.Descriptor{}, types.ErrManifestNotSet
|
||||
return []descriptor.Descriptor{}, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Layers, nil
|
||||
}
|
||||
func (m *docker2ManifestList) GetLayers() ([]types.Descriptor, error) {
|
||||
return []types.Descriptor{}, fmt.Errorf("layers are not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *docker2ManifestList) GetLayers() ([]descriptor.Descriptor, error) {
|
||||
return []descriptor.Descriptor{}, fmt.Errorf("layers are not available for media type %s%.0w", m.desc.MediaType, errs.ErrUnsupportedMediaType)
|
||||
}
|
||||
|
||||
func (m *docker2Manifest) GetOrig() interface{} {
|
||||
@ -93,17 +95,17 @@ func (m *docker2ManifestList) GetOrig() interface{} {
|
||||
return m.ManifestList
|
||||
}
|
||||
|
||||
func (m *docker2Manifest) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) {
|
||||
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
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, 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 {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
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) {
|
||||
dl, err := m.GetManifestList()
|
||||
@ -124,7 +126,7 @@ func (m *docker2ManifestList) GetPlatformList() ([]*platform.Platform, error) {
|
||||
// GetSize returns the size in bytes of all layers
|
||||
func (m *docker2Manifest) GetSize() (int64, error) {
|
||||
if !m.manifSet {
|
||||
return 0, types.ErrManifestNotSet
|
||||
return 0, errs.ErrManifestNotSet
|
||||
}
|
||||
var total int64
|
||||
for _, d := range m.Layers {
|
||||
@ -135,7 +137,7 @@ func (m *docker2Manifest) GetSize() (int64, error) {
|
||||
|
||||
func (m *docker2Manifest) MarshalJSON() ([]byte, error) {
|
||||
if !m.manifSet {
|
||||
return []byte{}, types.ErrManifestNotSet
|
||||
return []byte{}, errs.ErrManifestNotSet
|
||||
}
|
||||
if len(m.rawBody) > 0 {
|
||||
return m.rawBody, nil
|
||||
@ -144,7 +146,7 @@ func (m *docker2Manifest) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
func (m *docker2ManifestList) MarshalJSON() ([]byte, error) {
|
||||
if !m.manifSet {
|
||||
return []byte{}, types.ErrManifestNotSet
|
||||
return []byte{}, errs.ErrManifestNotSet
|
||||
}
|
||||
if len(m.rawBody) > 0 {
|
||||
return m.rawBody, nil
|
||||
@ -241,7 +243,7 @@ func (m *docker2ManifestList) MarshalPretty() ([]byte, error) {
|
||||
|
||||
func (m *docker2Manifest) SetAnnotation(key, val string) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
if m.Annotations == nil {
|
||||
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 {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
if m.Annotations == nil {
|
||||
m.Annotations = map[string]string{}
|
||||
@ -268,25 +270,25 @@ func (m *docker2ManifestList) SetAnnotation(key, val string) error {
|
||||
return m.updateDesc()
|
||||
}
|
||||
|
||||
func (m *docker2Manifest) SetConfig(d types.Descriptor) error {
|
||||
func (m *docker2Manifest) SetConfig(d descriptor.Descriptor) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.Config = d
|
||||
return m.updateDesc()
|
||||
}
|
||||
|
||||
func (m *docker2Manifest) SetLayers(dl []types.Descriptor) error {
|
||||
func (m *docker2Manifest) SetLayers(dl []descriptor.Descriptor) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.Layers = dl
|
||||
return m.updateDesc()
|
||||
}
|
||||
|
||||
func (m *docker2ManifestList) SetManifestList(dl []types.Descriptor) error {
|
||||
func (m *docker2ManifestList) SetManifestList(dl []descriptor.Descriptor) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.Manifests = dl
|
||||
return m.updateDesc()
|
||||
@ -295,11 +297,11 @@ func (m *docker2ManifestList) SetManifestList(dl []types.Descriptor) error {
|
||||
func (m *docker2Manifest) SetOrig(origIn interface{}) error {
|
||||
orig, ok := origIn.(schema2.Manifest)
|
||||
if !ok {
|
||||
return types.ErrUnsupportedMediaType
|
||||
return errs.ErrUnsupportedMediaType
|
||||
}
|
||||
if orig.MediaType != types.MediaTypeDocker2Manifest {
|
||||
if orig.MediaType != mediatype.Docker2Manifest {
|
||||
// TODO: error?
|
||||
orig.MediaType = types.MediaTypeDocker2Manifest
|
||||
orig.MediaType = mediatype.Docker2Manifest
|
||||
}
|
||||
m.manifSet = true
|
||||
m.Manifest = orig
|
||||
@ -309,11 +311,11 @@ func (m *docker2Manifest) SetOrig(origIn interface{}) error {
|
||||
func (m *docker2ManifestList) SetOrig(origIn interface{}) error {
|
||||
orig, ok := origIn.(schema2.ManifestList)
|
||||
if !ok {
|
||||
return types.ErrUnsupportedMediaType
|
||||
return errs.ErrUnsupportedMediaType
|
||||
}
|
||||
if orig.MediaType != types.MediaTypeDocker2ManifestList {
|
||||
if orig.MediaType != mediatype.Docker2ManifestList {
|
||||
// TODO: error?
|
||||
orig.MediaType = types.MediaTypeDocker2ManifestList
|
||||
orig.MediaType = mediatype.Docker2ManifestList
|
||||
}
|
||||
m.manifSet = true
|
||||
m.ManifestList = orig
|
||||
@ -326,8 +328,8 @@ func (m *docker2Manifest) updateDesc() error {
|
||||
return err
|
||||
}
|
||||
m.rawBody = mj
|
||||
m.desc = types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
m.desc = descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Digest: digest.FromBytes(mj),
|
||||
Size: int64(len(mj)),
|
||||
}
|
||||
@ -339,8 +341,8 @@ func (m *docker2ManifestList) updateDesc() error {
|
||||
return err
|
||||
}
|
||||
m.rawBody = mj
|
||||
m.desc = types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2ManifestList,
|
||||
m.desc = descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2ManifestList,
|
||||
Digest: digest.FromBytes(mj),
|
||||
Size: int64(len(mj)),
|
||||
}
|
||||
|
@ -17,8 +17,11 @@ import (
|
||||
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/schema2"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -27,7 +30,7 @@ import (
|
||||
// Manifest interface is implemented by all supported manifests but
|
||||
// many calls are only supported by certain underlying media types.
|
||||
type Manifest interface {
|
||||
GetDescriptor() types.Descriptor
|
||||
GetDescriptor() descriptor.Descriptor
|
||||
GetOrig() interface{}
|
||||
GetRef() ref.Ref
|
||||
IsList() bool
|
||||
@ -38,12 +41,12 @@ type Manifest interface {
|
||||
SetOrig(interface{}) error
|
||||
|
||||
// Deprecated: GetConfig should be accessed using [Imager] interface.
|
||||
GetConfig() (types.Descriptor, error)
|
||||
GetConfig() (descriptor.Descriptor, error)
|
||||
// Deprecated: GetLayers should be accessed using [Imager] interface.
|
||||
GetLayers() ([]types.Descriptor, error)
|
||||
GetLayers() ([]descriptor.Descriptor, error)
|
||||
|
||||
// Deprecated: GetManifestList should be accessed using [Indexer] interface.
|
||||
GetManifestList() ([]types.Descriptor, error)
|
||||
GetManifestList() ([]descriptor.Descriptor, error)
|
||||
|
||||
// Deprecated: GetConfigDigest should be replaced with [GetConfig].
|
||||
GetConfigDigest() (digest.Digest, error)
|
||||
@ -52,7 +55,7 @@ type Manifest interface {
|
||||
// Deprecated: GetMediaType should be replaced with GetDescriptor().MediaType, see [GetDescriptor].
|
||||
GetMediaType() string
|
||||
// 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].
|
||||
GetPlatformList() ([]*platform.Platform, error)
|
||||
// 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.
|
||||
type Indexer interface {
|
||||
GetManifestList() ([]types.Descriptor, error)
|
||||
SetManifestList(dl []types.Descriptor) error
|
||||
GetManifestList() ([]descriptor.Descriptor, error)
|
||||
SetManifestList(dl []descriptor.Descriptor) error
|
||||
}
|
||||
|
||||
// Imager is used by manifests packaging an image.
|
||||
type Imager interface {
|
||||
GetConfig() (types.Descriptor, error)
|
||||
GetLayers() ([]types.Descriptor, error)
|
||||
SetConfig(d types.Descriptor) error
|
||||
SetLayers(dl []types.Descriptor) error
|
||||
GetConfig() (descriptor.Descriptor, error)
|
||||
GetLayers() ([]descriptor.Descriptor, error)
|
||||
SetConfig(d descriptor.Descriptor) error
|
||||
SetLayers(dl []descriptor.Descriptor) error
|
||||
GetSize() (int64, error)
|
||||
}
|
||||
|
||||
// Subjecter is used by manifests that may have a subject field.
|
||||
type Subjecter interface {
|
||||
GetSubject() (*types.Descriptor, error)
|
||||
SetSubject(d *types.Descriptor) error
|
||||
GetSubject() (*descriptor.Descriptor, error)
|
||||
SetSubject(d *descriptor.Descriptor) error
|
||||
}
|
||||
|
||||
type manifestConfig struct {
|
||||
r ref.Ref
|
||||
desc types.Descriptor
|
||||
desc descriptor.Descriptor
|
||||
raw []byte
|
||||
orig interface{}
|
||||
header http.Header
|
||||
@ -113,7 +116,7 @@ func New(opts ...Opts) (Manifest, error) {
|
||||
// extract fields from header where available
|
||||
if mc.header != nil {
|
||||
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 {
|
||||
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.
|
||||
func WithDesc(desc types.Descriptor) Opts {
|
||||
func WithDesc(desc descriptor.Descriptor) Opts {
|
||||
return func(mc *manifestConfig) {
|
||||
mc.desc = desc
|
||||
}
|
||||
@ -178,15 +181,15 @@ func GetMediaType(m Manifest) string {
|
||||
}
|
||||
|
||||
// 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()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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 {
|
||||
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) {
|
||||
ociI := v1.Index{
|
||||
Versioned: v1.IndexSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
}
|
||||
switch orig := orig.(type) {
|
||||
case schema2.ManifestList:
|
||||
@ -311,7 +314,7 @@ func OCIIndexToAny(ociI v1.Index, origP interface{}) error {
|
||||
func OCIManifestFromAny(orig interface{}) (v1.Manifest, error) {
|
||||
ociM := v1.Manifest{
|
||||
Versioned: v1.ManifestSchemaVersion,
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
}
|
||||
switch orig := orig.(type) {
|
||||
case schema2.Manifest:
|
||||
@ -382,14 +385,14 @@ func fromOrig(c common, orig interface{}) (Manifest, error) {
|
||||
switch mOrig := orig.(type) {
|
||||
case schema1.Manifest:
|
||||
mt = mOrig.MediaType
|
||||
c.desc.MediaType = types.MediaTypeDocker1Manifest
|
||||
c.desc.MediaType = mediatype.Docker1Manifest
|
||||
m = &docker1Manifest{
|
||||
common: c,
|
||||
Manifest: mOrig,
|
||||
}
|
||||
case schema1.SignedManifest:
|
||||
mt = mOrig.MediaType
|
||||
c.desc.MediaType = types.MediaTypeDocker1ManifestSigned
|
||||
c.desc.MediaType = mediatype.Docker1ManifestSigned
|
||||
// recompute digest on the canonical data
|
||||
c.desc.Digest = digest.FromBytes(mOrig.Canonical)
|
||||
m = &docker1SignedManifest{
|
||||
@ -398,35 +401,35 @@ func fromOrig(c common, orig interface{}) (Manifest, error) {
|
||||
}
|
||||
case schema2.Manifest:
|
||||
mt = mOrig.MediaType
|
||||
c.desc.MediaType = types.MediaTypeDocker2Manifest
|
||||
c.desc.MediaType = mediatype.Docker2Manifest
|
||||
m = &docker2Manifest{
|
||||
common: c,
|
||||
Manifest: mOrig,
|
||||
}
|
||||
case schema2.ManifestList:
|
||||
mt = mOrig.MediaType
|
||||
c.desc.MediaType = types.MediaTypeDocker2ManifestList
|
||||
c.desc.MediaType = mediatype.Docker2ManifestList
|
||||
m = &docker2ManifestList{
|
||||
common: c,
|
||||
ManifestList: mOrig,
|
||||
}
|
||||
case v1.Manifest:
|
||||
mt = mOrig.MediaType
|
||||
c.desc.MediaType = types.MediaTypeOCI1Manifest
|
||||
c.desc.MediaType = mediatype.OCI1Manifest
|
||||
m = &oci1Manifest{
|
||||
common: c,
|
||||
Manifest: mOrig,
|
||||
}
|
||||
case v1.Index:
|
||||
mt = mOrig.MediaType
|
||||
c.desc.MediaType = types.MediaTypeOCI1ManifestList
|
||||
c.desc.MediaType = mediatype.OCI1ManifestList
|
||||
m = &oci1Index{
|
||||
common: c,
|
||||
Index: orig.(v1.Index),
|
||||
}
|
||||
case v1.ArtifactManifest:
|
||||
mt = mOrig.MediaType
|
||||
c.desc.MediaType = types.MediaTypeOCI1Artifact
|
||||
c.desc.MediaType = mediatype.OCI1Artifact
|
||||
m = &oci1Artifact{
|
||||
common: c,
|
||||
ArtifactManifest: mOrig,
|
||||
@ -458,49 +461,49 @@ func fromCommon(c common) (Manifest, error) {
|
||||
// extract media type from body, either explicitly or with duck typing
|
||||
if c.desc.MediaType == "" {
|
||||
mt := struct {
|
||||
MediaType string `json:"mediaType,omitempty"`
|
||||
SchemaVersion int `json:"schemaVersion,omitempty"`
|
||||
Signatures []interface{} `json:"signatures,omitempty"`
|
||||
Manifests []types.Descriptor `json:"manifests,omitempty"`
|
||||
Layers []types.Descriptor `json:"layers,omitempty"`
|
||||
MediaType string `json:"mediaType,omitempty"`
|
||||
SchemaVersion int `json:"schemaVersion,omitempty"`
|
||||
Signatures []interface{} `json:"signatures,omitempty"`
|
||||
Manifests []descriptor.Descriptor `json:"manifests,omitempty"`
|
||||
Layers []descriptor.Descriptor `json:"layers,omitempty"`
|
||||
}{}
|
||||
err = json.Unmarshal(c.rawBody, &mt)
|
||||
if mt.MediaType != "" {
|
||||
c.desc.MediaType = mt.MediaType
|
||||
} else if mt.SchemaVersion == 1 && len(mt.Signatures) > 0 {
|
||||
c.desc.MediaType = types.MediaTypeDocker1ManifestSigned
|
||||
c.desc.MediaType = mediatype.Docker1ManifestSigned
|
||||
} else if mt.SchemaVersion == 1 {
|
||||
c.desc.MediaType = types.MediaTypeDocker1Manifest
|
||||
c.desc.MediaType = mediatype.Docker1Manifest
|
||||
} else if len(mt.Manifests) > 0 {
|
||||
if strings.HasPrefix(mt.Manifests[0].MediaType, "application/vnd.docker.") {
|
||||
c.desc.MediaType = types.MediaTypeDocker2ManifestList
|
||||
c.desc.MediaType = mediatype.Docker2ManifestList
|
||||
} else {
|
||||
c.desc.MediaType = types.MediaTypeOCI1ManifestList
|
||||
c.desc.MediaType = mediatype.OCI1ManifestList
|
||||
}
|
||||
} else if len(mt.Layers) > 0 {
|
||||
if strings.HasPrefix(mt.Layers[0].MediaType, "application/vnd.docker.") {
|
||||
c.desc.MediaType = types.MediaTypeDocker2Manifest
|
||||
c.desc.MediaType = mediatype.Docker2Manifest
|
||||
} else {
|
||||
c.desc.MediaType = types.MediaTypeOCI1Manifest
|
||||
c.desc.MediaType = mediatype.OCI1Manifest
|
||||
}
|
||||
}
|
||||
}
|
||||
// compute digest
|
||||
if c.desc.MediaType != types.MediaTypeDocker1ManifestSigned {
|
||||
if c.desc.MediaType != mediatype.Docker1ManifestSigned {
|
||||
d := digest.FromBytes(c.rawBody)
|
||||
c.desc.Digest = d
|
||||
c.desc.Size = int64(len(c.rawBody))
|
||||
}
|
||||
}
|
||||
switch c.desc.MediaType {
|
||||
case types.MediaTypeDocker1Manifest:
|
||||
case mediatype.Docker1Manifest:
|
||||
var mOrig schema1.Manifest
|
||||
if len(c.rawBody) > 0 {
|
||||
err = json.Unmarshal(c.rawBody, &mOrig)
|
||||
mt = mOrig.MediaType
|
||||
}
|
||||
m = &docker1Manifest{common: c, Manifest: mOrig}
|
||||
case types.MediaTypeDocker1ManifestSigned:
|
||||
case mediatype.Docker1ManifestSigned:
|
||||
var mOrig schema1.SignedManifest
|
||||
if len(c.rawBody) > 0 {
|
||||
err = json.Unmarshal(c.rawBody, &mOrig)
|
||||
@ -510,35 +513,35 @@ func fromCommon(c common) (Manifest, error) {
|
||||
c.desc.Size = int64(len(mOrig.Canonical))
|
||||
}
|
||||
m = &docker1SignedManifest{common: c, SignedManifest: mOrig}
|
||||
case types.MediaTypeDocker2Manifest:
|
||||
case mediatype.Docker2Manifest:
|
||||
var mOrig schema2.Manifest
|
||||
if len(c.rawBody) > 0 {
|
||||
err = json.Unmarshal(c.rawBody, &mOrig)
|
||||
mt = mOrig.MediaType
|
||||
}
|
||||
m = &docker2Manifest{common: c, Manifest: mOrig}
|
||||
case types.MediaTypeDocker2ManifestList:
|
||||
case mediatype.Docker2ManifestList:
|
||||
var mOrig schema2.ManifestList
|
||||
if len(c.rawBody) > 0 {
|
||||
err = json.Unmarshal(c.rawBody, &mOrig)
|
||||
mt = mOrig.MediaType
|
||||
}
|
||||
m = &docker2ManifestList{common: c, ManifestList: mOrig}
|
||||
case types.MediaTypeOCI1Manifest:
|
||||
case mediatype.OCI1Manifest:
|
||||
var mOrig v1.Manifest
|
||||
if len(c.rawBody) > 0 {
|
||||
err = json.Unmarshal(c.rawBody, &mOrig)
|
||||
mt = mOrig.MediaType
|
||||
}
|
||||
m = &oci1Manifest{common: c, Manifest: mOrig}
|
||||
case types.MediaTypeOCI1ManifestList:
|
||||
case mediatype.OCI1ManifestList:
|
||||
var mOrig v1.Index
|
||||
if len(c.rawBody) > 0 {
|
||||
err = json.Unmarshal(c.rawBody, &mOrig)
|
||||
mt = mOrig.MediaType
|
||||
}
|
||||
m = &oci1Index{common: c, Index: mOrig}
|
||||
case types.MediaTypeOCI1Artifact:
|
||||
case mediatype.OCI1Artifact:
|
||||
var mOrig v1.ArtifactManifest
|
||||
if len(c.rawBody) > 0 {
|
||||
err = json.Unmarshal(c.rawBody, &mOrig)
|
||||
@ -546,7 +549,7 @@ func fromCommon(c common) (Manifest, error) {
|
||||
}
|
||||
m = &oci1Artifact{common: c, ArtifactManifest: mOrig}
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
func getPlatformList(dl []types.Descriptor) ([]*platform.Platform, error) {
|
||||
func getPlatformList(dl []descriptor.Descriptor) ([]*platform.Platform, error) {
|
||||
var l []*platform.Platform
|
||||
for _, d := range dl {
|
||||
if d.Platform != nil {
|
||||
|
@ -9,9 +9,11 @@ import (
|
||||
|
||||
"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/schema2"
|
||||
"github.com/regclient/regclient/types/errs"
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
v1 "github.com/regclient/regclient/types/oci/v1"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
"github.com/regclient/regclient/types/ref"
|
||||
@ -418,7 +420,7 @@ func TestNew(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal OCI Artifact json: %v", err)
|
||||
}
|
||||
manifestInvalid.MediaType = types.MediaTypeOCI1Manifest
|
||||
manifestInvalid.MediaType = mediatype.OCI1Manifest
|
||||
err = json.Unmarshal(rawDockerSchema1Signed, &manifestDockerSchema1Signed)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unmarshal docker schema1 signed json: %v", err)
|
||||
@ -427,20 +429,20 @@ func TestNew(t *testing.T) {
|
||||
name string
|
||||
opts []Opts
|
||||
wantR ref.Ref
|
||||
wantDesc types.Descriptor
|
||||
wantDesc descriptor.Descriptor
|
||||
wantE error
|
||||
isSet bool
|
||||
testAnnot bool
|
||||
hasAnnot bool
|
||||
testPlat string
|
||||
wantPlat types.Descriptor
|
||||
wantPlat descriptor.Descriptor
|
||||
wantSize int64
|
||||
testSubject bool
|
||||
hasSubject bool
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
wantE: fmt.Errorf("%w: \"%s\"", types.ErrUnsupportedMediaType, ""),
|
||||
wantE: fmt.Errorf("%w: \"%s\"", errs.ErrUnsupportedMediaType, ""),
|
||||
},
|
||||
{
|
||||
name: "Docker Schema 2 Manifest",
|
||||
@ -449,8 +451,8 @@ func TestNew(t *testing.T) {
|
||||
WithRaw(rawDockerSchema2),
|
||||
},
|
||||
wantR: r,
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -464,15 +466,15 @@ func TestNew(t *testing.T) {
|
||||
{
|
||||
name: "Docker Schema 2 Manifest full desc",
|
||||
opts: []Opts{
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Digest: digestDockerSchema2,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
}),
|
||||
WithRaw(rawDockerSchema2),
|
||||
},
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -499,7 +501,7 @@ func TestNew(t *testing.T) {
|
||||
testSubject: true,
|
||||
hasAnnot: true,
|
||||
testPlat: "linux/amd64",
|
||||
wantPlat: types.Descriptor{
|
||||
wantPlat: descriptor.Descriptor{
|
||||
MediaType: "application/vnd.docker.distribution.manifest.v2+json",
|
||||
Digest: "sha256:41b9947d8f19e154a5415c88ef71b851d37fa3ceb1de56ffe88d1b616ce503d9",
|
||||
Size: 1152,
|
||||
@ -517,7 +519,7 @@ func TestNew(t *testing.T) {
|
||||
testSubject: true,
|
||||
hasAnnot: true,
|
||||
testPlat: "darwin/arm64",
|
||||
wantPlat: types.Descriptor{
|
||||
wantPlat: descriptor.Descriptor{
|
||||
MediaType: "application/vnd.docker.distribution.manifest.v2+json",
|
||||
Digest: "sha256:b302f648065bb2ba542dc75167db065781f296ef72bb504585d652b27b5079ad",
|
||||
Size: 1152,
|
||||
@ -529,7 +531,7 @@ func TestNew(t *testing.T) {
|
||||
WithRef(r),
|
||||
WithRaw(rawOCI1Artifact),
|
||||
WithHeader(http.Header{
|
||||
"Content-Type": []string{types.MediaTypeOCI1Artifact},
|
||||
"Content-Type": []string{mediatype.OCI1Artifact},
|
||||
"Docker-Content-Digest": []string{digestOCIArtifact.String()},
|
||||
}),
|
||||
},
|
||||
@ -548,8 +550,8 @@ func TestNew(t *testing.T) {
|
||||
WithRaw(rawOCIImage),
|
||||
},
|
||||
wantR: r,
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: int64(len(rawOCIImage)),
|
||||
Digest: digestOCIImage,
|
||||
},
|
||||
@ -568,8 +570,8 @@ func TestNew(t *testing.T) {
|
||||
WithRaw(rawOCIIndex),
|
||||
},
|
||||
wantR: r,
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Size: int64(len(rawOCIIndex)),
|
||||
Digest: digestOCIIndex,
|
||||
},
|
||||
@ -585,13 +587,13 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithHeader(http.Header{
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
|
||||
"Docker-Content-Digest": []string{digestDockerSchema2.String()},
|
||||
}),
|
||||
},
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -602,13 +604,13 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithHeader(http.Header{
|
||||
"Content-Type": []string{types.MediaTypeDocker1Manifest},
|
||||
"Content-Type": []string{mediatype.Docker1Manifest},
|
||||
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
|
||||
"Docker-Content-Digest": []string{digestDockerSchema2.String()},
|
||||
}),
|
||||
},
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker1Manifest,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker1Manifest,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -619,13 +621,13 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithHeader(http.Header{
|
||||
"Content-Type": []string{types.MediaTypeDocker1ManifestSigned},
|
||||
"Content-Type": []string{mediatype.Docker1ManifestSigned},
|
||||
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
|
||||
"Docker-Content-Digest": []string{digestDockerSchema2.String()},
|
||||
}),
|
||||
},
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker1ManifestSigned,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker1ManifestSigned,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -636,13 +638,13 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithHeader(http.Header{
|
||||
"Content-Type": []string{types.MediaTypeDocker2Manifest},
|
||||
"Content-Type": []string{mediatype.Docker2Manifest},
|
||||
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
|
||||
"Docker-Content-Digest": []string{digestDockerSchema2.String()},
|
||||
}),
|
||||
},
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -653,13 +655,13 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithHeader(http.Header{
|
||||
"Content-Type": []string{types.MediaTypeDocker2ManifestList},
|
||||
"Content-Type": []string{mediatype.Docker2ManifestList},
|
||||
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
|
||||
"Docker-Content-Digest": []string{digestDockerSchema2.String()},
|
||||
}),
|
||||
},
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2ManifestList,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2ManifestList,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -670,13 +672,13 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithHeader(http.Header{
|
||||
"Content-Type": []string{types.MediaTypeOCI1Manifest},
|
||||
"Content-Type": []string{mediatype.OCI1Manifest},
|
||||
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
|
||||
"Docker-Content-Digest": []string{digestDockerSchema2.String()},
|
||||
}),
|
||||
},
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -687,13 +689,13 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithHeader(http.Header{
|
||||
"Content-Type": []string{types.MediaTypeOCI1ManifestList},
|
||||
"Content-Type": []string{mediatype.OCI1ManifestList},
|
||||
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
|
||||
"Docker-Content-Digest": []string{digestDockerSchema2.String()},
|
||||
}),
|
||||
},
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -704,13 +706,13 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithHeader(http.Header{
|
||||
"Content-Type": []string{types.MediaTypeOCI1Artifact},
|
||||
"Content-Type": []string{mediatype.OCI1Artifact},
|
||||
"Content-Length": []string{fmt.Sprintf("%d", len(rawDockerSchema2))},
|
||||
"Docker-Content-Digest": []string{digestDockerSchema2.String()},
|
||||
}),
|
||||
},
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Artifact,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Artifact,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
Digest: digestDockerSchema2,
|
||||
},
|
||||
@ -731,8 +733,8 @@ func TestNew(t *testing.T) {
|
||||
name: "Docker Schema 1 Signed Manifest",
|
||||
opts: []Opts{
|
||||
WithRaw(rawDockerSchema1Signed),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker1ManifestSigned,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker1ManifestSigned,
|
||||
Digest: digestDockerSchema1Signed,
|
||||
Size: int64(len(rawDockerSchema1Signed)),
|
||||
}),
|
||||
@ -757,8 +759,8 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithRaw(rawAmbiguousOCI),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
}),
|
||||
},
|
||||
wantE: nil,
|
||||
@ -769,8 +771,8 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithRaw(rawAmbiguousOCI),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
}),
|
||||
},
|
||||
wantE: nil,
|
||||
@ -781,30 +783,30 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithRaw(rawOCIImage),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
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",
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithRaw(rawOCIIndex),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
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",
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithRaw(rawDockerSchema2),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Digest: digestInvalid,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
}),
|
||||
@ -816,13 +818,13 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
WithRef(r),
|
||||
WithRaw(rawOCIImage),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Digest: digestOCIImage,
|
||||
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",
|
||||
@ -860,7 +862,7 @@ func TestNew(t *testing.T) {
|
||||
opts: []Opts{
|
||||
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",
|
||||
@ -869,8 +871,8 @@ func TestNew(t *testing.T) {
|
||||
},
|
||||
wantE: nil,
|
||||
isSet: true,
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: int64(len(rawOCIImageDuck)),
|
||||
Digest: digestOCIImageDuck,
|
||||
},
|
||||
@ -882,8 +884,8 @@ func TestNew(t *testing.T) {
|
||||
},
|
||||
wantE: nil,
|
||||
isSet: true,
|
||||
wantDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
wantDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Size: int64(len(rawOCIIndexDuck)),
|
||||
Digest: digestOCIIndexDuck,
|
||||
},
|
||||
@ -895,8 +897,8 @@ func TestNew(t *testing.T) {
|
||||
// - test if manifest is set
|
||||
// - test raw body
|
||||
}
|
||||
subDesc := types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
subDesc := descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Size: 1234,
|
||||
Digest: digest.FromString("test referrer"),
|
||||
}
|
||||
@ -939,32 +941,32 @@ func TestNew(t *testing.T) {
|
||||
if m.IsSet() {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -973,32 +975,32 @@ func TestNew(t *testing.T) {
|
||||
if !m.IsSet() {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
@ -1078,7 +1080,7 @@ func TestNew(t *testing.T) {
|
||||
func TestModify(t *testing.T) {
|
||||
t.Parallel()
|
||||
addDigest := digest.FromString("new layer digest")
|
||||
addDesc := types.Descriptor{
|
||||
addDesc := descriptor.Descriptor{
|
||||
Digest: addDigest,
|
||||
Size: 42,
|
||||
Annotations: map[string]string{
|
||||
@ -1090,22 +1092,22 @@ func TestModify(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
opts []Opts
|
||||
addDesc types.Descriptor
|
||||
origDesc types.Descriptor
|
||||
addDesc descriptor.Descriptor
|
||||
origDesc descriptor.Descriptor
|
||||
}{
|
||||
{
|
||||
name: "Docker Schema 2 Manifest",
|
||||
opts: []Opts{
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Digest: digestDockerSchema2,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
}),
|
||||
WithRaw(rawDockerSchema2),
|
||||
},
|
||||
addDesc: addDesc,
|
||||
origDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
origDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Digest: digestDockerSchema2,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
},
|
||||
@ -1113,16 +1115,16 @@ func TestModify(t *testing.T) {
|
||||
{
|
||||
name: "Docker Schema 2 List",
|
||||
opts: []Opts{
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2ManifestList,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2ManifestList,
|
||||
Digest: digestDockerSchema2List,
|
||||
Size: int64(len(rawDockerSchema2List)),
|
||||
}),
|
||||
WithRaw(rawDockerSchema2List),
|
||||
},
|
||||
addDesc: addDesc,
|
||||
origDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2ManifestList,
|
||||
origDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2ManifestList,
|
||||
Digest: digestDockerSchema2List,
|
||||
Size: int64(len(rawDockerSchema2List)),
|
||||
},
|
||||
@ -1131,15 +1133,15 @@ func TestModify(t *testing.T) {
|
||||
name: "OCI Image",
|
||||
opts: []Opts{
|
||||
WithRaw(rawOCIImage),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Digest: digestOCIImage,
|
||||
Size: int64(len(rawOCIImage)),
|
||||
}),
|
||||
},
|
||||
addDesc: addDesc,
|
||||
origDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
origDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Digest: digestOCIImage,
|
||||
Size: int64(len(rawOCIImage)),
|
||||
},
|
||||
@ -1148,15 +1150,15 @@ func TestModify(t *testing.T) {
|
||||
name: "OCI Index",
|
||||
opts: []Opts{
|
||||
WithRaw(rawOCIIndex),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Digest: digestOCIIndex,
|
||||
Size: int64(len(rawOCIIndex)),
|
||||
}),
|
||||
},
|
||||
addDesc: addDesc,
|
||||
origDesc: types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
origDesc: descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Digest: digestOCIIndex,
|
||||
Size: int64(len(rawOCIIndex)),
|
||||
},
|
||||
@ -1298,7 +1300,7 @@ func TestModify(t *testing.T) {
|
||||
func TestSet(t *testing.T) {
|
||||
t.Parallel()
|
||||
addDigest := digest.FromString("new digest")
|
||||
addDesc := types.Descriptor{
|
||||
addDesc := descriptor.Descriptor{
|
||||
Digest: addDigest,
|
||||
Size: 42,
|
||||
Annotations: map[string]string{
|
||||
@ -1318,21 +1320,21 @@ func TestSet(t *testing.T) {
|
||||
{
|
||||
name: "Docker Schema 1",
|
||||
opts: []Opts{
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker1ManifestSigned,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker1ManifestSigned,
|
||||
Digest: digestDockerSchema1Signed,
|
||||
Size: int64(len(rawDockerSchema1Signed)),
|
||||
}),
|
||||
WithRaw(rawDockerSchema1Signed),
|
||||
},
|
||||
expectImage: true,
|
||||
expectErr: types.ErrUnsupportedMediaType,
|
||||
expectErr: errs.ErrUnsupportedMediaType,
|
||||
},
|
||||
{
|
||||
name: "Docker Schema 2 Manifest",
|
||||
opts: []Opts{
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2Manifest,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2Manifest,
|
||||
Digest: digestDockerSchema2,
|
||||
Size: int64(len(rawDockerSchema2)),
|
||||
}),
|
||||
@ -1344,8 +1346,8 @@ func TestSet(t *testing.T) {
|
||||
{
|
||||
name: "Docker Schema 2 List",
|
||||
opts: []Opts{
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeDocker2ManifestList,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.Docker2ManifestList,
|
||||
Digest: digestDockerSchema2List,
|
||||
Size: int64(len(rawDockerSchema2List)),
|
||||
}),
|
||||
@ -1358,8 +1360,8 @@ func TestSet(t *testing.T) {
|
||||
name: "OCI Image",
|
||||
opts: []Opts{
|
||||
WithRaw(rawOCIImage),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Digest: digestOCIImage,
|
||||
Size: int64(len(rawOCIImage)),
|
||||
}),
|
||||
@ -1371,8 +1373,8 @@ func TestSet(t *testing.T) {
|
||||
name: "OCI Index",
|
||||
opts: []Opts{
|
||||
WithRaw(rawOCIIndex),
|
||||
WithDesc(types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
WithDesc(descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Digest: digestOCIIndex,
|
||||
Size: int64(len(rawOCIIndex)),
|
||||
}),
|
||||
|
@ -14,16 +14,18 @@ import (
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
|
||||
"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"
|
||||
"github.com/regclient/regclient/types/platform"
|
||||
)
|
||||
|
||||
const (
|
||||
// MediaTypeOCI1Manifest OCI v1 manifest media type
|
||||
MediaTypeOCI1Manifest = types.MediaTypeOCI1Manifest
|
||||
MediaTypeOCI1Manifest = mediatype.OCI1Manifest
|
||||
// MediaTypeOCI1ManifestList OCI v1 manifest list media type
|
||||
MediaTypeOCI1ManifestList = types.MediaTypeOCI1ManifestList
|
||||
MediaTypeOCI1ManifestList = mediatype.OCI1ManifestList
|
||||
)
|
||||
|
||||
type oci1Manifest struct {
|
||||
@ -43,72 +45,72 @@ type oci1Artifact struct {
|
||||
|
||||
func (m *oci1Manifest) GetAnnotations() (map[string]string, error) {
|
||||
if !m.manifSet {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Annotations, nil
|
||||
}
|
||||
func (m *oci1Manifest) GetConfig() (types.Descriptor, error) {
|
||||
func (m *oci1Manifest) GetConfig() (descriptor.Descriptor, error) {
|
||||
if !m.manifSet {
|
||||
return types.Descriptor{}, types.ErrManifestNotSet
|
||||
return descriptor.Descriptor{}, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Config, nil
|
||||
}
|
||||
func (m *oci1Manifest) GetConfigDigest() (digest.Digest, error) {
|
||||
if !m.manifSet {
|
||||
return digest.Digest(""), types.ErrManifestNotSet
|
||||
return digest.Digest(""), errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Config.Digest, nil
|
||||
}
|
||||
func (m *oci1Index) GetAnnotations() (map[string]string, error) {
|
||||
if !m.manifSet {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Annotations, nil
|
||||
}
|
||||
func (m *oci1Index) GetConfig() (types.Descriptor, error) {
|
||||
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *oci1Index) GetConfig() (descriptor.Descriptor, error) {
|
||||
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) {
|
||||
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) {
|
||||
if !m.manifSet {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Annotations, nil
|
||||
}
|
||||
func (m *oci1Artifact) GetConfig() (types.Descriptor, error) {
|
||||
return types.Descriptor{}, fmt.Errorf("config digest not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *oci1Artifact) GetConfig() (descriptor.Descriptor, error) {
|
||||
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) {
|
||||
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) {
|
||||
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *oci1Manifest) GetManifestList() ([]descriptor.Descriptor, error) {
|
||||
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 {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Manifests, nil
|
||||
}
|
||||
func (m *oci1Artifact) GetManifestList() ([]types.Descriptor, error) {
|
||||
return []types.Descriptor{}, fmt.Errorf("platform descriptor list not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *oci1Artifact) GetManifestList() ([]descriptor.Descriptor, error) {
|
||||
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 {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Layers, nil
|
||||
}
|
||||
func (m *oci1Index) GetLayers() ([]types.Descriptor, error) {
|
||||
return []types.Descriptor{}, fmt.Errorf("layers are not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *oci1Index) GetLayers() ([]descriptor.Descriptor, error) {
|
||||
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 {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Blobs, nil
|
||||
}
|
||||
@ -123,28 +125,28 @@ func (m *oci1Artifact) GetOrig() interface{} {
|
||||
return m.ArtifactManifest
|
||||
}
|
||||
|
||||
func (m *oci1Manifest) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) {
|
||||
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
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, 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 {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
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 {
|
||||
return nil, fmt.Errorf("platform not found: %s%.0w", *p, err)
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
func (m *oci1Artifact) GetPlatformDesc(p *platform.Platform) (*types.Descriptor, error) {
|
||||
return nil, fmt.Errorf("platform lookup not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
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, errs.ErrUnsupportedMediaType)
|
||||
}
|
||||
|
||||
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) {
|
||||
dl, err := m.GetManifestList()
|
||||
@ -154,12 +156,12 @@ func (m *oci1Index) GetPlatformList() ([]*platform.Platform, error) {
|
||||
return getPlatformList(dl)
|
||||
}
|
||||
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) {
|
||||
if !m.manifSet {
|
||||
return []byte{}, types.ErrManifestNotSet
|
||||
return []byte{}, errs.ErrManifestNotSet
|
||||
}
|
||||
|
||||
if len(m.rawBody) > 0 {
|
||||
@ -168,28 +170,28 @@ func (m *oci1Manifest) MarshalJSON() ([]byte, error) {
|
||||
|
||||
return json.Marshal((m.Manifest))
|
||||
}
|
||||
func (m *oci1Manifest) GetSubject() (*types.Descriptor, error) {
|
||||
func (m *oci1Manifest) GetSubject() (*descriptor.Descriptor, error) {
|
||||
if !m.manifSet {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Manifest.Subject, nil
|
||||
}
|
||||
func (m *oci1Index) GetSubject() (*types.Descriptor, error) {
|
||||
func (m *oci1Index) GetSubject() (*descriptor.Descriptor, error) {
|
||||
if !m.manifSet {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.Index.Subject, nil
|
||||
}
|
||||
func (m *oci1Artifact) GetSubject() (*types.Descriptor, error) {
|
||||
func (m *oci1Artifact) GetSubject() (*descriptor.Descriptor, error) {
|
||||
if !m.manifSet {
|
||||
return nil, types.ErrManifestNotSet
|
||||
return nil, errs.ErrManifestNotSet
|
||||
}
|
||||
return m.ArtifactManifest.Subject, nil
|
||||
}
|
||||
|
||||
func (m *oci1Index) MarshalJSON() ([]byte, error) {
|
||||
if !m.manifSet {
|
||||
return []byte{}, types.ErrManifestNotSet
|
||||
return []byte{}, errs.ErrManifestNotSet
|
||||
}
|
||||
|
||||
if len(m.rawBody) > 0 {
|
||||
@ -200,7 +202,7 @@ func (m *oci1Index) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
func (m *oci1Artifact) MarshalJSON() ([]byte, error) {
|
||||
if !m.manifSet {
|
||||
return []byte{}, types.ErrManifestNotSet
|
||||
return []byte{}, errs.ErrManifestNotSet
|
||||
}
|
||||
|
||||
if len(m.rawBody) > 0 {
|
||||
@ -370,7 +372,7 @@ func (m *oci1Artifact) MarshalPretty() ([]byte, error) {
|
||||
|
||||
func (m *oci1Manifest) SetAnnotation(key, val string) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
if m.Annotations == nil {
|
||||
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 {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
if m.Annotations == nil {
|
||||
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 {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
if m.Annotations == nil {
|
||||
m.Annotations = map[string]string{}
|
||||
@ -411,21 +413,21 @@ func (m *oci1Artifact) SetAnnotation(key, val string) error {
|
||||
return m.updateDesc()
|
||||
}
|
||||
|
||||
func (m *oci1Artifact) SetConfig(d types.Descriptor) error {
|
||||
return fmt.Errorf("set config not available for media type %s%.0w", m.desc.MediaType, types.ErrUnsupportedMediaType)
|
||||
func (m *oci1Artifact) SetConfig(d descriptor.Descriptor) error {
|
||||
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 {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.Config = d
|
||||
return m.updateDesc()
|
||||
}
|
||||
|
||||
func (m *oci1Artifact) SetLayers(dl []types.Descriptor) error {
|
||||
func (m *oci1Artifact) SetLayers(dl []descriptor.Descriptor) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.Blobs = dl
|
||||
return m.updateDesc()
|
||||
@ -434,7 +436,7 @@ func (m *oci1Artifact) SetLayers(dl []types.Descriptor) error {
|
||||
// GetSize returns the size in bytes of all layers
|
||||
func (m *oci1Manifest) GetSize() (int64, error) {
|
||||
if !m.manifSet {
|
||||
return 0, types.ErrManifestNotSet
|
||||
return 0, errs.ErrManifestNotSet
|
||||
}
|
||||
var total int64
|
||||
for _, d := range m.Layers {
|
||||
@ -446,7 +448,7 @@ func (m *oci1Manifest) GetSize() (int64, error) {
|
||||
// GetSize returns the size in bytes of all layers
|
||||
func (m *oci1Artifact) GetSize() (int64, error) {
|
||||
if !m.manifSet {
|
||||
return 0, types.ErrManifestNotSet
|
||||
return 0, errs.ErrManifestNotSet
|
||||
}
|
||||
var total int64
|
||||
for _, d := range m.Blobs {
|
||||
@ -455,17 +457,17 @@ func (m *oci1Artifact) GetSize() (int64, error) {
|
||||
return total, nil
|
||||
}
|
||||
|
||||
func (m *oci1Manifest) SetLayers(dl []types.Descriptor) error {
|
||||
func (m *oci1Manifest) SetLayers(dl []descriptor.Descriptor) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.Layers = dl
|
||||
return m.updateDesc()
|
||||
}
|
||||
|
||||
func (m *oci1Index) SetManifestList(dl []types.Descriptor) error {
|
||||
func (m *oci1Index) SetManifestList(dl []descriptor.Descriptor) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.Manifests = dl
|
||||
return m.updateDesc()
|
||||
@ -474,11 +476,11 @@ func (m *oci1Index) SetManifestList(dl []types.Descriptor) error {
|
||||
func (m *oci1Manifest) SetOrig(origIn interface{}) error {
|
||||
orig, ok := origIn.(v1.Manifest)
|
||||
if !ok {
|
||||
return types.ErrUnsupportedMediaType
|
||||
return errs.ErrUnsupportedMediaType
|
||||
}
|
||||
if orig.MediaType != types.MediaTypeOCI1Manifest {
|
||||
if orig.MediaType != mediatype.OCI1Manifest {
|
||||
// TODO: error?
|
||||
orig.MediaType = types.MediaTypeOCI1Manifest
|
||||
orig.MediaType = mediatype.OCI1Manifest
|
||||
}
|
||||
m.manifSet = true
|
||||
m.Manifest = orig
|
||||
@ -489,11 +491,11 @@ func (m *oci1Manifest) SetOrig(origIn interface{}) error {
|
||||
func (m *oci1Index) SetOrig(origIn interface{}) error {
|
||||
orig, ok := origIn.(v1.Index)
|
||||
if !ok {
|
||||
return types.ErrUnsupportedMediaType
|
||||
return errs.ErrUnsupportedMediaType
|
||||
}
|
||||
if orig.MediaType != types.MediaTypeOCI1ManifestList {
|
||||
if orig.MediaType != mediatype.OCI1ManifestList {
|
||||
// TODO: error?
|
||||
orig.MediaType = types.MediaTypeOCI1ManifestList
|
||||
orig.MediaType = mediatype.OCI1ManifestList
|
||||
}
|
||||
m.manifSet = true
|
||||
m.Index = orig
|
||||
@ -501,23 +503,23 @@ func (m *oci1Index) SetOrig(origIn interface{}) error {
|
||||
return m.updateDesc()
|
||||
}
|
||||
|
||||
func (m *oci1Artifact) SetSubject(d *types.Descriptor) error {
|
||||
func (m *oci1Artifact) SetSubject(d *descriptor.Descriptor) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.ArtifactManifest.Subject = d
|
||||
return m.updateDesc()
|
||||
}
|
||||
func (m *oci1Manifest) SetSubject(d *types.Descriptor) error {
|
||||
func (m *oci1Manifest) SetSubject(d *descriptor.Descriptor) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.Manifest.Subject = d
|
||||
return m.updateDesc()
|
||||
}
|
||||
func (m *oci1Index) SetSubject(d *types.Descriptor) error {
|
||||
func (m *oci1Index) SetSubject(d *descriptor.Descriptor) error {
|
||||
if !m.manifSet {
|
||||
return types.ErrManifestNotSet
|
||||
return errs.ErrManifestNotSet
|
||||
}
|
||||
m.Index.Subject = d
|
||||
return m.updateDesc()
|
||||
@ -526,11 +528,11 @@ func (m *oci1Index) SetSubject(d *types.Descriptor) error {
|
||||
func (m *oci1Artifact) SetOrig(origIn interface{}) error {
|
||||
orig, ok := origIn.(v1.ArtifactManifest)
|
||||
if !ok {
|
||||
return types.ErrUnsupportedMediaType
|
||||
return errs.ErrUnsupportedMediaType
|
||||
}
|
||||
if orig.MediaType != types.MediaTypeOCI1Artifact {
|
||||
if orig.MediaType != mediatype.OCI1Artifact {
|
||||
// TODO: error?
|
||||
orig.MediaType = types.MediaTypeOCI1Artifact
|
||||
orig.MediaType = mediatype.OCI1Artifact
|
||||
}
|
||||
m.manifSet = true
|
||||
m.ArtifactManifest = orig
|
||||
@ -544,8 +546,8 @@ func (m *oci1Manifest) updateDesc() error {
|
||||
return err
|
||||
}
|
||||
m.rawBody = mj
|
||||
m.desc = types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Manifest,
|
||||
m.desc = descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Manifest,
|
||||
Digest: digest.FromBytes(mj),
|
||||
Size: int64(len(mj)),
|
||||
}
|
||||
@ -557,8 +559,8 @@ func (m *oci1Index) updateDesc() error {
|
||||
return err
|
||||
}
|
||||
m.rawBody = mj
|
||||
m.desc = types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1ManifestList,
|
||||
m.desc = descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1ManifestList,
|
||||
Digest: digest.FromBytes(mj),
|
||||
Size: int64(len(mj)),
|
||||
}
|
||||
@ -570,8 +572,8 @@ func (m *oci1Artifact) updateDesc() error {
|
||||
return err
|
||||
}
|
||||
m.rawBody = mj
|
||||
m.desc = types.Descriptor{
|
||||
MediaType: types.MediaTypeOCI1Artifact,
|
||||
m.desc = descriptor.Descriptor{
|
||||
MediaType: mediatype.OCI1Artifact,
|
||||
Digest: digest.FromBytes(mj),
|
||||
Size: int64(len(mj)),
|
||||
}
|
||||
|
@ -1,50 +1,91 @@
|
||||
package types
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"github.com/regclient/regclient/types/mediatype"
|
||||
)
|
||||
|
||||
const (
|
||||
// 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 = "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 = "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 = "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 = "application/vnd.docker.container.image.v1+json"
|
||||
//
|
||||
// Deprecated: replace with [mediatype.Docker2ImageConfig].
|
||||
MediaTypeDocker2ImageConfig = mediatype.Docker2ImageConfig
|
||||
// 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 = "application/vnd.oci.image.manifest.v1+json"
|
||||
//
|
||||
// Deprecated: replace with [mediatype.OCI1Manifest].
|
||||
MediaTypeOCI1Manifest = mediatype.OCI1Manifest
|
||||
// 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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "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 = "application/vnd.oci.empty.v1+json"
|
||||
//
|
||||
// Deprecated: replace with [mediatype.OCI1Empty].
|
||||
MediaTypeOCI1Empty = mediatype.OCI1Empty
|
||||
// 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.
|
||||
func MediaTypeBase(orig string) string {
|
||||
base, _, _ := strings.Cut(orig, ";")
|
||||
return strings.TrimSpace(strings.ToLower(base))
|
||||
}
|
||||
var (
|
||||
// Base cleans the Content-Type header to return only the lower case base media type.
|
||||
//
|
||||
// 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"
|
||||
|
||||
@ -11,19 +11,19 @@ func TestMediaTypeBase(t *testing.T) {
|
||||
}{
|
||||
{
|
||||
name: "OCI Index",
|
||||
orig: MediaTypeOCI1ManifestList,
|
||||
expect: MediaTypeOCI1ManifestList,
|
||||
orig: OCI1ManifestList,
|
||||
expect: OCI1ManifestList,
|
||||
},
|
||||
{
|
||||
name: "OCI Index with charset",
|
||||
orig: "application/vnd.oci.image.index.v1+json; charset=utf-8",
|
||||
expect: MediaTypeOCI1ManifestList,
|
||||
expect: OCI1ManifestList,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
result := MediaTypeBase(tc.orig)
|
||||
result := Base(tc.orig)
|
||||
if tc.expect != result {
|
||||
t.Errorf("invalid result: expected \"%s\", received \"%s\"", tc.expect, result)
|
||||
}
|
@ -1,8 +1,6 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/regclient/regclient/types"
|
||||
)
|
||||
import "github.com/regclient/regclient/types/descriptor"
|
||||
|
||||
// ArtifactManifest EXPERIMENTAL defines an OCI Artifact
|
||||
type ArtifactManifest struct {
|
||||
@ -13,10 +11,10 @@ type ArtifactManifest struct {
|
||||
ArtifactType string `json:"artifactType,omitempty"`
|
||||
|
||||
// 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 *types.Descriptor `json:"subject,omitempty"`
|
||||
Subject *descriptor.Descriptor `json:"subject,omitempty"`
|
||||
|
||||
// Annotations contains arbitrary metadata for the artifact manifest.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
|
@ -1,7 +1,7 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/oci"
|
||||
)
|
||||
|
||||
@ -22,10 +22,10 @@ type Index struct {
|
||||
ArtifactType string `json:"artifactType,omitempty"`
|
||||
|
||||
// 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 *types.Descriptor `json:"subject,omitempty"`
|
||||
Subject *descriptor.Descriptor `json:"subject,omitempty"`
|
||||
|
||||
// Annotations contains arbitrary metadata for the image index.
|
||||
Annotations map[string]string `json:"annotations,omitempty"`
|
||||
|
@ -1,7 +1,7 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/regclient/regclient/types"
|
||||
"github.com/regclient/regclient/types/descriptor"
|
||||
"github.com/regclient/regclient/types/oci"
|
||||
)
|
||||
|
||||
@ -22,13 +22,13 @@ type Manifest struct {
|
||||
|
||||
// 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.
|
||||
Config types.Descriptor `json:"config"`
|
||||
Config descriptor.Descriptor `json:"config"`
|
||||
|
||||
// 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 *types.Descriptor `json:"subject,omitempty"`
|
||||
Subject *descriptor.Descriptor `json:"subject,omitempty"`
|
||||
|
||||
// Annotations contains arbitrary metadata for the image manifest.
|
||||
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