imagetools: fix merging JSON descriptor with old one

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi 2021-04-09 10:49:15 -07:00
parent ab09846df7
commit 328441cdc6
3 changed files with 60 additions and 9 deletions

View File

@ -118,7 +118,15 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error {
return err
}
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
})
}(i)
@ -238,3 +246,19 @@ func createCmd(dockerCli command.Cli) *cobra.Command {
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
}

View File

@ -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,
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)
```

View File

@ -47,13 +47,16 @@ func (r *Resolver) Combine(ctx context.Context, in string, descs []ocispec.Descr
switch mt {
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
p := descs[i].Platform
if descs[i].Platform == nil {
p, err := r.loadPlatform(ctx, in, dt)
if err != nil {
p = &ocispec.Platform{}
}
if p.OS == "" || p.Architecture == "" {
if err := r.loadPlatform(ctx, p, in, dt); err != nil {
return err
}
descs[i].Platform = p
}
descs[i].Platform = p
case images.MediaTypeDockerSchema1Manifest:
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
}
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
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)
if err != nil {
return nil, err
return err
}
var p ocispec.Platform
if err := json.Unmarshal(dt, &p); err != nil {
return nil, errors.WithStack(err)
return errors.WithStack(err)
}
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) {