@@ -42,17 +42,19 @@ class Image(object):
42
42
FORMAT = None
43
43
""" Image format version """
44
44
45
- def __init__ (self , log , docker , image , from_layer , tmp_dir = None , tag = None ):
45
+ def __init__ (self , log , docker , image , from_layer , tmp_dir = None , tag = None , rebase = None ):
46
46
self .log = log
47
47
self .debug = self .log .isEnabledFor (logging .DEBUG )
48
48
self .docker = docker
49
49
self .image = image
50
50
self .from_layer = from_layer
51
51
self .tag = tag
52
+ self .rebase = rebase
52
53
self .image_name = None
53
54
self .image_tag = None
54
55
self .squash_id = None
55
56
57
+
56
58
# Workaround for https://play.golang.org/p/sCsWMXYxqy
57
59
#
58
60
# Golang doesn't add padding to microseconds when marshaling
@@ -69,6 +71,7 @@ def __init__(self, log, docker, image, from_layer, tmp_dir=None, tag=None):
69
71
70
72
def squash (self ):
71
73
self ._before_squashing ()
74
+ self .log .info ("Squashing image '%s'..." % self .image )
72
75
ret = self ._squash ()
73
76
self ._after_squashing ()
74
77
@@ -92,12 +95,14 @@ def _initialize_directories(self):
92
95
93
96
# Temporary location on the disk of the old, unpacked *image*
94
97
self .old_image_dir = os .path .join (self .tmp_dir , "old" )
98
+ # Temporary location on the disk of the rebase, unpacked *image*
99
+ self .rebase_image_dir = os .path .join (self .tmp_dir , "rebase" )
95
100
# Temporary location on the disk of the new, unpacked, squashed *image*
96
101
self .new_image_dir = os .path .join (self .tmp_dir , "new" )
97
102
# Temporary location on the disk of the squashed *layer*
98
103
self .squashed_dir = os .path .join (self .new_image_dir , "squashed" )
99
104
100
- for d in self .old_image_dir , self .new_image_dir :
105
+ for d in self .old_image_dir , self .new_image_dir , self . rebase_image_dir :
101
106
os .makedirs (d )
102
107
103
108
def _squash_id (self , layer ):
@@ -150,8 +155,16 @@ def _before_squashing(self):
150
155
try :
151
156
self .old_image_id = self .docker .inspect_image (self .image )['Id' ]
152
157
except SquashError :
153
- raise SquashError (
154
- "Could not get the image ID to squash, please check provided 'image' argument: %s" % self .image )
158
+ raise SquashError ("Could not get the image ID to squash, "
159
+ "please check provided 'image' argument: %s" % self .image )
160
+
161
+ if self .rebase :
162
+ # The image id or name of the image to rebase to
163
+ try :
164
+ self .rebase = self .docker .inspect_image (self .rebase )['Id' ]
165
+ except SquashError :
166
+ raise SquashError ("Could not get the image ID to rebase to, "
167
+ "please check provided 'rebase' argument: %s" % self .rebase )
155
168
156
169
self .old_image_layers = []
157
170
@@ -164,32 +177,36 @@ def _before_squashing(self):
164
177
self .log .debug ("Old layers: %s" , self .old_image_layers )
165
178
166
179
# By default - squash all layers.
167
- if self .from_layer == None :
180
+ if self .from_layer is None :
168
181
self .from_layer = len (self .old_image_layers )
169
182
170
183
try :
171
184
number_of_layers = int (self .from_layer )
172
185
173
- self .log .debug (
174
- "We detected number of layers as the argument to squash" )
186
+ self .log .debug ("We detected number of layers as the argument to squash" )
175
187
except ValueError :
176
188
self .log .debug ("We detected layer as the argument to squash" )
177
189
178
190
squash_id = self ._squash_id (self .from_layer )
179
191
180
192
if not squash_id :
181
- raise SquashError (
182
- "The %s layer could not be found in the %s image" % (self .from_layer , self .image ))
193
+ raise SquashError ("The %s layer could not be found in the %s image" % (self .from_layer , self .image ))
183
194
184
- number_of_layers = len (self .old_image_layers ) - \
185
- self .old_image_layers .index (squash_id ) - 1
195
+ number_of_layers = len (self .old_image_layers ) - self .old_image_layers .index (squash_id ) - 1
186
196
187
197
self ._validate_number_of_layers (number_of_layers )
188
198
189
199
marker = len (self .old_image_layers ) - number_of_layers
190
200
191
201
self .layers_to_squash = self .old_image_layers [marker :]
192
- self .layers_to_move = self .old_image_layers [:marker ]
202
+ if self .rebase :
203
+ self .layers_to_move = []
204
+ self ._read_layers (self .layers_to_move , self .rebase )
205
+ self .layers_to_move .reverse ()
206
+ else :
207
+ self .layers_to_move = self .old_image_layers [:marker ]
208
+
209
+ self .old_image_squash_marker = marker
193
210
194
211
self .log .info ("Checking if squashing is necessary..." )
195
212
@@ -199,18 +216,18 @@ def _before_squashing(self):
199
216
if len (self .layers_to_squash ) == 1 :
200
217
raise SquashUnnecessaryError ("Single layer marked to squash, no squashing is required" )
201
218
202
- self .log .info ("Attempting to squash last %s layers..." ,
203
- number_of_layers )
219
+ self .log .info ("Attempting to squash last %s layers%s ..." , number_of_layers ,
220
+ " rebasing on %s" % self . rebase if self . rebase else "" )
204
221
self .log .debug ("Layers to squash: %s" , self .layers_to_squash )
205
222
self .log .debug ("Layers to move: %s" , self .layers_to_move )
206
223
207
224
# Fetch the image and unpack it on the fly to the old image directory
208
225
self ._save_image (self .old_image_id , self .old_image_dir )
226
+ if self .rebase :
227
+ self ._save_image (self .rebase , self .rebase_image_dir )
209
228
210
229
self .size_before = self ._dir_size (self .old_image_dir )
211
230
212
- self .log .info ("Squashing image '%s'..." % self .image )
213
-
214
231
def _after_squashing (self ):
215
232
self .log .debug ("Removing from disk already squashed layers..." )
216
233
shutil .rmtree (self .old_image_dir , ignore_errors = True )
@@ -670,7 +687,7 @@ def _squash_layers(self, layers_to_squash, layers_to_move):
670
687
671
688
# Find all files in layers that we don't squash
672
689
files_in_layers_to_move = self ._files_in_layers (
673
- layers_to_move , self .old_image_dir )
690
+ layers_to_move , self .old_image_dir if not self . rebase else self . rebase_image_dir )
674
691
675
692
with tarfile .open (self .squashed_tar , 'w' , format = tarfile .PAX_FORMAT ) as squashed_tar :
676
693
to_skip = []
0 commit comments