summaryrefslogtreecommitdiff
path: root/cmd/podman
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman')
-rw-r--r--cmd/podman/attach.go2
-rw-r--r--cmd/podman/build.go2
-rw-r--r--cmd/podman/cliconfig/config.go5
-rw-r--r--cmd/podman/common.go6
-rw-r--r--cmd/podman/container.go19
-rw-r--r--cmd/podman/events.go3
-rw-r--r--cmd/podman/export.go7
-rw-r--r--cmd/podman/image.go19
-rw-r--r--cmd/podman/inspect.go38
-rw-r--r--cmd/podman/load.go7
-rw-r--r--cmd/podman/login.go2
-rw-r--r--cmd/podman/main.go4
-rw-r--r--cmd/podman/play_kube.go2
-rw-r--r--cmd/podman/pull.go2
-rw-r--r--cmd/podman/push.go2
-rw-r--r--cmd/podman/run.go6
-rw-r--r--cmd/podman/runlabel.go2
-rw-r--r--cmd/podman/save.go8
-rw-r--r--cmd/podman/search.go2
-rw-r--r--cmd/podman/start.go10
-rw-r--r--cmd/podman/tree.go190
21 files changed, 295 insertions, 43 deletions
diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go
index 08976cdaa..86e89cfd7 100644
--- a/cmd/podman/attach.go
+++ b/cmd/podman/attach.go
@@ -35,7 +35,7 @@ func init() {
flags := attachCommand.Flags()
flags.StringVar(&attachCommand.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
flags.BoolVar(&attachCommand.NoStdin, "no-stdin", false, "Do not attach STDIN. The default is false")
- flags.BoolVar(&attachCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process (default true)")
+ flags.BoolVar(&attachCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process")
flags.BoolVarP(&attachCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
markFlagHiddenForRemoteClient("latest", flags)
}
diff --git a/cmd/podman/build.go b/cmd/podman/build.go
index 72d78aff9..f0a67791a 100644
--- a/cmd/podman/build.go
+++ b/cmd/podman/build.go
@@ -52,7 +52,7 @@ func init() {
buildCommand.SetHelpTemplate(HelpTemplate())
buildCommand.SetUsageTemplate(UsageTemplate())
flags := buildCommand.Flags()
- flags.SetInterspersed(false)
+ flags.SetInterspersed(true)
budFlags := buildahcli.GetBudFlags(&budFlagsValues)
flag := budFlags.Lookup("pull")
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index 38a68f94f..1461c9f03 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -66,6 +66,11 @@ type TagValues struct {
PodmanCommand
}
+type TreeValues struct {
+ PodmanCommand
+ WhatRequires bool
+}
+
type WaitValues struct {
PodmanCommand
Interval uint
diff --git a/cmd/podman/common.go b/cmd/podman/common.go
index 79b7495ab..43dfdb837 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -226,7 +226,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
)
createFlags.String(
"detach-keys", "",
- "Override the key sequence for detaching a container. Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`",
+ "Override the key sequence for detaching a container. Format is a single character `[a-Z]` or `ctrl-<value>` where `<value>` is one of: `a-z`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`",
)
createFlags.StringSlice(
"device", []string{},
@@ -313,7 +313,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
)
createFlags.String(
"image-volume", "bind",
- "Tells podman how to handle the builtin image volumes. The options are: 'bind', 'tmpfs', or 'ignore' (default 'bind')",
+ "Tells podman how to handle the builtin image volumes. The options are: 'bind', 'tmpfs', or 'ignore'",
)
createFlags.Bool(
"init", false,
@@ -374,7 +374,7 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
)
createFlags.Int64(
"memory-swappiness", -1,
- "Tune container memory swappiness (0 to 100) (default -1)",
+ "Tune container memory swappiness (0 to 100, or -1 for system default)",
)
createFlags.String(
"name", "",
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index 8ad8d7a44..ce6ad8883 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -19,6 +19,20 @@ var (
},
}
+ contInspectSubCommand cliconfig.InspectValues
+ _contInspectSubCommand = &cobra.Command{
+ Use: strings.Replace(_inspectCommand.Use, "| IMAGE", "", 1),
+ Short: "Display the configuration of a container",
+ Long: `Displays the low-level information on a container identified by name or ID.`,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ contInspectSubCommand.InputArgs = args
+ contInspectSubCommand.GlobalFlags = MainGlobalOpts
+ return inspectCmd(&contInspectSubCommand)
+ },
+ Example: `podman container inspect myCtr
+ podman container inspect -l --format '{{.Id}} {{.Config.Labels}}'`,
+ }
+
listSubCommand cliconfig.PsValues
_listSubCommand = &cobra.Command{
Use: strings.Replace(_psCommand.Use, "ps", "list", 1),
@@ -37,12 +51,15 @@ var (
// Commands that are universally implemented.
containerCommands = []*cobra.Command{
_containerExistsCommand,
- _inspectCommand,
+ _contInspectSubCommand,
_listSubCommand,
}
)
func init() {
+ contInspectSubCommand.Command = _contInspectSubCommand
+ inspectInit(&contInspectSubCommand)
+
listSubCommand.Command = _listSubCommand
psInit(&listSubCommand)
diff --git a/cmd/podman/events.go b/cmd/podman/events.go
index dda9a03f9..f6c20e8ff 100644
--- a/cmd/podman/events.go
+++ b/cmd/podman/events.go
@@ -11,7 +11,8 @@ var (
eventsCommand cliconfig.EventValues
eventsDescription = "Monitor podman events"
_eventsCommand = &cobra.Command{
- Use: "events [flags]",
+ Use: "events",
+ Args: noSubArgs,
Short: "show podman events",
Long: eventsDescription,
RunE: func(cmd *cobra.Command, args []string) error {
diff --git a/cmd/podman/export.go b/cmd/podman/export.go
index e5dc410a7..92633facd 100644
--- a/cmd/podman/export.go
+++ b/cmd/podman/export.go
@@ -36,7 +36,7 @@ func init() {
exportCommand.SetHelpTemplate(HelpTemplate())
exportCommand.SetUsageTemplate(UsageTemplate())
flags := exportCommand.Flags()
- flags.StringVarP(&exportCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT")
+ flags.StringVarP(&exportCommand.Output, "output", "o", "", "Write to a specified file (default: stdout, which must be redirected)")
}
// exportCmd saves a container to a tarball on disk
@@ -60,15 +60,16 @@ func exportCmd(c *cliconfig.ExportValues) error {
}
output := c.Output
- if runtime.Remote && (output == "/dev/stdout" || len(output) == 0) {
+ if runtime.Remote && len(output) == 0 {
return errors.New("remote client usage must specify an output file (-o)")
}
- if output == "/dev/stdout" {
+ if len(output) == 0 {
file := os.Stdout
if logrus.IsTerminal(file) {
return errors.Errorf("refusing to export to terminal. Use -o flag or redirect")
}
+ output = "/dev/stdout"
}
if err := parse.ValidateFileName(output); err != nil {
diff --git a/cmd/podman/image.go b/cmd/podman/image.go
index 52bac6ecb..66c141686 100644
--- a/cmd/podman/image.go
+++ b/cmd/podman/image.go
@@ -31,6 +31,19 @@ var (
Example: strings.Replace(_imagesCommand.Example, "podman images", "podman image list", -1),
}
+ inspectSubCommand cliconfig.InspectValues
+ _inspectSubCommand = &cobra.Command{
+ Use: strings.Replace(_inspectCommand.Use, "CONTAINER | ", "", 1),
+ Short: "Display the configuration of an image",
+ Long: `Displays the low-level information on an image identified by name or ID.`,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ inspectSubCommand.InputArgs = args
+ inspectSubCommand.GlobalFlags = MainGlobalOpts
+ return inspectCmd(&inspectSubCommand)
+ },
+ Example: `podman image inspect alpine`,
+ }
+
rmSubCommand cliconfig.RmiValues
_rmSubCommand = &cobra.Command{
Use: strings.Replace(_rmiCommand.Use, "rmi", "rm", 1),
@@ -52,7 +65,7 @@ var imageSubCommands = []*cobra.Command{
_imagesSubCommand,
_imageExistsCommand,
_importCommand,
- _inspectCommand,
+ _inspectSubCommand,
_loadCommand,
_pruneImagesCommand,
_pullCommand,
@@ -60,6 +73,7 @@ var imageSubCommands = []*cobra.Command{
_rmSubCommand,
_saveCommand,
_tagCommand,
+ _treeCommand,
}
func init() {
@@ -69,6 +83,9 @@ func init() {
imagesSubCommand.Command = _imagesSubCommand
imagesInit(&imagesSubCommand)
+ inspectSubCommand.Command = _inspectSubCommand
+ inspectInit(&inspectSubCommand)
+
imageCommand.SetUsageTemplate(UsageTemplate())
imageCommand.AddCommand(imageSubCommands...)
imageCommand.AddCommand(getImageSubCommands()...)
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index e14f25c24..3d6fd07e0 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -27,7 +27,7 @@ var (
inspectDescription = `This displays the low-level information on containers and images identified by name or ID.
If given a name that matches both a container and an image, this command inspects the container. By default, this will render all results in a JSON array.`
- _inspectCommand = &cobra.Command{
+ _inspectCommand = cobra.Command{
Use: "inspect [flags] CONTAINER | IMAGE",
Short: "Display the configuration of a container or image",
Long: inspectDescription,
@@ -42,16 +42,34 @@ var (
}
)
+func inspectInit(command *cliconfig.InspectValues) {
+ command.SetHelpTemplate(HelpTemplate())
+ command.SetUsageTemplate(UsageTemplate())
+ flags := command.Flags()
+ flags.StringVarP(&command.Format, "format", "f", "", "Change the output format to a Go template")
+
+ // -t flag applicable only to 'podman inspect', not 'image/container inspect'
+ ambiguous := strings.Contains(command.Use, "|")
+ if ambiguous {
+ flags.StringVarP(&command.TypeObject, "type", "t", inspectAll, "Return JSON for specified type, (image or container)")
+ }
+
+ if strings.Contains(command.Use, "CONTAINER") {
+ containers_only := " (containers only)"
+ if !ambiguous {
+ containers_only = ""
+ command.TypeObject = inspectTypeContainer
+ }
+ flags.BoolVarP(&command.Latest, "latest", "l", false, "Act on the latest container podman is aware of"+containers_only)
+ flags.BoolVarP(&command.Size, "size", "s", false, "Display total file size"+containers_only)
+ markFlagHiddenForRemoteClient("latest", flags)
+ } else {
+ command.TypeObject = inspectTypeImage
+ }
+}
func init() {
- inspectCommand.Command = _inspectCommand
- inspectCommand.SetHelpTemplate(HelpTemplate())
- inspectCommand.SetUsageTemplate(UsageTemplate())
- flags := inspectCommand.Flags()
- flags.StringVarP(&inspectCommand.TypeObject, "type", "t", inspectAll, "Return JSON for specified type, (e.g image, container or task)")
- flags.StringVarP(&inspectCommand.Format, "format", "f", "", "Change the output format to a Go template")
- flags.BoolVarP(&inspectCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of if the type is a container")
- flags.BoolVarP(&inspectCommand.Size, "size", "s", false, "Display total file size if the type is container")
- markFlagHiddenForRemoteClient("latest", flags)
+ inspectCommand.Command = &_inspectCommand
+ inspectInit(&inspectCommand)
}
func inspectCmd(c *cliconfig.InspectValues) error {
diff --git a/cmd/podman/load.go b/cmd/podman/load.go
index 303c23bc7..46add699e 100644
--- a/cmd/podman/load.go
+++ b/cmd/podman/load.go
@@ -34,7 +34,7 @@ func init() {
loadCommand.SetHelpTemplate(HelpTemplate())
loadCommand.SetUsageTemplate(UsageTemplate())
flags := loadCommand.Flags()
- flags.StringVarP(&loadCommand.Input, "input", "i", "/dev/stdin", "Read from archive file, default is STDIN")
+ flags.StringVarP(&loadCommand.Input, "input", "i", "", "Read from specified archive file (default: stdin)")
flags.BoolVarP(&loadCommand.Quiet, "quiet", "q", false, "Suppress the output")
flags.StringVar(&loadCommand.SignaturePolicy, "signature-policy", "", "Pathname of signature policy file (not usually used)")
@@ -64,7 +64,10 @@ func loadCmd(c *cliconfig.LoadValues) error {
if runtime.Remote && len(input) == 0 {
return errors.New("the remote client requires you to load via -i and a tarball")
}
- if input == "/dev/stdin" {
+ if len(input) == 0 {
+ input = "/dev/stdin"
+ c.Input = input
+
fi, err := os.Stdin.Stat()
if err != nil {
return err
diff --git a/cmd/podman/login.go b/cmd/podman/login.go
index 43a7d246e..4e96b43cb 100644
--- a/cmd/podman/login.go
+++ b/cmd/podman/login.go
@@ -45,7 +45,7 @@ func init() {
flags.StringVar(&loginCommand.CertDir, "cert-dir", "", "Pathname of a directory containing TLS certificates and keys used to connect to the registry")
flags.BoolVar(&loginCommand.GetLogin, "get-login", true, "Return the current login user for the registry")
flags.StringVarP(&loginCommand.Password, "password", "p", "", "Password for registry")
- flags.BoolVar(&loginCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&loginCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
flags.StringVarP(&loginCommand.Username, "username", "u", "", "Username for registry")
flags.BoolVar(&loginCommand.StdinPassword, "password-stdin", false, "Take the password from stdin")
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 669860341..1717e0624 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -42,7 +42,7 @@ var mainCommands = []*cobra.Command{
&_imagesCommand,
_importCommand,
_infoCommand,
- _inspectCommand,
+ &_inspectCommand,
_killCommand,
_loadCommand,
podCommand.Command,
@@ -115,7 +115,7 @@ func init() {
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.DefaultMountsFile, "default-mounts-file", "", "Path to default mounts file")
rootCmd.PersistentFlags().MarkHidden("defaults-mount-file")
rootCmd.PersistentFlags().StringSliceVar(&MainGlobalOpts.HooksDir, "hooks-dir", []string{}, "Set the OCI hooks directory path (may be set multiple times)")
- rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error (default), fatal or panic")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error, fatal or panic")
rootCmd.PersistentFlags().IntVar(&MainGlobalOpts.MaxWorks, "max-workers", 0, "The maximum number of workers for parallel operations")
rootCmd.PersistentFlags().MarkHidden("max-workers")
rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Namespace, "namespace", "", "Set the libpod namespace, used to create separate views of the containers and pods on the system")
diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go
index 44aa4776b..eeb1aad64 100644
--- a/cmd/podman/play_kube.go
+++ b/cmd/podman/play_kube.go
@@ -59,7 +59,7 @@ func init() {
flags.StringVar(&playKubeCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
flags.BoolVarP(&playKubeCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
flags.StringVar(&playKubeCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
- flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&playKubeCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
func playKubeYAMLCmd(c *cliconfig.KubePlayValues) error {
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 7986d5530..8888c5e28 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -52,7 +52,7 @@ func init() {
flags.StringVar(&pullCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
flags.BoolVarP(&pullCommand.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
flags.StringVar(&pullCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
- flags.BoolVar(&pullCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&pullCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index afc385527..a1dac24ae 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -54,7 +54,7 @@ func init() {
flags.BoolVar(&pushCommand.RemoveSignatures, "remove-signatures", false, "Discard any pre-existing signatures in the image")
flags.StringVar(&pushCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
flags.StringVar(&pushCommand.SignBy, "sign-by", "", "Add a signature at the destination using the specified key")
- flags.BoolVar(&pushCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&pushCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
func pushCmd(c *cliconfig.PushValues) error {
diff --git a/cmd/podman/run.go b/cmd/podman/run.go
index 130c5a32c..32e7b3510 100644
--- a/cmd/podman/run.go
+++ b/cmd/podman/run.go
@@ -44,7 +44,7 @@ func init() {
runCommand.SetUsageTemplate(UsageTemplate())
flags := runCommand.Flags()
flags.SetInterspersed(false)
- flags.Bool("sig-proxy", true, "Proxy received signals to the process (default true)")
+ flags.Bool("sig-proxy", true, "Proxy received signals to the process")
getCreateFlags(&runCommand.PodmanCommand)
}
@@ -166,6 +166,10 @@ func runCmd(c *cliconfig.RunValues) error {
exitCode = int(ecode)
}
+ if c.IsSet("rm") {
+ runtime.RemoveContainer(ctx, ctr, false, true)
+ }
+
return nil
}
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index 5ab55949b..f79aa8b0e 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -60,7 +60,7 @@ func init() {
flags.BoolP("pull", "p", false, "Pull the image if it does not exist locally prior to executing the label contents")
flags.BoolVarP(&runlabelCommand.Quiet, "quiet", "q", false, "Suppress output information when installing images")
flags.StringVar(&runlabelCommand.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
- flags.BoolVar(&runlabelCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&runlabelCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
flags.MarkDeprecated("pull", "podman will pull if not found in local storage")
}
diff --git a/cmd/podman/save.go b/cmd/podman/save.go
index df016b069..c10679740 100644
--- a/cmd/podman/save.go
+++ b/cmd/podman/save.go
@@ -58,7 +58,7 @@ func init() {
flags := saveCommand.Flags()
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)")
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)")
- flags.StringVarP(&saveCommand.Output, "output", "o", "/dev/stdout", "Write to a file, default is STDOUT")
+ flags.StringVarP(&saveCommand.Output, "output", "o", "", "Write to a specified file (default: stdout, which must be redirected)")
flags.BoolVarP(&saveCommand.Quiet, "quiet", "q", false, "Suppress the output")
}
@@ -79,14 +79,14 @@ func saveCmd(c *cliconfig.SaveValues) error {
return errors.Errorf("--compress can only be set when --format is either 'oci-dir' or 'docker-dir'")
}
- output := c.Output
- if output == "/dev/stdout" {
+ if len(c.Output) == 0 {
fi := os.Stdout
if logrus.IsTerminal(fi) {
return errors.Errorf("refusing to save to terminal. Use -o flag or redirect")
}
+ c.Output = "/dev/stdout"
}
- if err := parse.ValidateFileName(output); err != nil {
+ if err := parse.ValidateFileName(c.Output); err != nil {
return err
}
return runtime.SaveImage(getContext(), c)
diff --git a/cmd/podman/search.go b/cmd/podman/search.go
index 25f5a98b7..5997e144a 100644
--- a/cmd/podman/search.go
+++ b/cmd/podman/search.go
@@ -46,7 +46,7 @@ func init() {
flags.StringVar(&searchCommand.Format, "format", "", "Change the output format to a Go template")
flags.IntVar(&searchCommand.Limit, "limit", 0, "Limit the number of results")
flags.BoolVar(&searchCommand.NoTrunc, "no-trunc", false, "Do not truncate the output")
- flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries (default: true)")
+ flags.BoolVar(&searchCommand.TlsVerify, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
}
func searchCmd(c *cliconfig.SearchValues) error {
diff --git a/cmd/podman/start.go b/cmd/podman/start.go
index e942c1ccd..cf406cf66 100644
--- a/cmd/podman/start.go
+++ b/cmd/podman/start.go
@@ -41,7 +41,7 @@ func init() {
flags.StringVar(&startCommand.DetachKeys, "detach-keys", "", "Override the key sequence for detaching a container. Format is a single character [a-Z] or ctrl-<value> where <value> is one of: a-z, @, ^, [, , or _")
flags.BoolVarP(&startCommand.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached")
flags.BoolVarP(&startCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of")
- flags.BoolVar(&startCommand.SigProxy, "sig-proxy", true, "Proxy received signals to the process (default true if attaching, false otherwise)")
+ flags.BoolVar(&startCommand.SigProxy, "sig-proxy", false, "Proxy received signals to the process (default true if attaching, false otherwise)")
markFlagHiddenForRemoteClient("latest", flags)
}
@@ -62,14 +62,10 @@ func startCmd(c *cliconfig.StartValues) error {
return errors.Errorf("you cannot start and attach multiple containers at once")
}
- sigProxy := c.SigProxy
+ sigProxy := c.SigProxy || attach
if sigProxy && !attach {
- if c.Flag("sig-proxy").Changed {
- return errors.Wrapf(libpod.ErrInvalidArg, "you cannot use sig-proxy without --attach")
- } else {
- sigProxy = false
- }
+ return errors.Wrapf(libpod.ErrInvalidArg, "you cannot use sig-proxy without --attach")
}
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
diff --git a/cmd/podman/tree.go b/cmd/podman/tree.go
new file mode 100644
index 000000000..ebda18cdb
--- /dev/null
+++ b/cmd/podman/tree.go
@@ -0,0 +1,190 @@
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod/image"
+ units "github.com/docker/go-units"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+const (
+ middleItem = "├── "
+ continueItem = "│ "
+ lastItem = "└── "
+)
+
+var (
+ treeCommand cliconfig.TreeValues
+
+ treeDescription = "Prints layer hierarchy of an image in a tree format"
+ _treeCommand = &cobra.Command{
+ Use: "tree",
+ Short: treeDescription,
+ Long: treeDescription,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ treeCommand.InputArgs = args
+ treeCommand.GlobalFlags = MainGlobalOpts
+ return treeCmd(&treeCommand)
+ },
+ Example: "podman image tree alpine:latest",
+ }
+)
+
+func init() {
+ treeCommand.Command = _treeCommand
+ treeCommand.SetUsageTemplate(UsageTemplate())
+ treeCommand.Flags().BoolVar(&treeCommand.WhatRequires, "whatrequires", false, "Show all child images and layers of the specified image")
+}
+
+// infoImage keep information of Image along with all associated layers
+type infoImage struct {
+ // id of image
+ id string
+ // tags of image
+ tags []string
+ // layers stores all layers of image.
+ layers []image.LayerInfo
+}
+
+func treeCmd(c *cliconfig.TreeValues) error {
+ args := c.InputArgs
+ if len(args) == 0 {
+ return errors.Errorf("an image name must be specified")
+ }
+ if len(args) > 1 {
+ return errors.Errorf("you must provide at most 1 argument")
+ }
+
+ runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+ if err != nil {
+ return errors.Wrapf(err, "error creating libpod runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ img, err := runtime.ImageRuntime().NewFromLocal(args[0])
+ if err != nil {
+ return err
+ }
+
+ // Fetch map of image-layers, which is used for printing output.
+ layerInfoMap, err := image.GetLayersMapWithImageInfo(runtime.ImageRuntime())
+ if err != nil {
+ return errors.Wrapf(err, "error while retriving layers of image %q", img.InputName)
+ }
+
+ // Create an imageInfo and fill the image and layer info
+ imageInfo := &infoImage{
+ id: img.ID(),
+ tags: img.Names(),
+ }
+
+ size, err := img.Size(context.Background())
+ if err != nil {
+ return errors.Wrapf(err, "error while retriving image size")
+ }
+ fmt.Printf("Image ID: %s\n", imageInfo.id[:12])
+ fmt.Printf("Tags:\t %s\n", imageInfo.tags)
+ fmt.Printf("Size:\t %v\n", units.HumanSizeWithPrecision(float64(*size), 4))
+ fmt.Printf(fmt.Sprintf("Image Layers\n"))
+
+ if !c.WhatRequires {
+ // fill imageInfo with layers associated with image.
+ // the layers will be filled such that
+ // (Start)RootLayer->...intermediate Parent Layer(s)-> TopLayer(End)
+ err := buildImageHierarchyMap(imageInfo, layerInfoMap, img.TopLayer())
+ if err != nil {
+ return err
+ }
+ // Build output from imageInfo into buffer
+ printImageHierarchy(imageInfo)
+
+ } else {
+ // fill imageInfo with layers associated with image.
+ // the layers will be filled such that
+ // (Start)TopLayer->...intermediate Child Layer(s)-> Child TopLayer(End)
+ // (Forks)... intermediate Child Layer(s) -> Child Top Layer(End)
+ err := printImageChildren(layerInfoMap, img.TopLayer(), "", true)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Stores hierarchy of images such that all parent layers using which image is built are stored in imageInfo
+// Layers are added such that (Start)RootLayer->...intermediate Parent Layer(s)-> TopLayer(End)
+func buildImageHierarchyMap(imageInfo *infoImage, layerMap map[string]*image.LayerInfo, layerID string) error {
+ if layerID == "" {
+ return nil
+ }
+ ll, ok := layerMap[layerID]
+ if !ok {
+ return fmt.Errorf("lookup error: layerid %s not found", layerID)
+ }
+ if err := buildImageHierarchyMap(imageInfo, layerMap, ll.ParentID); err != nil {
+ return err
+ }
+
+ imageInfo.layers = append(imageInfo.layers, *ll)
+ return nil
+}
+
+// Stores all children layers which are created using given Image.
+// Layers are stored as follows
+// (Start)TopLayer->...intermediate Child Layer(s)-> Child TopLayer(End)
+// (Forks)... intermediate Child Layer(s) -> Child Top Layer(End)
+func printImageChildren(layerMap map[string]*image.LayerInfo, layerID string, prefix string, last bool) error {
+ if layerID == "" {
+ return nil
+ }
+ ll, ok := layerMap[layerID]
+ if !ok {
+ return fmt.Errorf("lookup error: layerid %s, not found", layerID)
+ }
+ fmt.Printf(prefix)
+
+ //initialize intend with middleItem to reduce middleItem checks.
+ intend := middleItem
+ if !last {
+ // add continueItem i.e. '|' for next iteration prefix
+ prefix = prefix + continueItem
+ } else if len(ll.ChildID) > 1 || len(ll.ChildID) == 0 {
+ // The above condition ensure, alignment happens for node, which has more then 1 childern.
+ // If node is last in printing hierarchy, it should not be printed as middleItem i.e. ├──
+ intend = lastItem
+ prefix = prefix + " "
+ }
+
+ var tags string
+ if len(ll.RepoTags) > 0 {
+ tags = fmt.Sprintf(" Top Layer of: %s", ll.RepoTags)
+ }
+ fmt.Printf("%sID: %s Size: %7v%s\n", intend, ll.ID[:12], units.HumanSizeWithPrecision(float64(ll.Size), 4), tags)
+ for count, childID := range ll.ChildID {
+ if err := printImageChildren(layerMap, childID, prefix, (count == len(ll.ChildID)-1)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// prints the layers info of image
+func printImageHierarchy(imageInfo *infoImage) {
+ for count, l := range imageInfo.layers {
+ var tags string
+ intend := middleItem
+ if len(l.RepoTags) > 0 {
+ tags = fmt.Sprintf(" Top Layer of: %s", l.RepoTags)
+ }
+ if count == len(imageInfo.layers)-1 {
+ intend = lastItem
+ }
+ fmt.Printf("%s ID: %s Size: %7v%s\n", intend, l.ID[:12], units.HumanSizeWithPrecision(float64(l.Size), 4), tags)
+ }
+}