Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
| ... | ... |
@@ -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 |