Stores complete OCI descriptor instead of digest and platform
fields. This includes the size which was getting lost by not
storing the original manifest bytes.
Attempt to support existing cached files, if not output
the filename with the incorrect content.
Signed-off-by: Derek McGowan <derek@mcgstyle.net>
(cherry picked from commit 1fd2d66df8)
Signed-off-by: Andrew Hsu <andrewhsu@docker.com>
98 lines
2.9 KiB
Go
98 lines
2.9 KiB
Go
package manifest
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/docker/cli/cli"
|
|
"github.com/docker/cli/cli/command"
|
|
"github.com/docker/cli/cli/manifest/store"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
type annotateOptions struct {
|
|
target string // the target manifest list name (also transaction ID)
|
|
image string // the manifest to annotate within the list
|
|
variant string // an architecture variant
|
|
os string
|
|
arch string
|
|
osFeatures []string
|
|
}
|
|
|
|
// NewAnnotateCommand creates a new `docker manifest annotate` command
|
|
func newAnnotateCommand(dockerCli command.Cli) *cobra.Command {
|
|
var opts annotateOptions
|
|
|
|
cmd := &cobra.Command{
|
|
Use: "annotate [OPTIONS] MANIFEST_LIST MANIFEST",
|
|
Short: "Add additional information to a local image manifest",
|
|
Args: cli.ExactArgs(2),
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
opts.target = args[0]
|
|
opts.image = args[1]
|
|
return runManifestAnnotate(dockerCli, opts)
|
|
},
|
|
}
|
|
|
|
flags := cmd.Flags()
|
|
|
|
flags.StringVar(&opts.os, "os", "", "Set operating system")
|
|
flags.StringVar(&opts.arch, "arch", "", "Set architecture")
|
|
flags.StringSliceVar(&opts.osFeatures, "os-features", []string{}, "Set operating system feature")
|
|
flags.StringVar(&opts.variant, "variant", "", "Set architecture variant")
|
|
|
|
return cmd
|
|
}
|
|
|
|
func runManifestAnnotate(dockerCli command.Cli, opts annotateOptions) error {
|
|
targetRef, err := normalizeReference(opts.target)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "annotate: error parsing name for manifest list %s", opts.target)
|
|
}
|
|
imgRef, err := normalizeReference(opts.image)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "annotate: error parsing name for manifest %s", opts.image)
|
|
}
|
|
|
|
manifestStore := dockerCli.ManifestStore()
|
|
imageManifest, err := manifestStore.Get(targetRef, imgRef)
|
|
switch {
|
|
case store.IsNotFound(err):
|
|
return fmt.Errorf("manifest for image %s does not exist in %s", opts.image, opts.target)
|
|
case err != nil:
|
|
return err
|
|
}
|
|
|
|
// Update the mf
|
|
if imageManifest.Descriptor.Platform == nil {
|
|
imageManifest.Descriptor.Platform = new(ocispec.Platform)
|
|
}
|
|
if opts.os != "" {
|
|
imageManifest.Descriptor.Platform.OS = opts.os
|
|
}
|
|
if opts.arch != "" {
|
|
imageManifest.Descriptor.Platform.Architecture = opts.arch
|
|
}
|
|
for _, osFeature := range opts.osFeatures {
|
|
imageManifest.Descriptor.Platform.OSFeatures = appendIfUnique(imageManifest.Descriptor.Platform.OSFeatures, osFeature)
|
|
}
|
|
if opts.variant != "" {
|
|
imageManifest.Descriptor.Platform.Variant = opts.variant
|
|
}
|
|
|
|
if !isValidOSArch(imageManifest.Descriptor.Platform.OS, imageManifest.Descriptor.Platform.Architecture) {
|
|
return errors.Errorf("manifest entry for image has unsupported os/arch combination: %s/%s", opts.os, opts.arch)
|
|
}
|
|
return manifestStore.Save(targetRef, imgRef, imageManifest)
|
|
}
|
|
|
|
func appendIfUnique(list []string, str string) []string {
|
|
for _, s := range list {
|
|
if s == str {
|
|
return list
|
|
}
|
|
}
|
|
return append(list, str)
|
|
}
|