@@ -1384,26 +1384,90 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, i
13841384 layer = ilayer .ID
13851385 }
13861386
1387- var res * Image
1388- err := s .writeToImageStore (func () error {
1389- var options ImageOptions
1387+ var options ImageOptions
1388+ var namesToAddAfterCreating []string
1389+
1390+ if err := s .imageStore .startWriting (); err != nil {
1391+ return nil , err
1392+ }
1393+ defer s .imageStore .stopWriting ()
1394+
1395+ // Check if the ID refers to an image in a read-only store -- we want
1396+ // to allow images in read-only stores to have their names changed, so
1397+ // if we find one, merge the new values in with what we know about the
1398+ // image that's already there.
1399+ if id != "" {
1400+ for _ , is := range s .roImageStores {
1401+ store := is
1402+ if err := store .startReading (); err != nil {
1403+ return nil , err
1404+ }
1405+ defer store .stopReading ()
1406+ if i , err := store .Get (id ); err == nil {
1407+ // set information about this image in "options"
1408+ options = ImageOptions {
1409+ Metadata : i .Metadata ,
1410+ CreationDate : i .Created ,
1411+ Digest : i .Digest ,
1412+ Digests : copyDigestSlice (i .Digests ),
1413+ NamesHistory : copyStringSlice (i .NamesHistory ),
1414+ }
1415+ for _ , key := range i .BigDataNames {
1416+ data , err := store .BigData (id , key )
1417+ if err != nil {
1418+ return nil , err
1419+ }
1420+ dataDigest , err := store .BigDataDigest (id , key )
1421+ if err != nil {
1422+ return nil , err
1423+ }
1424+ options .BigData = append (options .BigData , ImageBigDataOption {
1425+ Key : key ,
1426+ Data : data ,
1427+ Digest : dataDigest ,
1428+ })
1429+ }
1430+ namesToAddAfterCreating = dedupeStrings (append (append ([]string {}, i .Names ... ), names ... ))
1431+ break
1432+ }
1433+ }
1434+ }
13901435
1391- if iOptions != nil {
1392- options = * iOptions
1393- options .Digests = copyDigestSlice (iOptions .Digests )
1394- options .BigData = copyImageBigDataOptionSlice (iOptions .BigData )
1395- options .NamesHistory = copyStringSlice (iOptions .NamesHistory )
1396- options .Flags = copyStringInterfaceMap (iOptions .Flags )
1436+ // merge any passed-in options into "options" as best we can
1437+ if iOptions != nil {
1438+ if ! iOptions .CreationDate .IsZero () {
1439+ options .CreationDate = iOptions .CreationDate
13971440 }
1398- if options . CreationDate . IsZero () {
1399- options .CreationDate = time . Now (). UTC ()
1441+ if iOptions . Digest != "" {
1442+ options .Digest = iOptions . Digest
14001443 }
1444+ options .Digests = append (options .Digests , copyDigestSlice (iOptions .Digests )... )
1445+ if iOptions .Metadata != "" {
1446+ options .Metadata = iOptions .Metadata
1447+ }
1448+ options .BigData = append (options .BigData , copyImageBigDataOptionSlice (iOptions .BigData )... )
1449+ options .NamesHistory = append (options .NamesHistory , copyStringSlice (iOptions .NamesHistory )... )
1450+ if options .Flags == nil {
1451+ options .Flags = make (map [string ]interface {})
1452+ }
1453+ for k , v := range iOptions .Flags {
1454+ options .Flags [k ] = v
1455+ }
1456+ }
1457+
1458+ if options .CreationDate .IsZero () {
1459+ options .CreationDate = time .Now ().UTC ()
1460+ }
1461+ if metadata != "" {
14011462 options .Metadata = metadata
1463+ }
14021464
1403- var err error
1404- res , err = s .imageStore .create (id , names , layer , options )
1405- return err
1406- })
1465+ res , err := s .imageStore .create (id , names , layer , options )
1466+ if err == nil && len (namesToAddAfterCreating ) > 0 {
1467+ // set any names we pulled up from an additional image store, now that we won't be
1468+ // triggering a duplicate names error
1469+ err = s .imageStore .updateNames (res .ID , namesToAddAfterCreating , addNames )
1470+ }
14071471 return res , err
14081472}
14091473
@@ -2130,18 +2194,30 @@ func (s *store) Exists(id string) bool {
21302194 return s .containerStore .Exists (id )
21312195}
21322196
2133- func dedupeNames (names []string ) []string {
2134- seen := make (map [string ]bool )
2197+ func dedupeStrings (names []string ) []string {
2198+ seen := make (map [string ]struct {} )
21352199 deduped := make ([]string , 0 , len (names ))
21362200 for _ , name := range names {
21372201 if _ , wasSeen := seen [name ]; ! wasSeen {
2138- seen [name ] = true
2202+ seen [name ] = struct {}{}
21392203 deduped = append (deduped , name )
21402204 }
21412205 }
21422206 return deduped
21432207}
21442208
2209+ func dedupeDigests (digests []digest.Digest ) []digest.Digest {
2210+ seen := make (map [digest.Digest ]struct {})
2211+ deduped := make ([]digest.Digest , 0 , len (digests ))
2212+ for _ , d := range digests {
2213+ if _ , wasSeen := seen [d ]; ! wasSeen {
2214+ seen [d ] = struct {}{}
2215+ deduped = append (deduped , d )
2216+ }
2217+ }
2218+ return deduped
2219+ }
2220+
21452221// Deprecated: Prone to race conditions, suggested alternatives are `AddNames` and `RemoveNames`.
21462222func (s * store ) SetNames (id string , names []string ) error {
21472223 return s .updateNames (id , names , setNames )
@@ -2156,7 +2232,7 @@ func (s *store) RemoveNames(id string, names []string) error {
21562232}
21572233
21582234func (s * store ) updateNames (id string , names []string , op updateNameOperation ) error {
2159- deduped := dedupeNames (names )
2235+ deduped := dedupeStrings (names )
21602236
21612237 layerFound := false
21622238 if err := s .writeToLayerStore (func (rlstore rwLayerStore ) error {
@@ -2188,11 +2264,12 @@ func (s *store) updateNames(id string, names []string, op updateNameOperation) e
21882264 if i , err := store .Get (id ); err == nil {
21892265 // "pull up" the image so that we can change its names list
21902266 options := ImageOptions {
2191- Metadata : i .Metadata ,
21922267 CreationDate : i .Created ,
21932268 Digest : i .Digest ,
21942269 Digests : copyDigestSlice (i .Digests ),
2270+ Metadata : i .Metadata ,
21952271 NamesHistory : copyStringSlice (i .NamesHistory ),
2272+ Flags : copyStringInterfaceMap (i .Flags ),
21962273 }
21972274 for _ , key := range i .BigDataNames {
21982275 data , err := store .BigData (id , key )
0 commit comments