Merge pull request from tonistiigi/descriptor-merge

imagetools: fix merging JSON descriptor with old one
pull/605/head
Akihiro Suda committed by GitHub
commit 8d64b6484f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -118,7 +118,15 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
return err return err
} }
srcs[i].Ref = nil srcs[i].Ref = nil
srcs[i].Desc = desc if srcs[i].Desc.Digest == "" {
srcs[i].Desc = desc
} else {
var err error
srcs[i].Desc, err = mergeDesc(desc, srcs[i].Desc)
if err != nil {
return err
}
}
return nil return nil
}) })
}(i) }(i)
@ -238,3 +246,19 @@ func createCmd(dockerCli command.Cli) *cobra.Command {
return cmd return cmd
} }
func mergeDesc(d1, d2 ocispec.Descriptor) (ocispec.Descriptor, error) {
if d2.Size != 0 && d1.Size != d2.Size {
return ocispec.Descriptor{}, errors.Errorf("invalid size mismatch for %s, %d != %d", d1.Digest, d2.Size, d1.Size)
}
if d2.MediaType != "" {
d1.MediaType = d2.MediaType
}
if len(d2.Annotations) != 0 {
d1.Annotations = d2.Annotations // no merge so support removes
}
if d2.Platform != nil {
d1.Platform = d2.Platform // missing items filled in later from image config
}
return d1, nil
}

@ -50,6 +50,19 @@ Use the `--dry-run` flag to not push the image, just show it.
Reads source from files. A source can be a manifest digest, manifest reference, Reads source from files. A source can be a manifest digest, manifest reference,
or a JSON of OCI descriptor object. or a JSON of OCI descriptor object.
In order to define annotations or additional platform properties like `os.version` and
`os.features` you need to add them in the OCI descriptor object encoded in JSON.
```
docker buildx imagetools inspect --raw alpine | jq '.manifests[0] | .platform."os.version"="10.1"' > descr.json
docker buildx imagetools create -f descr.json myuser/image
```
The descriptor in the file is merged with existing descriptor in the registry if it exists.
The supported fields for the descriptor are defined in [OCI spec](https://github.com/opencontainers/image-spec/blob/master/descriptor.md#properties) .
### <a name="tag"></a> Set reference for new image (-t, --tag) ### <a name="tag"></a> Set reference for new image (-t, --tag)
``` ```

@ -47,13 +47,16 @@ func (r *Resolver) Combine(ctx context.Context, in string, descs []ocispec.Descr
switch mt { switch mt {
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
p := descs[i].Platform
if descs[i].Platform == nil { if descs[i].Platform == nil {
p, err := r.loadPlatform(ctx, in, dt) p = &ocispec.Platform{}
if err != nil { }
if p.OS == "" || p.Architecture == "" {
if err := r.loadPlatform(ctx, p, in, dt); err != nil {
return err return err
} }
descs[i].Platform = p
} }
descs[i].Platform = p
case images.MediaTypeDockerSchema1Manifest: case images.MediaTypeDockerSchema1Manifest:
return errors.Errorf("schema1 manifests are not allowed in manifest lists") return errors.Errorf("schema1 manifests are not allowed in manifest lists")
} }
@ -166,24 +169,35 @@ func (r *Resolver) Push(ctx context.Context, ref reference.Named, desc ocispec.D
return err return err
} }
func (r *Resolver) loadPlatform(ctx context.Context, in string, dt []byte) (*ocispec.Platform, error) { func (r *Resolver) loadPlatform(ctx context.Context, p2 *ocispec.Platform, in string, dt []byte) error {
var manifest ocispec.Manifest var manifest ocispec.Manifest
if err := json.Unmarshal(dt, &manifest); err != nil { if err := json.Unmarshal(dt, &manifest); err != nil {
return nil, errors.WithStack(err) return errors.WithStack(err)
} }
dt, err := r.GetDescriptor(ctx, in, manifest.Config) dt, err := r.GetDescriptor(ctx, in, manifest.Config)
if err != nil { if err != nil {
return nil, err return err
} }
var p ocispec.Platform var p ocispec.Platform
if err := json.Unmarshal(dt, &p); err != nil { if err := json.Unmarshal(dt, &p); err != nil {
return nil, errors.WithStack(err) return errors.WithStack(err)
} }
p = platforms.Normalize(p) p = platforms.Normalize(p)
return &p, nil
if p2.Architecture == "" {
p2.Architecture = p.Architecture
if p2.Variant == "" {
p2.Variant = p.Variant
}
}
if p2.OS == "" {
p2.OS = p.OS
}
return nil
} }
func detectMediaType(dt []byte) (string, error) { func detectMediaType(dt []byte) (string, error) {

Loading…
Cancel
Save