github.com/AliyunContainerService/cli@v0.0.0-20181009023821-814ced4b30d0/cli/command/image/save.go (about) 1 package image 2 3 import ( 4 "context" 5 "io" 6 "os" 7 "path/filepath" 8 9 "github.com/docker/cli/cli" 10 "github.com/docker/cli/cli/command" 11 "github.com/pkg/errors" 12 "github.com/spf13/cobra" 13 ) 14 15 type saveOptions struct { 16 images []string 17 output string 18 } 19 20 // NewSaveCommand creates a new `docker save` command 21 func NewSaveCommand(dockerCli command.Cli) *cobra.Command { 22 var opts saveOptions 23 24 cmd := &cobra.Command{ 25 Use: "save [OPTIONS] IMAGE [IMAGE...]", 26 Short: "Save one or more images to a tar archive (streamed to STDOUT by default)", 27 Args: cli.RequiresMinArgs(1), 28 RunE: func(cmd *cobra.Command, args []string) error { 29 opts.images = args 30 return RunSave(dockerCli, opts) 31 }, 32 } 33 34 flags := cmd.Flags() 35 36 flags.StringVarP(&opts.output, "output", "o", "", "Write to a file, instead of STDOUT") 37 38 return cmd 39 } 40 41 // RunSave performs a save against the engine based on the specified options 42 func RunSave(dockerCli command.Cli, opts saveOptions) error { 43 if opts.output == "" && dockerCli.Out().IsTerminal() { 44 return errors.New("cowardly refusing to save to a terminal. Use the -o flag or redirect") 45 } 46 47 if err := validateOutputPath(opts.output); err != nil { 48 return errors.Wrap(err, "failed to save image") 49 } 50 51 responseBody, err := dockerCli.Client().ImageSave(context.Background(), opts.images) 52 if err != nil { 53 return err 54 } 55 defer responseBody.Close() 56 57 if opts.output == "" { 58 _, err := io.Copy(dockerCli.Out(), responseBody) 59 return err 60 } 61 62 return command.CopyToFile(opts.output, responseBody) 63 } 64 65 func validateOutputPath(path string) error { 66 dir := filepath.Dir(path) 67 if dir != "" && dir != "." { 68 if _, err := os.Stat(dir); os.IsNotExist(err) { 69 return errors.Errorf("unable to validate output path: directory %q does not exist", dir) 70 } 71 } 72 return nil 73 }