Browse code

Fix duplicate layers in exported tar

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>

Tonis Tiigi authored on 2016/06/28 04:46:15
Showing 1 changed files
... ...
@@ -29,6 +29,7 @@ type saveSession struct {
29 29
 	outDir      string
30 30
 	images      map[image.ID]*imageDescriptor
31 31
 	savedLayers map[string]struct{}
32
+	diffIDPaths map[layer.DiffID]string // cache every diffID blob to avoid duplicates
32 33
 }
33 34
 
34 35
 func (l *tarexporter) Save(names []string, outStream io.Writer) error {
... ...
@@ -117,6 +118,7 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
117 117
 
118 118
 func (s *saveSession) save(outStream io.Writer) error {
119 119
 	s.savedLayers = make(map[string]struct{})
120
+	s.diffIDPaths = make(map[layer.DiffID]string)
120 121
 
121 122
 	// get image json
122 123
 	tempDir, err := ioutil.TempDir("", "docker-export-")
... ...
@@ -297,35 +299,46 @@ func (s *saveSession) saveLayer(id layer.ChainID, legacyImg image.V1Image, creat
297 297
 	}
298 298
 
299 299
 	// serialize filesystem
300
-	tarFile, err := os.Create(filepath.Join(outDir, legacyLayerFileName))
301
-	if err != nil {
302
-		return distribution.Descriptor{}, err
303
-	}
304
-	defer tarFile.Close()
305
-
300
+	layerPath := filepath.Join(outDir, legacyLayerFileName)
306 301
 	l, err := s.ls.Get(id)
307 302
 	if err != nil {
308 303
 		return distribution.Descriptor{}, err
309 304
 	}
310 305
 	defer layer.ReleaseAndLog(s.ls, l)
311 306
 
312
-	arch, err := l.TarStream()
313
-	if err != nil {
314
-		return distribution.Descriptor{}, err
315
-	}
316
-	defer arch.Close()
307
+	if oldPath, exists := s.diffIDPaths[l.DiffID()]; exists {
308
+		relPath, err := filepath.Rel(layerPath, oldPath)
309
+		if err != nil {
310
+			return distribution.Descriptor{}, err
311
+		}
312
+		os.Symlink(relPath, layerPath)
313
+	} else {
317 314
 
318
-	if _, err := io.Copy(tarFile, arch); err != nil {
319
-		return distribution.Descriptor{}, err
320
-	}
315
+		tarFile, err := os.Create(layerPath)
316
+		if err != nil {
317
+			return distribution.Descriptor{}, err
318
+		}
319
+		defer tarFile.Close()
321 320
 
322
-	for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
323
-		// todo: maybe save layer created timestamp?
324
-		if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
321
+		arch, err := l.TarStream()
322
+		if err != nil {
325 323
 			return distribution.Descriptor{}, err
326 324
 		}
327
-	}
325
+		defer arch.Close()
326
+
327
+		if _, err := io.Copy(tarFile, arch); err != nil {
328
+			return distribution.Descriptor{}, err
329
+		}
330
+
331
+		for _, fname := range []string{"", legacyVersionFileName, legacyConfigFileName, legacyLayerFileName} {
332
+			// todo: maybe save layer created timestamp?
333
+			if err := system.Chtimes(filepath.Join(outDir, fname), createdTime, createdTime); err != nil {
334
+				return distribution.Descriptor{}, err
335
+			}
336
+		}
328 337
 
338
+		s.diffIDPaths[l.DiffID()] = layerPath
339
+	}
329 340
 	s.savedLayers[legacyImg.ID] = struct{}{}
330 341
 
331 342
 	var src distribution.Descriptor