1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package mutate
16
17 import (
18 "fmt"
19
20 v1 "github.com/google/go-containerregistry/pkg/v1"
21 "github.com/google/go-containerregistry/pkg/v1/empty"
22 )
23
24
25 func Rebase(orig, oldBase, newBase v1.Image) (v1.Image, error) {
26
27
28 origLayers, err := orig.Layers()
29 if err != nil {
30 return nil, fmt.Errorf("failed to get layers for original: %w", err)
31 }
32 oldBaseLayers, err := oldBase.Layers()
33 if err != nil {
34 return nil, err
35 }
36 if len(oldBaseLayers) > len(origLayers) {
37 return nil, fmt.Errorf("image %q is not based on %q (too few layers)", orig, oldBase)
38 }
39 for i, l := range oldBaseLayers {
40 oldLayerDigest, err := l.Digest()
41 if err != nil {
42 return nil, fmt.Errorf("failed to get digest of layer %d of %q: %w", i, oldBase, err)
43 }
44 origLayerDigest, err := origLayers[i].Digest()
45 if err != nil {
46 return nil, fmt.Errorf("failed to get digest of layer %d of %q: %w", i, orig, err)
47 }
48 if oldLayerDigest != origLayerDigest {
49 return nil, fmt.Errorf("image %q is not based on %q (layer %d mismatch)", orig, oldBase, i)
50 }
51 }
52
53 oldConfig, err := oldBase.ConfigFile()
54 if err != nil {
55 return nil, fmt.Errorf("failed to get config for old base: %w", err)
56 }
57
58 origConfig, err := orig.ConfigFile()
59 if err != nil {
60 return nil, fmt.Errorf("failed to get config for original: %w", err)
61 }
62
63 newConfig, err := newBase.ConfigFile()
64 if err != nil {
65 return nil, fmt.Errorf("could not get config for new base: %w", err)
66 }
67
68
69
70
71
72
73 rebasedImage, err := Config(empty.Image, *origConfig.Config.DeepCopy())
74 if err != nil {
75 return nil, fmt.Errorf("failed to create empty image with original config: %w", err)
76 }
77
78
79 rebasedConfig, err := rebasedImage.ConfigFile()
80 if err != nil {
81 return nil, fmt.Errorf("could not get config for rebased image: %w", err)
82 }
83
84 rebasedConfig.Architecture = newConfig.Architecture
85 rebasedConfig.OS = newConfig.OS
86 rebasedConfig.OSVersion = newConfig.OSVersion
87
88
89 rebasedImage, err = ConfigFile(rebasedImage, rebasedConfig)
90 if err != nil {
91 return nil, fmt.Errorf("failed to replace config for rebased image: %w", err)
92 }
93
94
95 newBaseLayers, err := newBase.Layers()
96 if err != nil {
97 return nil, fmt.Errorf("could not get new base layers for new base: %w", err)
98 }
99
100 rebasedImage, err = Append(rebasedImage, createAddendums(0, 0, newConfig.History, newBaseLayers)...)
101 if err != nil {
102 return nil, fmt.Errorf("failed to append new base image: %w", err)
103 }
104
105
106 rebasedImage, err = Append(rebasedImage, createAddendums(len(oldConfig.History), len(oldBaseLayers)+1, origConfig.History, origLayers)...)
107 if err != nil {
108 return nil, fmt.Errorf("failed to append original image: %w", err)
109 }
110
111 return rebasedImage, nil
112 }
113
114
115
116 func createAddendums(startHistory, startLayer int, history []v1.History, layers []v1.Layer) []Addendum {
117 var adds []Addendum
118
119
120
121 layerIndex := 0
122 for historyIndex := range history {
123 var layer v1.Layer
124 emptyLayer := history[historyIndex].EmptyLayer
125 if !emptyLayer {
126 layer = layers[layerIndex]
127 layerIndex++
128 }
129 if historyIndex >= startHistory || layerIndex >= startLayer {
130 adds = append(adds, Addendum{
131 Layer: layer,
132 History: history[historyIndex],
133 })
134 }
135 }
136
137 for i := layerIndex; i < len(layers); i++ {
138 if i >= startLayer {
139 adds = append(adds, Addendum{Layer: layers[layerIndex]})
140 }
141 }
142
143 return adds
144 }
145
View as plain text