1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
|
package imagemetaresolver
import (
"context"
"net/http"
"sync"
"github.com/containerd/containerd/platforms"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/client/llb/sourceresolver"
"github.com/moby/buildkit/util/contentutil"
"github.com/moby/buildkit/util/imageutil"
"github.com/moby/buildkit/version"
"github.com/moby/locker"
digest "github.com/opencontainers/go-digest"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
)
var defaultImageMetaResolver llb.ImageMetaResolver
var defaultImageMetaResolverOnce sync.Once
var WithDefault = imageOptionFunc(func(ii *llb.ImageInfo) {
llb.WithMetaResolver(Default()).SetImageOption(ii)
})
type imageMetaResolverOpts struct {
platform *ocispecs.Platform
}
type ImageMetaResolverOpt func(o *imageMetaResolverOpts)
func WithDefaultPlatform(p *ocispecs.Platform) ImageMetaResolverOpt {
return func(o *imageMetaResolverOpts) {
o.platform = p
}
}
func New(with ...ImageMetaResolverOpt) llb.ImageMetaResolver {
var opts imageMetaResolverOpts
for _, f := range with {
f(&opts)
}
headers := http.Header{}
headers.Set("User-Agent", version.UserAgent())
return &imageMetaResolver{
resolver: docker.NewResolver(docker.ResolverOptions{
Headers: headers,
}),
platform: opts.platform,
buffer: contentutil.NewBuffer(),
cache: map[string]resolveResult{},
locker: locker.New(),
}
}
func Default() llb.ImageMetaResolver {
defaultImageMetaResolverOnce.Do(func() {
defaultImageMetaResolver = New()
})
return defaultImageMetaResolver
}
type imageMetaResolver struct {
resolver remotes.Resolver
buffer contentutil.Buffer
platform *ocispecs.Platform
locker *locker.Locker
cache map[string]resolveResult
}
type resolveResult struct {
config []byte
dgst digest.Digest
}
func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, opt sourceresolver.Opt) (string, digest.Digest, []byte, error) {
imr.locker.Lock(ref)
defer imr.locker.Unlock(ref)
platform := imr.platform
if opt.Platform != nil {
platform = opt.Platform
}
k := imr.key(ref, platform)
if res, ok := imr.cache[k]; ok {
return ref, res.dgst, res.config, nil
}
dgst, config, err := imageutil.Config(ctx, ref, imr.resolver, imr.buffer, nil, platform)
if err != nil {
return "", "", nil, err
}
imr.cache[k] = resolveResult{dgst: dgst, config: config}
return ref, dgst, config, nil
}
func (imr *imageMetaResolver) key(ref string, platform *ocispecs.Platform) string {
if platform != nil {
ref += platforms.Format(*platform)
}
return ref
}
type imageOptionFunc func(*llb.ImageInfo)
func (fn imageOptionFunc) SetImageOption(ii *llb.ImageInfo) {
fn(ii)
}
|