package cache import ( "errors" "fmt" "io" v1 "github.com/google/go-containerregistry/pkg/v1" "edge-infra.dev/pkg/f8n/warehouse/oci/layer" ) // cachingImage wraps access to v1.Image with a [Cache]. Implements v1.Image type cachingImage struct { v1.Image cache *LazyCache } // Image returns a new v1.Image backed by a [cachingImage]. OCI interface methods will read // from a [Cache] if found, falling back to wrapped inner implementation if not. Most likely, // inner Image will be a remoteImage. func Image(i v1.Image, c *LazyCache) v1.Image { return &cachingImage{ Image: i, cache: c, } } func (c *cachingImage) Layers() ([]v1.Layer, error) { m, err := c.Image.Manifest() if err != nil { return nil, err } layers := make([]v1.Layer, 0, len(m.Layers)) for _, desc := range m.Layers { l, err := c.LayerByDigest(desc.Digest) if err != nil { return nil, err } layers = append(layers, l) } return layers, nil } func (c *cachingImage) RawConfigFile() ([]byte, error) { manifest, err := c.Image.Manifest() if err != nil { return nil, err } h := manifest.Config.Digest if cached, err := c.cache.getLayer(h); err == nil { rc, err := cached.Uncompressed() if err != nil { return nil, err } defer rc.Close() return io.ReadAll(rc) } else if !errors.Is(err, ErrNotFound) { return nil, err } raw, err := c.Image.RawConfigFile() if err != nil { return nil, err } c.cache.putBlob(h, raw) return raw, nil } // LayerByDigest returns a Layer for interacting with a particular layer of // the image, looking it up by "digest" (the compressed hash). func (c *cachingImage) LayerByDigest(h v1.Hash) (v1.Layer, error) { if cached, err := c.cache.getLayer(h); err == nil { return cached, nil } else if !errors.Is(err, ErrNotFound) { return nil, err } l, err := c.Image.LayerByDigest(h) if err != nil { return nil, err } ll, err := layer.FromOCILayer(l) if err != nil { return nil, fmt.Errorf("failed to convert OCI Layer to Warehouse Layer. error: %v", err) } return c.cache.putLayer(ll) } // TODO(dk185217): make sense of diffid vs digest func (c *cachingImage) LayerByDiffID(h v1.Hash) (v1.Layer, error) { return c.LayerByDigest(h) }