@@ -21,8 +21,10 @@ import (
21
21
)
22
22
23
23
type imageDescriptor struct {
24
- refs []reference.NamedTagged
25
- layers []string
24
+ refs []reference.NamedTagged
25
+ layers []string
26
+ image * image.Image
27
+ layerRef layer.Layer
26
28
}
27
29
28
30
type saveSession struct {
@@ -39,33 +41,47 @@ func (l *tarexporter) Save(names []string, outStream io.Writer) error {
39
41
return err
40
42
}
41
43
44
+ // Release all the image top layer references
45
+ defer l .releaseLayerReferences (images )
42
46
return (& saveSession {tarexporter : l , images : images }).save (outStream )
43
47
}
44
48
45
- func (l * tarexporter ) parseNames (names []string ) (map [image.ID ]* imageDescriptor , error ) {
49
+ // parseNames will parse the image names to a map which contains image.ID to *imageDescriptor.
50
+ // Each imageDescriptor holds an image top layer reference named 'layerRef'. It is taken here, should be released later.
51
+ func (l * tarexporter ) parseNames (names []string ) (desc map [image.ID ]* imageDescriptor , rErr error ) {
46
52
imgDescr := make (map [image.ID ]* imageDescriptor )
53
+ defer func () {
54
+ if rErr != nil {
55
+ l .releaseLayerReferences (imgDescr )
56
+ }
57
+ }()
47
58
48
- addAssoc := func (id image.ID , ref reference.Named ) {
59
+ addAssoc := func (id image.ID , ref reference.Named ) error {
49
60
if _ , ok := imgDescr [id ]; ! ok {
50
- imgDescr [id ] = & imageDescriptor {}
61
+ descr := & imageDescriptor {}
62
+ if err := l .takeLayerReference (id , descr ); err != nil {
63
+ return err
64
+ }
65
+ imgDescr [id ] = descr
51
66
}
52
67
53
68
if ref != nil {
54
69
if _ , ok := ref .(reference.Canonical ); ok {
55
- return
70
+ return nil
56
71
}
57
72
tagged , ok := reference .TagNameOnly (ref ).(reference.NamedTagged )
58
73
if ! ok {
59
- return
74
+ return nil
60
75
}
61
76
62
77
for _ , t := range imgDescr [id ].refs {
63
78
if tagged .String () == t .String () {
64
- return
79
+ return nil
65
80
}
66
81
}
67
82
imgDescr [id ].refs = append (imgDescr [id ].refs , tagged )
68
83
}
84
+ return nil
69
85
}
70
86
71
87
for _ , name := range names {
@@ -78,11 +94,9 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
78
94
// Check if digest ID reference
79
95
if digested , ok := ref .(reference.Digested ); ok {
80
96
id := image .IDFromDigest (digested .Digest ())
81
- _ , err := l .is .Get (id )
82
- if err != nil {
97
+ if err := addAssoc (id , nil ); err != nil {
83
98
return nil , err
84
99
}
85
- addAssoc (id , nil )
86
100
continue
87
101
}
88
102
return nil , errors .Errorf ("invalid reference: %v" , name )
@@ -93,33 +107,70 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
93
107
if err != nil {
94
108
return nil , err
95
109
}
96
- addAssoc (imgID , nil )
110
+ if err := addAssoc (imgID , nil ); err != nil {
111
+ return nil , err
112
+ }
97
113
continue
98
114
}
99
115
if reference .IsNameOnly (namedRef ) {
100
116
assocs := l .rs .ReferencesByName (namedRef )
101
117
for _ , assoc := range assocs {
102
- addAssoc (image .IDFromDigest (assoc .ID ), assoc .Ref )
118
+ if err := addAssoc (image .IDFromDigest (assoc .ID ), assoc .Ref ); err != nil {
119
+ return nil , err
120
+ }
103
121
}
104
122
if len (assocs ) == 0 {
105
123
imgID , err := l .is .Search (name )
106
124
if err != nil {
107
125
return nil , err
108
126
}
109
- addAssoc (imgID , nil )
127
+ if err := addAssoc (imgID , nil ); err != nil {
128
+ return nil , err
129
+ }
110
130
}
111
131
continue
112
132
}
113
133
id , err := l .rs .Get (namedRef )
114
134
if err != nil {
115
135
return nil , err
116
136
}
117
- addAssoc (image .IDFromDigest (id ), namedRef )
137
+ if err := addAssoc (image .IDFromDigest (id ), namedRef ); err != nil {
138
+ return nil , err
139
+ }
118
140
119
141
}
120
142
return imgDescr , nil
121
143
}
122
144
145
+ // takeLayerReference will take/Get the image top layer reference
146
+ func (l * tarexporter ) takeLayerReference (id image.ID , imgDescr * imageDescriptor ) error {
147
+ img , err := l .is .Get (id )
148
+ if err != nil {
149
+ return err
150
+ }
151
+ imgDescr .image = img
152
+ topLayerID := img .RootFS .ChainID ()
153
+ if topLayerID == "" {
154
+ return nil
155
+ }
156
+ layer , err := l .ls .Get (topLayerID )
157
+ if err != nil {
158
+ return err
159
+ }
160
+ imgDescr .layerRef = layer
161
+ return nil
162
+ }
163
+
164
+ // releaseLayerReferences will release all the image top layer references
165
+ func (l * tarexporter ) releaseLayerReferences (imgDescr map [image.ID ]* imageDescriptor ) error {
166
+ for _ , descr := range imgDescr {
167
+ if descr .layerRef != nil {
168
+ l .ls .Release (descr .layerRef )
169
+ }
170
+ }
171
+ return nil
172
+ }
173
+
123
174
func (s * saveSession ) save (outStream io.Writer ) error {
124
175
s .savedLayers = make (map [string ]struct {})
125
176
s .diffIDPaths = make (map [layer.DiffID ]string )
@@ -224,11 +275,7 @@ func (s *saveSession) save(outStream io.Writer) error {
224
275
}
225
276
226
277
func (s * saveSession ) saveImage (id image.ID ) (map [layer.DiffID ]distribution.Descriptor , error ) {
227
- img , err := s .is .Get (id )
228
- if err != nil {
229
- return nil , err
230
- }
231
-
278
+ img := s .images [id ].image
232
279
if len (img .RootFS .DiffIDs ) == 0 {
233
280
return nil , fmt .Errorf ("empty export - not implemented" )
234
281
}
0 commit comments