Skip to content

Commit

Permalink
Refactor layout package to wrap a CNBImageCore
Browse files Browse the repository at this point in the history
Signed-off-by: Natalie Arellano <[email protected]>
  • Loading branch information
natalieparellano committed Jan 30, 2024
1 parent efd1f09 commit c3794cc
Show file tree
Hide file tree
Showing 21 changed files with 528 additions and 1,031 deletions.
70 changes: 36 additions & 34 deletions cnb_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package imgutil
import (
"errors"
"fmt"
"io"
"strings"
"time"

Expand All @@ -18,10 +19,10 @@ import (
// The working image could be any v1.Image,
// but in practice will start off as a pointer to a locallayout.v1ImageFacade (or similar).
type CNBImageCore struct {
v1.Image // the working image
// required
repoName string
v1.Image // the working image
// optional
createdAt time.Time
preferredMediaTypes MediaTypes
preserveHistory bool
previousImage v1.Image
Expand All @@ -36,7 +37,7 @@ var _ v1.Image = &CNBImageCore{}

// FIXME: mark deprecated methods as deprecated on the interface when other packages (remote, layout) expose a v1.Image

// Deprecated: Architecture
// TBD Deprecated: Architecture
func (i *CNBImageCore) Architecture() (string, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand All @@ -45,7 +46,7 @@ func (i *CNBImageCore) Architecture() (string, error) {
return configFile.Architecture, nil
}

// Deprecated: CreatedAt
// TBD Deprecated: CreatedAt
func (i *CNBImageCore) CreatedAt() (time.Time, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand All @@ -54,7 +55,7 @@ func (i *CNBImageCore) CreatedAt() (time.Time, error) {
return configFile.Created.Time, nil
}

// Deprecated: Entrypoint
// TBD Deprecated: Entrypoint
func (i *CNBImageCore) Entrypoint() ([]string, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand Down Expand Up @@ -85,7 +86,19 @@ func (i *CNBImageCore) GetAnnotateRefName() (string, error) {
return manifest.Annotations["org.opencontainers.image.ref.name"], nil
}

// Deprecated: History
func (i *CNBImageCore) GetLayer(diffID string) (io.ReadCloser, error) {
hash, err := v1.NewHash(diffID)
if err != nil {
return nil, err
}
layer, err := i.LayerByDiffID(hash)
if err != nil {
return nil, err
}
return layer.Uncompressed()
}

// TBD Deprecated: History
func (i *CNBImageCore) History() ([]v1.History, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand All @@ -94,7 +107,7 @@ func (i *CNBImageCore) History() ([]v1.History, error) {
return configFile.History, nil
}

// Deprecated: Label
// TBD Deprecated: Label
func (i *CNBImageCore) Label(key string) (string, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand All @@ -103,7 +116,7 @@ func (i *CNBImageCore) Label(key string) (string, error) {
return configFile.Config.Labels[key], nil
}

// Deprecated: Labels
// TBD Deprecated: Labels
func (i *CNBImageCore) Labels() (map[string]string, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand All @@ -112,16 +125,12 @@ func (i *CNBImageCore) Labels() (map[string]string, error) {
return configFile.Config.Labels, nil
}

// Deprecated: ManifestSize
// TBD Deprecated: ManifestSize
func (i *CNBImageCore) ManifestSize() (int64, error) {
return i.Image.Size()
}

func (i *CNBImageCore) Name() string {
return i.repoName
}

// Deprecated: OS
// TBD Deprecated: OS
func (i *CNBImageCore) OS() (string, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand All @@ -130,7 +139,7 @@ func (i *CNBImageCore) OS() (string, error) {
return configFile.OS, nil
}

// Deprecated: OSVersion
// TBD Deprecated: OSVersion
func (i *CNBImageCore) OSVersion() (string, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand All @@ -145,7 +154,7 @@ func (i *CNBImageCore) TopLayer() (string, error) {
return "", err
}
if len(layers) == 0 {
return "", fmt.Errorf("image %q has no layers", i.Name())
return "", errors.New("image has no layers")
}
topLayer := layers[len(layers)-1]
hex, err := topLayer.DiffID()
Expand All @@ -165,7 +174,7 @@ func (i *CNBImageCore) Valid() bool {
return err == nil
}

// Deprecated: Variant
// TBD Deprecated: Variant
func (i *CNBImageCore) Variant() (string, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand All @@ -174,7 +183,7 @@ func (i *CNBImageCore) Variant() (string, error) {
return configFile.Variant, nil
}

// Deprecated: WorkingDir
// TBD Deprecated: WorkingDir
func (i *CNBImageCore) WorkingDir() (string, error) {
configFile, err := getConfigFile(i.Image)
if err != nil {
Expand All @@ -201,25 +210,21 @@ func (i *CNBImageCore) AnnotateRefName(refName string) error {
return nil
}

func (i *CNBImageCore) Rename(name string) {
i.repoName = name
}

// Deprecated: SetArchitecture
// TBD Deprecated: SetArchitecture
func (i *CNBImageCore) SetArchitecture(architecture string) error {
return i.MutateConfigFile(func(c *v1.ConfigFile) {
c.Architecture = architecture
})
}

// Deprecated: SetCmd
// TBD Deprecated: SetCmd
func (i *CNBImageCore) SetCmd(cmd ...string) error {
return i.MutateConfigFile(func(c *v1.ConfigFile) {
c.Config.Cmd = cmd
})
}

// Deprecated: SetEntrypoint
// TBD Deprecated: SetEntrypoint
func (i *CNBImageCore) SetEntrypoint(ep ...string) error {
return i.MutateConfigFile(func(c *v1.ConfigFile) {
c.Config.Entrypoint = ep
Expand Down Expand Up @@ -249,7 +254,7 @@ func (i *CNBImageCore) SetEnv(key, val string) error {
})
}

// Deprecated: SetHistory
// TBD Deprecated: SetHistory
func (i *CNBImageCore) SetHistory(histories []v1.History) error {
return i.MutateConfigFile(func(c *v1.ConfigFile) {
c.History = histories
Expand All @@ -271,21 +276,21 @@ func (i *CNBImageCore) SetOS(osVal string) error {
})
}

// Deprecated: SetOSVersion
// TBD Deprecated: SetOSVersion
func (i *CNBImageCore) SetOSVersion(osVersion string) error {
return i.MutateConfigFile(func(c *v1.ConfigFile) {
c.OSVersion = osVersion
})
}

// Deprecated: SetVariant
// TBD Deprecated: SetVariant
func (i *CNBImageCore) SetVariant(variant string) error {
return i.MutateConfigFile(func(c *v1.ConfigFile) {
c.Variant = variant
})
}

// Deprecated: SetWorkingDir
// TBD Deprecated: SetWorkingDir
func (i *CNBImageCore) SetWorkingDir(dir string) error {
return i.MutateConfigFile(func(c *v1.ConfigFile) {
c.Config.WorkingDir = dir
Expand All @@ -312,11 +317,8 @@ func (i *CNBImageCore) AddLayerWithDiffIDAndHistory(path, _ string, history v1.H
if !i.preserveHistory {
history = emptyHistory
}
configFile, err := getConfigFile(i)
if err != nil {
return err
}
history.Created = configFile.Created
history.Created = v1.Time{Time: i.createdAt}

i.Image, err = mutate.Append(
i.Image,
mutate.Addendum{
Expand Down
130 changes: 4 additions & 126 deletions image.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import (
"time"

v1 "github.com/google/go-containerregistry/pkg/v1"
"github.com/google/go-containerregistry/pkg/v1/empty"
"github.com/google/go-containerregistry/pkg/v1/mutate"
"github.com/google/go-containerregistry/pkg/v1/types"
)

type Image interface {
Expand All @@ -19,7 +17,7 @@ type Image interface {
CreatedAt() (time.Time, error)
Entrypoint() ([]string, error)
Env(key string) (string, error)
// Found tells whether the image exists in the repository by `Name()`.
// Found reports if image exists in the image store with `Name()`.
Found() bool
GetAnnotateRefName() (string, error)
// GetLayer retrieves layer by diff id. Returns a reader of the uncompressed contents of the layer.
Expand Down Expand Up @@ -87,136 +85,16 @@ type Platform struct {
OSVersion string
}

type MediaTypes int

const (
MissingTypes MediaTypes = iota
DefaultTypes
OCITypes
DockerTypes
)

func (t MediaTypes) ManifestType() types.MediaType {
switch t {
case OCITypes:
return types.OCIManifestSchema1
case DockerTypes:
return types.DockerManifestSchema2
default:
return ""
}
}

func (t MediaTypes) ConfigType() types.MediaType {
switch t {
case OCITypes:
return types.OCIConfigJSON
case DockerTypes:
return types.DockerConfigJSON
default:
return ""
}
}

func (t MediaTypes) LayerType() types.MediaType {
switch t {
case OCITypes:
return types.OCILayer
case DockerTypes:
return types.DockerLayer
default:
return ""
}
}

// OverrideMediaTypes mutates the provided v1.Image to use the desired media types
// in the image manifest and config files (including the layers referenced in the manifest)
func OverrideMediaTypes(image v1.Image, mediaTypes MediaTypes) (v1.Image, error) {
if mediaTypes == DefaultTypes || mediaTypes == MissingTypes {
// without media types option, default to original media types
return image, nil
}

// manifest media type
retImage := mutate.MediaType(empty.Image, mediaTypes.ManifestType())

// update empty image with image config
config, err := image.ConfigFile()
if err != nil {
return nil, err
}
history := config.History
// zero out diff IDs and history, as these will be updated when we call `mutate.Append`
config.RootFS.DiffIDs = make([]v1.Hash, 0)
config.History = []v1.History{}
retImage, err = mutate.ConfigFile(retImage, config)
if err != nil {
return nil, err
}

// config media type
retImage = mutate.ConfigMediaType(retImage, mediaTypes.ConfigType())

// layers media type
layers, err := image.Layers()
if err != nil {
return nil, err
}
additions := layersAddendum(layers, history, mediaTypes.LayerType())
retImage, err = mutate.Append(retImage, additions...)
if err != nil {
return nil, err
}

return retImage, nil
}

// OverrideHistoryIfNeeded zeroes out the history if the number of history entries doesn't match the number of layers.
func OverrideHistoryIfNeeded(image v1.Image) (v1.Image, error) {
configFile, err := image.ConfigFile()
if err != nil || configFile == nil {
return nil, fmt.Errorf("getting image config: %w", err)
configFile, err := getConfigFile(image)
if err != nil {
return nil, err
}
configFile.History = NormalizedHistory(configFile.History, len(configFile.RootFS.DiffIDs))
return mutate.ConfigFile(image, configFile)
}

func NormalizedHistory(history []v1.History, nLayers int) []v1.History {
if history == nil {
return make([]v1.History, nLayers)
}
// ensure we remove history for empty layers
var nHistory []v1.History
for _, h := range history {
if !h.EmptyLayer {
nHistory = append(nHistory, h)
}
}
if len(nHistory) == nLayers {
return nHistory
}
return make([]v1.History, nLayers)
}

// layersAddendum creates an Addendum array with the given layers
// and the desired media type
func layersAddendum(layers []v1.Layer, history []v1.History, mediaType types.MediaType) []mutate.Addendum {
additions := make([]mutate.Addendum, 0)
if len(history) != len(layers) {
history = make([]v1.History, len(layers))
}
for idx, layer := range layers {
additions = append(additions, mutate.Addendum{
Layer: layer,
History: history[idx],
MediaType: mediaType,
})
}
return additions
}

var NormalizedDateTime = time.Date(1980, time.January, 1, 0, 0, 1, 0, time.UTC)

type SaveDiagnostic struct {
ImageName string
Cause error
Expand Down
Loading

0 comments on commit c3794cc

Please sign in to comment.