From 9315114fe9ef31736125d8cab9d420b33d61ab96 Mon Sep 17 00:00:00 2001 From: Natalie Arellano Date: Fri, 12 Apr 2024 11:04:21 -0400 Subject: [PATCH 1/3] Add interface method, AddOrReuseLayerWithHistory Signed-off-by: Natalie Arellano --- cnb_image.go | 23 +++++++++++++++++++++++ fakes/image.go | 6 ++++++ image.go | 1 + local/local.go | 11 +++++++++++ 4 files changed, 41 insertions(+) diff --git a/cnb_image.go b/cnb_image.go index 2881d446..ae361f43 100644 --- a/cnb_image.go +++ b/cnb_image.go @@ -357,6 +357,29 @@ func (i *CNBImageCore) AddLayerWithHistory(layer v1.Layer, history v1.History) e return err } +func (i *CNBImageCore) AddOrReuseLayerWithHistory(path string, diffID string, history v1.History) error { + prevLayerExists, err := i.PreviousImageHasLayer(diffID) + if err != nil { + return err + } + if !prevLayerExists { + return i.AddLayerWithDiffIDAndHistory(path, diffID, history) + } + return i.ReuseLayerWithHistory(diffID, history) +} + +func (i *CNBImageCore) PreviousImageHasLayer(diffID string) (bool, error) { + layerHash, err := v1.NewHash(diffID) + if err != nil { + return false, fmt.Errorf("failed to get layer hash: %w", err) + } + prevConfigFile, err := getConfigFile(i.previousImage) + if err != nil { + return false, fmt.Errorf("failed to get previous image config: %w", err) + } + return contains(prevConfigFile.RootFS.DiffIDs, layerHash), nil +} + func (i *CNBImageCore) Rebase(baseTopLayerDiffID string, withNewBase Image) error { newBase := withNewBase.UnderlyingImage() // FIXME: when all imgutil.Images are v1.Images, we can remove this part var err error diff --git a/fakes/image.go b/fakes/image.go index 1e849d9a..a27704b6 100644 --- a/fakes/image.go +++ b/fakes/image.go @@ -18,6 +18,8 @@ import ( "github.com/buildpacks/imgutil" ) +var _ imgutil.Image = &Image{} + func NewImage(name, topLayerSha string, identifier imgutil.Identifier) *Image { return &Image{ labels: nil, @@ -238,6 +240,10 @@ func shaForFile(path string) (string, error) { return hex.EncodeToString(hasher.Sum(make([]byte, 0, hasher.Size()))), nil } +func (i *Image) AddOrReuseLayerWithHistory(_, _ string, _ v1.History) error { + panic("implement me") +} + func (i *Image) GetLayer(sha string) (io.ReadCloser, error) { path, ok := i.layersMap[sha] if !ok { diff --git a/image.go b/image.go index f8009442..4a43381c 100644 --- a/image.go +++ b/image.go @@ -62,6 +62,7 @@ type Image interface { AddLayer(path string) error AddLayerWithDiffID(path, diffID string) error AddLayerWithDiffIDAndHistory(path, diffID string, history v1.History) error + AddOrReuseLayerWithHistory(path, diffID string, history v1.History) error Delete() error Rebase(string, Image) error RemoveLabel(string) error diff --git a/local/local.go b/local/local.go index 77c7a032..e18cf276 100644 --- a/local/local.go +++ b/local/local.go @@ -166,6 +166,17 @@ func (i *Image) addLayerToStore(fromPath, withDiffID string) (v1.Layer, error) { return layer, nil } +func (i *Image) AddOrReuseLayerWithHistory(path string, diffID string, history v1.History) error { + prevLayerExists, err := i.PreviousImageHasLayer(diffID) + if err != nil { + return err + } + if !prevLayerExists { + return i.AddLayerWithDiffIDAndHistory(path, diffID, history) + } + return i.ReuseLayerWithHistory(diffID, history) +} + func (i *Image) Rebase(baseTopLayerDiffID string, withNewBase imgutil.Image) error { if err := i.ensureLayers(); err != nil { return err From 026d3a3af6fdf7fd7026f61a17bd1738cd3b40ce Mon Sep 17 00:00:00 2001 From: Natalie Arellano Date: Fri, 12 Apr 2024 11:26:13 -0400 Subject: [PATCH 2/3] Add nil check Signed-off-by: Natalie Arellano --- cnb_image.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cnb_image.go b/cnb_image.go index ae361f43..4ea65af5 100644 --- a/cnb_image.go +++ b/cnb_image.go @@ -369,6 +369,9 @@ func (i *CNBImageCore) AddOrReuseLayerWithHistory(path string, diffID string, hi } func (i *CNBImageCore) PreviousImageHasLayer(diffID string) (bool, error) { + if i.previousImage == nil { + return false, nil + } layerHash, err := v1.NewHash(diffID) if err != nil { return false, fmt.Errorf("failed to get layer hash: %w", err) From 801e57259f004cc198aabb9e259c08f176adc481 Mon Sep 17 00:00:00 2001 From: Natalie Arellano Date: Fri, 12 Apr 2024 11:48:21 -0400 Subject: [PATCH 3/3] We should always normalize history before adding a layer Signed-off-by: Natalie Arellano --- cnb_image.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cnb_image.go b/cnb_image.go index 4ea65af5..cac042cf 100644 --- a/cnb_image.go +++ b/cnb_image.go @@ -483,6 +483,14 @@ func getHistory(forIndex int, fromImage v1.Image) (v1.History, error) { } func (i *CNBImageCore) ReuseLayerWithHistory(diffID string, history v1.History) error { + var err error + // ensure existing history + if err = i.MutateConfigFile(func(c *v1.ConfigFile) { + c.History = NormalizedHistory(c.History, len(c.RootFS.DiffIDs)) + }); err != nil { + return err + } + layerHash, err := v1.NewHash(diffID) if err != nil { return fmt.Errorf("failed to get layer hash: %w", err)