1
0
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:
Brandon Mitchell 2024-03-04 15:43:18 -05:00
parent b991f53ad7
commit eea06e2a5c
No known key found for this signature in database
GPG Key ID: 6E0FF28C767A8BEE
108 changed files with 2529 additions and 1721 deletions

36
blob.go
View File

@ -14,6 +14,8 @@ import (
"github.com/regclient/regclient/scheme"
"github.com/regclient/regclient/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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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

View File

@ -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",

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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)

View File

@ -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",

View File

@ -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",

View File

@ -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

View File

@ -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",

View File

@ -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
View File

@ -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()))
}

View File

@ -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",

View File

@ -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

View File

@ -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
)

View File

@ -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() {

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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 {

View File

@ -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)
}
}

View File

@ -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

View File

@ -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
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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)
}
})

View File

@ -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 != "" {

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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")
}
})

View File

@ -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 {

View File

@ -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
)

View File

@ -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
)

View File

@ -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
)

View File

@ -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
)

View File

@ -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))
}

View File

@ -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
)

View File

@ -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
)

View File

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

View File

@ -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
)

View File

@ -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
)

View File

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

View File

@ -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

View File

@ -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...)
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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))
}
}

View File

@ -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")

View File

@ -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

View File

@ -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,
},

View File

@ -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

View File

@ -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)
}

View File

@ -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),
)

View File

@ -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"

View File

@ -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 := &reghttp.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 := &reghttp.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 := &reghttp.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

View File

@ -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)
}

View File

@ -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 := &reghttp.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 := &reghttp.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

View File

@ -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)
}
})
}

View File

@ -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")

View File

@ -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

View File

@ -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)
}

View File

@ -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),

View File

@ -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

View File

@ -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)
}

View File

@ -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)
}
})

View File

@ -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
View File

@ -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 {

View File

@ -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
}

View File

@ -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)
}
})
}

View File

@ -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
}

View File

@ -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))

View File

@ -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

View File

@ -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 {

View File

@ -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
)

View File

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

View File

@ -1,4 +1,4 @@
package types
package descriptor
import (
"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",

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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
View File

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

View File

@ -12,12 +12,14 @@ import (
digest "github.com/opencontainers/go-digest"
"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
}

View File

@ -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)),
}

View File

@ -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)),
}

View File

@ -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 {

View File

@ -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)),
}),

View File

@ -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)),
}

View File

@ -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
)

View File

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

View File

@ -1,4 +1,4 @@
package types
package mediatype
import "testing"
@ -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)
}

View File

@ -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"`

View File

@ -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"`

View File

@ -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