1
0
mirror of https://github.com/regclient/regclient.git synced 2025-04-18 22:44:00 +03:00
regclient/scheme/scheme.go
Brandon Mitchell 763599514d
Feat: Include source in referrers response
This simplifies handling external sources.

Signed-off-by: Brandon Mitchell <git@bmitch.net>
2024-12-03 17:12:10 -05:00

235 lines
8.2 KiB
Go

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