github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/cmd/podman/save.go (about) 1 package main 2 3 import ( 4 "os" 5 "strings" 6 7 "github.com/containers/libpod/cmd/podman/cliconfig" 8 "github.com/containers/libpod/cmd/podman/shared/parse" 9 "github.com/containers/libpod/pkg/adapter" 10 "github.com/containers/libpod/pkg/util" 11 "github.com/pkg/errors" 12 "github.com/spf13/cobra" 13 "golang.org/x/crypto/ssh/terminal" 14 ) 15 16 const ( 17 ociManifestDir = "oci-dir" 18 ociArchive = "oci-archive" 19 v2s2ManifestDir = "docker-dir" 20 v2s2Archive = "docker-archive" 21 ) 22 23 var validFormats = []string{ociManifestDir, ociArchive, v2s2ManifestDir, v2s2Archive} 24 25 var ( 26 saveCommand cliconfig.SaveValues 27 saveDescription = `Save an image to docker-archive or oci-archive on the local machine. Default is docker-archive.` 28 29 _saveCommand = &cobra.Command{ 30 Use: "save [flags] IMAGE", 31 Short: "Save image to an archive", 32 Long: saveDescription, 33 RunE: func(cmd *cobra.Command, args []string) error { 34 saveCommand.InputArgs = args 35 saveCommand.GlobalFlags = MainGlobalOpts 36 saveCommand.Remote = remoteclient 37 return saveCmd(&saveCommand) 38 }, 39 Args: func(cmd *cobra.Command, args []string) error { 40 format, err := cmd.Flags().GetString("format") 41 if err != nil { 42 return err 43 } 44 if !util.StringInSlice(format, validFormats) { 45 return errors.Errorf("format value must be one of %s", strings.Join(validFormats, " ")) 46 } 47 return nil 48 }, 49 Example: `podman save --quiet -o myimage.tar imageID 50 podman save --format docker-dir -o ubuntu-dir ubuntu 51 podman save > alpine-all.tar alpine:latest`, 52 } 53 ) 54 55 func init() { 56 saveCommand.Command = _saveCommand 57 saveCommand.SetHelpTemplate(HelpTemplate()) 58 saveCommand.SetUsageTemplate(UsageTemplate()) 59 flags := saveCommand.Flags() 60 flags.BoolVar(&saveCommand.Compress, "compress", false, "Compress tarball image layers when saving to a directory using the 'dir' transport. (default is same compression type as source)") 61 flags.StringVar(&saveCommand.Format, "format", v2s2Archive, "Save image to oci-archive, oci-dir (directory with oci manifest type), docker-archive, docker-dir (directory with v2s2 manifest type)") 62 flags.StringVarP(&saveCommand.Output, "output", "o", "", "Write to a specified file (default: stdout, which must be redirected)") 63 flags.BoolVarP(&saveCommand.Quiet, "quiet", "q", false, "Suppress the output") 64 } 65 66 // saveCmd saves the image to either docker-archive or oci 67 func saveCmd(c *cliconfig.SaveValues) error { 68 args := c.InputArgs 69 if len(args) == 0 { 70 return errors.Errorf("need at least 1 argument") 71 } 72 73 runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) 74 if err != nil { 75 return errors.Wrapf(err, "could not create runtime") 76 } 77 defer runtime.DeferredShutdown(false) 78 79 if c.Flag("compress").Changed && (c.Format != ociManifestDir && c.Format != v2s2ManifestDir && c.Format == "") { 80 return errors.Errorf("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'") 81 } 82 83 if len(c.Output) == 0 { 84 fi := os.Stdout 85 if terminal.IsTerminal(int(fi.Fd())) { 86 return errors.Errorf("refusing to save to terminal. Use -o flag or redirect") 87 } 88 c.Output = "/dev/stdout" 89 } 90 if err := parse.ValidateFileName(c.Output); err != nil { 91 return err 92 } 93 return runtime.SaveImage(getContext(), c) 94 }