Files
docker-cli/cli/command/image/save.go
Sebastiaan van Stijn 0adaf6be3b verify that DisableFlagsInUseLine is set for all commands
This replaces the visitAll recursive function with a test that verifies that
the option is set for all commands and subcommands, so that it doesn't have
to be modified at runtime.

We currently still have to loop over all functions for the setValidateArgs
call, but that can be looked at separately.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2025-09-01 09:39:46 +02:00

93 lines
2.6 KiB
Go

package image
import (
"context"
"io"
"github.com/containerd/platforms"
"github.com/docker/cli/cli"
"github.com/docker/cli/cli/command"
"github.com/docker/cli/cli/command/completion"
"github.com/moby/moby/client"
"github.com/moby/sys/atomicwriter"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
type saveOptions struct {
images []string
output string
platform []string
}
// newSaveCommand creates a new "docker image save" command.
func newSaveCommand(dockerCLI command.Cli) *cobra.Command {
var opts saveOptions
cmd := &cobra.Command{
Use: "save [OPTIONS] IMAGE [IMAGE...]",
Short: "Save one or more images to a tar archive (streamed to STDOUT by default)",
Args: cli.RequiresMinArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
opts.images = args
return runSave(cmd.Context(), dockerCLI, opts)
},
Annotations: map[string]string{
"aliases": "docker image save, docker save",
},
ValidArgsFunction: completion.ImageNames(dockerCLI, -1),
DisableFlagsInUseLine: true,
}
flags := cmd.Flags()
flags.StringVarP(&opts.output, "output", "o", "", "Write to a file, instead of STDOUT")
flags.StringSliceVar(&opts.platform, "platform", []string{}, `Save only the given platform(s). Formatted as a comma-separated list of "os[/arch[/variant]]" (e.g., "linux/amd64,linux/arm64/v8")`)
_ = flags.SetAnnotation("platform", "version", []string{"1.48"})
_ = cmd.RegisterFlagCompletionFunc("platform", completion.Platforms)
return cmd
}
// runSave performs a save against the engine based on the specified options
func runSave(ctx context.Context, dockerCLI command.Cli, opts saveOptions) error {
var options []client.ImageSaveOption
platformList := []ocispec.Platform{}
for _, p := range opts.platform {
pp, err := platforms.Parse(p)
if err != nil {
return errors.Wrap(err, "invalid platform")
}
platformList = append(platformList, pp)
}
if len(platformList) > 0 {
options = append(options, client.ImageSaveWithPlatforms(platformList...))
}
var output io.Writer
if opts.output == "" {
if dockerCLI.Out().IsTerminal() {
return errors.New("cowardly refusing to save to a terminal. Use the -o flag or redirect")
}
output = dockerCLI.Out()
} else {
writer, err := atomicwriter.New(opts.output, 0o600)
if err != nil {
return errors.Wrap(err, "failed to save image")
}
defer writer.Close()
output = writer
}
responseBody, err := dockerCLI.Client().ImageSave(ctx, opts.images, options...)
if err != nil {
return err
}
defer responseBody.Close()
_, err = io.Copy(output, responseBody)
return err
}