Little helper to run CNCF's k3s in Docker
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
k3d/vendor/github.com/google/go-containerregistry/pkg/v1/remote/puller.go

222 lines
5.4 KiB

// Copyright 2023 Google LLC All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package remote
import (
"context"
"sync"
"github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/partial"
"github.com/google/go-containerregistry/pkg/v1/types"
)
type Puller struct {
o *options
// map[resource]*reader
readers sync.Map
}
func NewPuller(options ...Option) (*Puller, error) {
o, err := makeOptions(options...)
if err != nil {
return nil, err
}
return newPuller(o), nil
}
func newPuller(o *options) *Puller {
if o.puller != nil {
return o.puller
}
return &Puller{
o: o,
}
}
type reader struct {
// in
target resource
o *options
// f()
once sync.Once
// out
f *fetcher
err error
}
// this will run once per reader instance
func (r *reader) init(ctx context.Context) error {
r.once.Do(func() {
r.f, r.err = makeFetcher(ctx, r.target, r.o)
})
return r.err
}
func (p *Puller) fetcher(ctx context.Context, target resource) (*fetcher, error) {
v, _ := p.readers.LoadOrStore(target, &reader{
target: target,
o: p.o,
})
rr := v.(*reader)
return rr.f, rr.init(ctx)
}
// Head is like remote.Head, but avoids re-authenticating when possible.
func (p *Puller) Head(ctx context.Context, ref name.Reference) (*v1.Descriptor, error) {
f, err := p.fetcher(ctx, ref.Context())
if err != nil {
return nil, err
}
return f.headManifest(ctx, ref, allManifestMediaTypes)
}
// Get is like remote.Get, but avoids re-authenticating when possible.
func (p *Puller) Get(ctx context.Context, ref name.Reference) (*Descriptor, error) {
return p.get(ctx, ref, allManifestMediaTypes, p.o.platform)
}
func (p *Puller) get(ctx context.Context, ref name.Reference, acceptable []types.MediaType, platform v1.Platform) (*Descriptor, error) {
f, err := p.fetcher(ctx, ref.Context())
if err != nil {
return nil, err
}
return f.get(ctx, ref, acceptable, platform)
}
// Layer is like remote.Layer, but avoids re-authenticating when possible.
func (p *Puller) Layer(ctx context.Context, ref name.Digest) (v1.Layer, error) {
f, err := p.fetcher(ctx, ref.Context())
if err != nil {
return nil, err
}
h, err := v1.NewHash(ref.Identifier())
if err != nil {
return nil, err
}
l, err := partial.CompressedToLayer(&remoteLayer{
fetcher: *f,
ctx: ctx,
digest: h,
})
if err != nil {
return nil, err
}
return &MountableLayer{
Layer: l,
Reference: ref,
}, nil
}
// List lists tags in a repo and handles pagination, returning the full list of tags.
func (p *Puller) List(ctx context.Context, repo name.Repository) ([]string, error) {
lister, err := p.Lister(ctx, repo)
if err != nil {
return nil, err
}
tagList := []string{}
for lister.HasNext() {
tags, err := lister.Next(ctx)
if err != nil {
return nil, err
}
tagList = append(tagList, tags.Tags...)
}
return tagList, nil
}
// Lister lists tags in a repo and returns a Lister for paginating through the results.
func (p *Puller) Lister(ctx context.Context, repo name.Repository) (*Lister, error) {
return p.lister(ctx, repo, p.o.pageSize)
}
func (p *Puller) lister(ctx context.Context, repo name.Repository, pageSize int) (*Lister, error) {
f, err := p.fetcher(ctx, repo)
if err != nil {
return nil, err
}
page, err := f.listPage(ctx, repo, "", pageSize)
if err != nil {
return nil, err
}
return &Lister{
f: f,
repo: repo,
pageSize: pageSize,
page: page,
err: err,
}, nil
}
// Catalog lists repos in a registry and handles pagination, returning the full list of repos.
func (p *Puller) Catalog(ctx context.Context, reg name.Registry) ([]string, error) {
return p.catalog(ctx, reg, p.o.pageSize)
}
func (p *Puller) catalog(ctx context.Context, reg name.Registry, pageSize int) ([]string, error) {
catalogger, err := p.catalogger(ctx, reg, pageSize)
if err != nil {
return nil, err
}
repoList := []string{}
for catalogger.HasNext() {
repos, err := catalogger.Next(ctx)
if err != nil {
return nil, err
}
repoList = append(repoList, repos.Repos...)
}
return repoList, nil
}
// Catalogger lists repos in a registry and returns a Catalogger for paginating through the results.
func (p *Puller) Catalogger(ctx context.Context, reg name.Registry) (*Catalogger, error) {
return p.catalogger(ctx, reg, p.o.pageSize)
}
func (p *Puller) catalogger(ctx context.Context, reg name.Registry, pageSize int) (*Catalogger, error) {
f, err := p.fetcher(ctx, reg)
if err != nil {
return nil, err
}
page, err := f.catalogPage(ctx, reg, "", pageSize)
if err != nil {
return nil, err
}
return &Catalogger{
f: f,
reg: reg,
pageSize: pageSize,
page: page,
err: err,
}, nil
}
func (p *Puller) referrers(ctx context.Context, d name.Digest, filter map[string]string) (v1.ImageIndex, error) {
f, err := p.fetcher(ctx, d.Context())
if err != nil {
return nil, err
}
return f.fetchReferrers(ctx, filter, d)
}