// Package scheme defines the interface for various reference schemes. package scheme import ( "context" "io" "github.com/regclient/regclient/internal/pqueue" "github.com/regclient/regclient/internal/reqmeta" "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" "github.com/regclient/regclient/types/referrer" "github.com/regclient/regclient/types/tag" ) // 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 descriptor.Descriptor) error // BlobGet retrieves a blob, returning a reader. 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 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 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 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 // ManifestGet retrieves a manifest from a repository. ManifestGet(ctx context.Context, r ref.Ref) (manifest.Manifest, error) // ManifestHead gets metadata about the manifest (existence, digest, mediatype, size). ManifestHead(ctx context.Context, r ref.Ref) (manifest.Manifest, error) // ManifestPut sends a manifest to the repository. ManifestPut(ctx context.Context, r ref.Ref, m manifest.Manifest, opts ...ManifestOpts) error // Ping verifies access to a registry or equivalent. Ping(ctx context.Context, r ref.Ref) (ping.Result, error) // ReferrerList returns a list of referrers to a given reference. ReferrerList(ctx context.Context, r ref.Ref, opts ...ReferrerOpts) (referrer.ReferrerList, error) // TagDelete removes a tag from the repository. TagDelete(ctx context.Context, r ref.Ref) error // TagList returns a list of tags from the repository. TagList(ctx context.Context, r ref.Ref, opts ...TagOpts) (*tag.List, error) } // Closer is used to check if a scheme implements the Close API. type Closer interface { Close(ctx context.Context, r ref.Ref) error } // GCLocker is used to indicate locking is available for GC management. type GCLocker interface { // GCLock a reference to prevent GC from triggering during a put, locks are not exclusive. GCLock(r ref.Ref) // GCUnlock a reference to allow GC (once all locks are released). // The reference should be closed after this step and unlock should only be called once per each Lock call. GCUnlock(r ref.Ref) } // Throttler is used to indicate the scheme implements Throttle. type Throttler interface { Throttle(r ref.Ref, put bool) []*pqueue.Queue[reqmeta.Data] } // ManifestConfig is used by schemes to import [ManifestOpts]. type ManifestConfig struct { CheckReferrers bool Child bool // used when pushing a child of a manifest list, skips indexing in ocidir Manifest manifest.Manifest } // ManifestOpts is used to set options on manifest APIs. type ManifestOpts func(*ManifestConfig) // WithManifestCheckReferrers is used when deleting a manifest. // It indicates the manifest should be fetched and referrers should be deleted if defined. func WithManifestCheckReferrers() ManifestOpts { return func(config *ManifestConfig) { config.CheckReferrers = true } } // WithManifestChild indicates the API call is on a child manifest. // This is used internally when copying multi-platform manifests. // This bypasses tracking of an untagged digest in ocidir which is needed for garbage collection. func WithManifestChild() ManifestOpts { return func(config *ManifestConfig) { config.Child = true } } // WithManifest is used to pass the manifest to a method to avoid an extra GET request. // This is used on a delete to check for referrers. func WithManifest(m manifest.Manifest) ManifestOpts { return func(mc *ManifestConfig) { mc.Manifest = m } } // ReferrerConfig is used by schemes to import [ReferrerOpts]. type ReferrerConfig struct { MatchOpt descriptor.MatchOpt // filter/sort results Platform string // get referrers for a specific platform SrcRepo ref.Ref // repo used to query referrers } // ReferrerOpts is used to set options on referrer APIs. type ReferrerOpts func(*ReferrerConfig) // WithReferrerMatchOpt filters results using [descriptor.MatchOpt]. func WithReferrerMatchOpt(mo descriptor.MatchOpt) ReferrerOpts { return func(config *ReferrerConfig) { config.MatchOpt = mo } } // WithReferrerPlatform gets referrers for a single platform from a multi-platform manifest. // Note that this is implemented by [regclient.ReferrerList] and not the individual scheme implementations. func WithReferrerPlatform(p string) ReferrerOpts { return func(config *ReferrerConfig) { config.Platform = p } } // WithReferrerSource pulls referrers from a separate source. // Note that this is implemented by [regclient.ReferrerList] and not the individual scheme implementations. func WithReferrerSource(r ref.Ref) ReferrerOpts { return func(config *ReferrerConfig) { config.SrcRepo = r } } // WithReferrerAT filters by a specific artifactType value. // // Deprecated: replace with [WithReferrerMatchOpt]. func WithReferrerAT(at string) ReferrerOpts { return func(config *ReferrerConfig) { config.MatchOpt.ArtifactType = at } } // WithReferrerAnnotations filters by a list of annotations, all of which must match. // // Deprecated: replace with [WithReferrerMatchOpt]. func WithReferrerAnnotations(annotations map[string]string) ReferrerOpts { return func(config *ReferrerConfig) { if config.MatchOpt.Annotations == nil { config.MatchOpt.Annotations = annotations } else { for k, v := range annotations { config.MatchOpt.Annotations[k] = v } } } } // WithReferrerSort orders the resulting referrers listing according to a specified annotation. // // Deprecated: replace with [WithReferrerMatchOpt]. func WithReferrerSort(annotation string, desc bool) ReferrerOpts { return func(config *ReferrerConfig) { config.MatchOpt.SortAnnotation = annotation config.MatchOpt.SortDesc = desc } } // ReferrerFilter filters the referrer list according to the config. func ReferrerFilter(config ReferrerConfig, rlIn referrer.ReferrerList) referrer.ReferrerList { return referrer.ReferrerList{ Subject: rlIn.Subject, Source: rlIn.Source, Manifest: rlIn.Manifest, Annotations: rlIn.Annotations, Tags: rlIn.Tags, Descriptors: descriptor.DescriptorListFilter(rlIn.Descriptors, config.MatchOpt), } } // RepoConfig is used by schemes to import [RepoOpts]. type RepoConfig struct { Limit int Last string } // RepoOpts is used to set options on repo APIs. type RepoOpts func(*RepoConfig) // WithRepoLimit passes a maximum number of repositories to return to the repository list API. // Registries may ignore this. func WithRepoLimit(l int) RepoOpts { return func(config *RepoConfig) { config.Limit = l } } // WithRepoLast passes the last received repository for requesting the next batch of repositories. // Registries may ignore this. func WithRepoLast(l string) RepoOpts { return func(config *RepoConfig) { config.Last = l } } // TagConfig is used by schemes to import [TagOpts]. type TagConfig struct { Limit int Last string } // TagOpts is used to set options on tag APIs. type TagOpts func(*TagConfig) // WithTagLimit passes a maximum number of tags to return to the tag list API. // Registries may ignore this. func WithTagLimit(limit int) TagOpts { return func(t *TagConfig) { t.Limit = limit } } // WithTagLast passes the last received tag for requesting the next batch of tags. // Registries may ignore this. func WithTagLast(last string) TagOpts { return func(t *TagConfig) { t.Last = last } }