From 62365aa5e648e161e4fed5ecd8f10c7e7ddc3452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Gronowski?= Date: Wed, 14 Feb 2024 13:06:43 +0100 Subject: [PATCH] util/multiprovider: Implement Info MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Require base provides to implement both content.InfoReaderProvider. Signed-off-by: Paweł Gronowski --- cache/remote.go | 17 ++++++++++++++++- cache/remotecache/v1/chains.go | 15 +++++++++++++++ cache/remotecache/v1/parse.go | 6 +++--- solver/types.go | 2 +- util/contentutil/multiprovider.go | 24 +++++++++++++++++++----- 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/cache/remote.go b/cache/remote.go index 0607c7aab..639aa7dbf 100644 --- a/cache/remote.go +++ b/cache/remote.go @@ -18,6 +18,7 @@ import ( "github.com/moby/buildkit/util/leaseutil" "github.com/moby/buildkit/util/progress/logs" "github.com/moby/buildkit/util/pull/pullprogress" + digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sync/errgroup" @@ -85,7 +86,7 @@ func (sr *immutableRef) GetRemotes(ctx context.Context, createIfNeeded bool, ref return res, nil } -func appendRemote(parents []*solver.Remote, desc ocispecs.Descriptor, p content.Provider) (res []*solver.Remote) { +func appendRemote(parents []*solver.Remote, desc ocispecs.Descriptor, p content.InfoReaderProvider) (res []*solver.Remote) { for _, pRemote := range parents { provider := contentutil.NewMultiProvider(pRemote.Provider) provider.Add(desc.Digest, p) @@ -276,6 +277,10 @@ func (mp *lazyMultiProvider) ReaderAt(ctx context.Context, desc ocispecs.Descrip return mp.mprovider.ReaderAt(ctx, desc) } +func (mp *lazyMultiProvider) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) { + return mp.mprovider.Info(ctx, dgst) +} + func (mp *lazyMultiProvider) Unlazy(ctx context.Context) error { eg, egctx := errgroup.WithContext(ctx) for _, p := range mp.plist { @@ -304,6 +309,16 @@ func (p lazyRefProvider) ReaderAt(ctx context.Context, desc ocispecs.Descriptor) return p.ref.cm.ContentStore.ReaderAt(ctx, desc) } +func (p lazyRefProvider) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) { + if dgst != p.desc.Digest { + return content.Info{}, errdefs.ErrNotFound + } + if err := p.Unlazy(ctx); err != nil { + return content.Info{}, errdefs.ErrNotFound + } + return p.ref.cm.ContentStore.Info(ctx, dgst) +} + func (p lazyRefProvider) Unlazy(ctx context.Context) error { _, err := p.ref.cm.unlazyG.Do(ctx, string(p.desc.Digest), func(ctx context.Context) (_ struct{}, rerr error) { if isLazy, err := p.ref.isLazy(ctx); err != nil { diff --git a/cache/remotecache/v1/chains.go b/cache/remotecache/v1/chains.go index 8eac0da89..c92ffc318 100644 --- a/cache/remotecache/v1/chains.go +++ b/cache/remotecache/v1/chains.go @@ -10,6 +10,7 @@ import ( "github.com/moby/buildkit/solver" digest "github.com/opencontainers/go-digest" ocispecs "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/pkg/errors" ) func NewCacheChains() *CacheChains { @@ -120,6 +121,20 @@ type DescriptorProviderPair struct { Provider content.Provider } +func (p DescriptorProviderPair) ReaderAt(ctx context.Context, desc ocispecs.Descriptor) (content.ReaderAt, error) { + return p.Provider.ReaderAt(ctx, desc) +} + +func (p DescriptorProviderPair) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) { + if dgst != p.Descriptor.Digest { + return content.Info{}, errors.Errorf("content not found %s", dgst) + } + return content.Info{ + Digest: p.Descriptor.Digest, + Size: p.Descriptor.Size, + }, nil +} + // item is an implementation of a record in the cache chain. After validation, // normalization and marshalling into the cache config, the item results form // into the "layers", while the digests and the links form into the "records". diff --git a/cache/remotecache/v1/parse.go b/cache/remotecache/v1/parse.go index 3c8294a60..44b1645b9 100644 --- a/cache/remotecache/v1/parse.go +++ b/cache/remotecache/v1/parse.go @@ -82,7 +82,7 @@ func parseRecord(cc CacheConfig, idx int, provider DescriptorProvider, t solver. } remote.Descriptors = append(remote.Descriptors, descPair.Descriptor) - mp.Add(descPair.Descriptor.Digest, descPair.Provider) + mp.Add(descPair.Descriptor.Digest, descPair) } if remote != nil { remote.Provider = mp @@ -123,12 +123,12 @@ func getRemoteChain(layers []CacheLayer, idx int, provider DescriptorProvider, v } r.Descriptors = append(r.Descriptors, descPair.Descriptor) mp := contentutil.NewMultiProvider(r.Provider) - mp.Add(descPair.Descriptor.Digest, descPair.Provider) + mp.Add(descPair.Descriptor.Digest, descPair) r.Provider = mp return r, nil } return &solver.Remote{ Descriptors: []ocispecs.Descriptor{descPair.Descriptor}, - Provider: descPair.Provider, + Provider: descPair, }, nil } diff --git a/solver/types.go b/solver/types.go index 8357676cd..d7e47321b 100644 --- a/solver/types.go +++ b/solver/types.go @@ -142,7 +142,7 @@ type CacheExporterRecord interface { // TODO: add closer to keep referenced data from getting deleted type Remote struct { Descriptors []ocispecs.Descriptor - Provider content.Provider + Provider content.InfoReaderProvider } // CacheLink is a link between two cache records diff --git a/util/contentutil/multiprovider.go b/util/contentutil/multiprovider.go index aba096d7c..f61f33d5e 100644 --- a/util/contentutil/multiprovider.go +++ b/util/contentutil/multiprovider.go @@ -13,18 +13,18 @@ import ( ) // NewMultiProvider creates a new mutable provider with a base provider -func NewMultiProvider(base content.Provider) *MultiProvider { +func NewMultiProvider(base content.InfoReaderProvider) *MultiProvider { return &MultiProvider{ base: base, - sub: map[digest.Digest]content.Provider{}, + sub: map[digest.Digest]content.InfoReaderProvider{}, } } // MultiProvider is a provider backed by a mutable map of providers type MultiProvider struct { mu sync.RWMutex - base content.Provider - sub map[digest.Digest]content.Provider + base content.InfoReaderProvider + sub map[digest.Digest]content.InfoReaderProvider } func (mp *MultiProvider) SnapshotLabels(descs []ocispecs.Descriptor, index int) map[string]string { @@ -85,8 +85,22 @@ func (mp *MultiProvider) ReaderAt(ctx context.Context, desc ocispecs.Descriptor) return mp.base.ReaderAt(ctx, desc) } +// Info returns a content.Info +func (mp *MultiProvider) Info(ctx context.Context, dgst digest.Digest) (content.Info, error) { + mp.mu.RLock() + if p, ok := mp.sub[dgst]; ok { + mp.mu.RUnlock() + return p.Info(ctx, dgst) + } + mp.mu.RUnlock() + if mp.base == nil { + return content.Info{}, errors.Wrapf(errdefs.ErrNotFound, "content %v", dgst) + } + return mp.base.Info(ctx, dgst) +} + // Add adds a new child provider for a specific digest -func (mp *MultiProvider) Add(dgst digest.Digest, p content.Provider) { +func (mp *MultiProvider) Add(dgst digest.Digest, p content.InfoReaderProvider) { mp.mu.Lock() defer mp.mu.Unlock() mp.sub[dgst] = p