91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
package image
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/buildpacks/imgutil"
|
|
"github.com/buildpacks/imgutil/layout"
|
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
|
)
|
|
|
|
const LayoutKind = "layout"
|
|
|
|
type LayoutHandler struct {
|
|
layoutDir string
|
|
}
|
|
|
|
func (h *LayoutHandler) InitImage(imageRef string) (imgutil.Image, error) {
|
|
if imageRef == "" {
|
|
return nil, nil
|
|
}
|
|
|
|
path, err := h.parseRef(imageRef)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return layout.NewImage(path, layout.FromBaseImagePath(path))
|
|
}
|
|
|
|
func (h *LayoutHandler) Kind() string {
|
|
return LayoutKind
|
|
}
|
|
|
|
func (h *LayoutHandler) parseRef(imageRef string) (string, error) {
|
|
if !strings.HasPrefix(imageRef, h.layoutDir) {
|
|
path, err := layout.ParseRefToPath(imageRef)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return filepath.Join(h.layoutDir, path), nil
|
|
}
|
|
return imageRef, nil
|
|
}
|
|
|
|
// helpers
|
|
|
|
// FromLayoutPath takes a path to a directory (such as <layers>/extended/run) containing a single image in "sparse" OCI layout format,
|
|
// and returns a v1.Image along with the path of the image (such as <layers>/extended/run/sha256:<sha256>)
|
|
// or an error if the image cannot be loaded.
|
|
// The path is helpful for locating the image when we only know the digest of the config, such as for local images.
|
|
func FromLayoutPath(parentPath string) (v1.Image, string, error) {
|
|
fis, err := os.ReadDir(parentPath)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, "", nil
|
|
}
|
|
return nil, "", err
|
|
}
|
|
if len(fis) == 0 {
|
|
return nil, "", nil
|
|
}
|
|
if len(fis) > 1 {
|
|
return nil, "", fmt.Errorf("expected directory %q to have only 1 item; found %d", parentPath, len(fis))
|
|
}
|
|
imagePath := filepath.Join(parentPath, fis[0].Name())
|
|
layoutPath, err := layout.FromPath(imagePath)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
index, err := layoutPath.ImageIndex()
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
indexManifest, err := index.IndexManifest()
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
manifests := indexManifest.Manifests
|
|
if len(manifests) != 1 {
|
|
return nil, "", fmt.Errorf("expected image index at %q to have only 1 manifest; found %d", imagePath, len(manifests))
|
|
}
|
|
manifest := manifests[0]
|
|
image, err := layoutPath.Image(manifest.Digest)
|
|
if err != nil {
|
|
return nil, "", err
|
|
}
|
|
return image, imagePath, nil
|
|
}
|