summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--cmd/podman/attach.go2
-rw-r--r--cmd/podman/build.go2
-rw-r--r--cmd/podman/common.go4
-rw-r--r--cmd/podman/export.go7
-rw-r--r--cmd/podman/load.go7
-rw-r--r--cmd/podman/login.go2
-rw-r--r--cmd/podman/main.go2
-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.go2
-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--completions/zsh/_podman385
-rw-r--r--contrib/spec/podman.spec.in1
-rw-r--r--libpod/container_internal.go12
-rw-r--r--libpod/events.go4
-rw-r--r--libpod/runtime.go156
-rw-r--r--test/test_podman_build.sh7
22 files changed, 509 insertions, 116 deletions
diff --git a/Makefile b/Makefile
index 782fa4e62..03e21cbe1 100644
--- a/Makefile
+++ b/Makefile
@@ -27,6 +27,7 @@ CONTAINER_RUNTIME := $(shell command -v podman 2> /dev/null || echo docker)
OCI_RUNTIME ?= ""
BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions
+ZSHINSTALLDIR=${PREFIX}/share/zsh/site-functions
SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z)
PACKAGES ?= $(shell $(GO) list -tags "${BUILDTAGS}" ./... | grep -v github.com/containers/libpod/vendor | grep -v e2e | grep -v system )
@@ -247,6 +248,8 @@ install.config:
install.completions:
install ${SELINUXOPT} -d -m 755 ${BASHINSTALLDIR}
install ${SELINUXOPT} -m 644 completions/bash/podman ${BASHINSTALLDIR}
+ install ${SELINUXOPT} -d -m 755 ${ZSHINSTALLDIR}
+ install ${SELINUXOPT} -m 644 completions/zsh/_podman ${ZSHINSTALLDIR}
install.cni:
install ${SELINUXOPT} -d -m 755 ${ETCDIR}/cni/net.d/
@@ -332,6 +335,7 @@ API.md: cmd/podman/varlink/io.podman.varlink
validate.completions: completions/bash/podman
. completions/bash/podman
+ if [ -x /bin/zsh ]; then /bin/zsh completions/zsh/_podman; fi
validate: gofmt .gitvalidation validate.completions
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/common.go b/cmd/podman/common.go
index b76037297..43dfdb837 100644
--- a/cmd/podman/common.go
+++ b/cmd/podman/common.go
@@ -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/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/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 af6731d96..1717e0624 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -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 a92d5d3db..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)
}
diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go
index 68621e095..229ff1201 100644
--- a/cmd/podman/runlabel.go
+++ b/cmd/podman/runlabel.go
@@ -57,7 +57,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/completions/zsh/_podman b/completions/zsh/_podman
new file mode 100644
index 000000000..530649c0c
--- /dev/null
+++ b/completions/zsh/_podman
@@ -0,0 +1,385 @@
+#compdef podman
+
+# To get zsh to reread this file: unset -f _podman;rm -f ~/.zcompdump;compinit
+
+# On rereads, reset cache. (Not that the cacheing works, but some day it might)
+unset -m '_podman_*'
+
+###############################################################################
+# BEGIN 'podman help' parsers -- for options, subcommands, and usage
+
+# Run 'podman XX --help', set _podman_commands to a formatted list of cmds
+_read_podman_commands() {
+ local line
+
+ # Cache: the intention here is to run each 'podman help' only once.
+ # Unfortunately it doesn't seem to actually be working: even though
+ # I can see the var_ref in my shell, it's not visible here.
+ local _var_ref=_podman_commands_"${*// /_}"
+ typeset -ga _podman_commands
+ _podman_commands=(${(P)_var_ref})
+ (( $#_podman_commands )) && return
+
+ _call_program podman podman "$@" --help |\
+ sed -n -e '0,/^Available Commands/d' -e '/^[A-Z]/q;p' |\
+ sed -e 's/^ \+\([^ ]\+\) \+/\1:/' |\
+ egrep . | while read line; do
+ _podman_commands+=($line)
+ done
+
+ eval "typeset -ga $_var_ref"
+ eval "$_var_ref=(\$_podman_commands)"
+}
+
+# Run 'podman XX --help', set _podman_flag_list to a formatted list
+# of flag options for XX
+_read_podman_flags() {
+ local line
+
+ local _var_ref=_podman_flags_"${*// /_}"
+ eval "typeset -ga ${_var_ref}"
+ typeset -ga _podman_flag_list
+ _podman_flag_list=(${(P)_var_ref})
+ (( $#_podman_flag_list )) && return
+
+ # Extract the Flags; strip leading whitespace; pack '-f, --foo'
+ # as '-f,--foo' (no space); then add '=' to '--foo string'.
+ # The result will be, e.g. '-f,--foo=string Description of Option'
+ _call_program podman podman "$@" --help |\
+ sed -n -e '0,/^Flags:/d' -e '/^$/q;p' |\
+ sed -e 's/^ *//' -e 's/^\(-.,\) --/\1--/' |\
+ sed -e 's/^\(-[^ ]\+\) \([^ ]\+\) /\1=\2 /' |\
+ while read flags desc;do
+ # flags like --foo=string: split into --foo & string
+ local -a tmpa
+ local optval=
+ tmpa=(${(s.=.)flags})
+ if [ -n "$tmpa[2]" ]; then
+ flags=$tmpa[1]
+ optval=$tmpa[2]
+ fi
+
+ # 'podman attach --detach-keys' includes ']' in help msg
+ desc=${desc//\]/\\]}
+
+ for flag in ${(s:,:)flags}; do
+ if [ -n "$optval" ]; then
+ _podman_flag_list+=("${flag}[$desc]:$(_podman_find_helper ${flags} ${optval} ${desc})")
+ else
+ _podman_flag_list+=("${flag}[$desc]")
+ fi
+ done
+ done
+
+ eval "typeset -ga $_var_ref=(\$_podman_flag_list)"
+}
+
+# Run 'podman XXX --help', set _podman_usage to the line after "Usage:"
+_read_podman_usage() {
+ local _var_ref=_podman_usage_"${*// /_}"
+ typeset -ga _podman_usage
+ _podman_usage=${(P)_var_ref}
+ (( $#_podman_usage )) && return
+
+ _podman_usage=$(_call_program podman podman "$@" --help |\
+ grep -A1 'Usage:'|\
+ tail -1 |\
+ sed -e 's/^ *//')
+
+ eval "typeset -ga $_var_ref"
+ eval "$_var_ref=\$_podman_usage"
+}
+
+# END 'podman help' parsers
+###############################################################################
+# BEGIN custom helpers for individual option arguments
+
+# Find a zsh helper for a given flag or command-line option
+_podman_find_helper() {
+ local flags=$1
+ local optval=$2
+ local desc=$3
+ local helper=
+
+ # Yes, this is a lot of hardcoding. IMHO it's still better than
+ # hardcoding every possible podman option.
+ # FIXME: there are many more options that could use helpers.
+ if expr "$desc" : ".*[Dd]irectory" >/dev/null; then
+ optval="directory"
+ helper="_files -/"
+ elif expr "$desc" : ".*[Pp]ath" >/dev/null; then
+ optval="path"
+ helper=_files
+ elif [ "$flags" = "--cgroup-manager" ]; then
+ optval="cgroup manager"
+ helper="(cgroupfs systemd)"
+ elif [ "$flags" = "--log-level" ]; then
+ optval="log level"
+ # 'Log messages above specified level: debug, ... (default "...")'
+ # Strip off the description and all 'default' strings
+ desc=${desc/Log*:/} # debug, info, ... (default "...")
+ desc=${(S)desc//\(*\)/} # debug, info, ... or panic
+ desc=${desc//,/} # debug info ... or panic
+ desc=${desc// or / } # debug info ... panic
+ desc=${desc// / } # collapse multiple spaces
+ # FIXME: how to present values _in order_, not sorted alphabetically?
+ helper="($desc)"
+ fi
+ echo "$optval:$helper"
+}
+
+# END custom helpers for individual option arguments
+###############################################################################
+# BEGIN helpers for command-line args (containers, images)
+
+__podman_helper_generic() {
+ local expl line
+ local -a results
+
+ local foo1=$1; shift
+ local name=$2; shift
+
+ _call_program $foo1 podman "$@" |\
+ while read line; do
+ results+=(${=line})
+ done
+
+ _wanted $foo1 expl $name compadd ${(u)results}
+}
+
+_podman_helper_image() {
+ __podman_helper_generic podman-images 'images' \
+ images --format '{{.ID}}\ {{.Repository}}:{{.Tag}}'
+}
+
+# FIXME: at some point, distinguish between running & stopped containers
+_podman_helper_container() {
+ __podman_helper_generic podman-containers 'containers' \
+ ps -a --format '{{.Names}}\ {{.ID}}'
+}
+
+_podman_helper_pod() {
+ __podman_helper_generic podman-pods 'pods' pod list --format '{{.Name}}'
+}
+
+_podman_helper_volume() {
+ __podman_helper_generic podman-volumes 'volumes' volume ls --format '{{.Name}}'
+}
+
+# Combinations. This one seen in diff & inspect
+_podman_helper_container-or-image() {
+ _podman_helper_image
+ _podman_helper_container
+}
+
+# Seen in generate-kube
+_podman_helper_container-or-pod() {
+ _podman_helper_container
+ _podman_helper_pod
+}
+
+# For top and pod-top
+_podman_helper_format-descriptors() {
+ __podman_helper_generic top-format-descriptors 'format descriptors' \
+ top --list-descriptors
+}
+
+# for push, login/logout, and trust
+# FIXME: some day, use this to define a helper for IMAGE-PATH (in 'pull')
+_podman_helper_registry() {
+ local expl
+ local -a registries
+
+ # Suggestions for improvement more than welcome.
+ python3 -c 'from configparser import ConfigParser;cp=ConfigParser();cp.read("/etc/containers/registries.conf");registries=eval(cp.get("registries.search","registries"));[print(r) for r in registries]' 2>/dev/null | while read line; do
+ registries+=($line)
+ done
+
+ if (( $#registries )); then
+ _wanted podman-registry expl "registry" compadd ${(u)registries}
+ else
+ _hosts
+ fi
+}
+
+# END helpers for command-line args
+###############################################################################
+# BEGIN figure out completion helpers for a given (sub)command
+
+# Read Usage string for this subcommand, set up helpers for its subargs
+_set_up_podman_args() {
+ _read_podman_usage "$@"
+
+ typeset -ga _podman_args=()
+ # E.g. 'podman exec [flags] CONTAINER [...' -> 'CONTAINER [....'
+ local usage_rhs=$(expr "$_podman_usage" : ".*\[flags\] \+\(.*\)")
+
+ # e.g. podman pod ps which takes no further args
+ if [ -z "$usage_rhs" ]; then
+ return
+ fi
+
+ # podman diff & inspect accept 'CONTAINER | IMAGE'; make into one keyword.
+ usage_rhs=${usage_rhs// | /-OR-}
+
+ # Arg parsing. There are three possibilities in Usage messages:
+ #
+ # [IMAGE] - optional image arg (zero or one)
+ # IMAGE - exactly one image arg
+ # IMAGE [IMAGE...] - one or more image args
+ # and, theoretically:
+ # [IMAGE...] - zero or more? Haven't seen it in practice. Defer.
+ #
+ # For completion purposes, we only need to provide two options:
+ # one, or more than one? That is: continue offering completion
+ # suggestions after the first one? For that, we make two passes;
+ # in the first, mark an option as either '' (only one) or
+
+ # Parse each command-line arg seen in usage message
+ local word
+ local -A _seen=()
+ for word in ${=usage_rhs}; do
+ local unbracketed=$(expr "$word" : "\[\(.*\)\]")
+
+ if [ -n "$unbracketed" ]; then
+ # Remove all dots; assume(!?) that they'll all be at the end
+ unbracketed=${unbracketed//./}
+
+ if (( $_seen[$unbracketed] )); then
+ # Is this the same word as the previous arg?
+ if expr "$_podman_args[-1]" : ":$unbracketed:" >/dev/null; then
+ # Yes. Make it '*:...' instead of ':...', indicating >1
+ _podman_args[-1]="*$_podman_args[-1]"
+ fi
+ continue
+ fi
+
+ word=$unbracketed
+ fi
+
+ # As of 2019-03 all such instances are '[COMMAND [ARG...]]' and are,
+ # of course, at the end of the line. We can't offer completion for
+ # these, because the container will have different commands than
+ # the host system... but try anyway.
+ if [ "$word" = '[COMMAND' ]; then
+ # e.g. podman create, exec, run
+ _podman_args+=(
+ ":command: _command_names -e"
+ "*::arguments: _normal"
+ )
+ return
+ fi
+
+ # Look for an existing helper, e.g. IMAGE -> _podman_helper_image
+ local helper="_podman_helper_${(L)word}"
+ if (( $+functions[$helper] )); then
+ :
+ else
+ # No defined helper. Reset, but check for known expressions.
+ helper=
+ case "$word" in
+ KUBEFILE) helper='_files -g "*.y(|a)ml(-.)"' ;;
+ PATH) helper='_files' ;;
+ esac
+ fi
+
+ # Another special case: 'top' actually takes multiple options
+ local multi=
+ if [ "$word" = "FORMAT-DESCRIPTORS" ]; then
+ multi='*'
+ fi
+ _podman_args+=("$multi:${(L)word}:$helper")
+ _seen[$word]=1
+ done
+}
+
+# For an endpoint command, i.e. not a subcommand.
+_podman_terminus() {
+ typeset -A opt_args
+ typeset -ga _podman_flag_list
+ typeset -ga _podman_args
+ integer ret=1
+
+ # Find out what args it takes (e.g. image(s), container(s)) and see
+ # if we have helpers for them.
+ _set_up_podman_args "$@"
+ _arguments -C $_podman_flag_list $_podman_args && ret=0
+
+ return ret
+}
+
+# END figure out completion helpers for a given (sub)command
+################################################################################
+# BEGIN actual entry point
+
+# This is the main entry point; it's also where we (recursively) come in
+# to handle nested subcommands such as 'podman container' or even 3-level
+# ones like 'podman generate kube'. Nesting is complicated, so here's
+# my best understanding as of 2019-03-12:
+#
+# Easy first: when you do "podman <TAB>" zsh calls us, we run 'podman --help',
+# figure out the global options and subcommands, and run the magic _arguments
+# command. That will offer those options/subcommands, and complete, etc.
+#
+# Where it gets harder is when you do "podman container mount <TAB>".
+# zsh first calls us with words=(podman container mount) but we don't
+# want all that full context yet! We want to go a piece at a time,
+# handling 'container' first, then 'mount'; ending up with our
+# final 'podman container mount --help' giving us suitable flags
+# and no subcommands; from which we determine that it's a terminus
+# and jump to a function that handles non-subcommand arguments.
+#
+# This is the closest I've yet come to understanding zsh completion;
+# it is still incomplete and may in fact be incorrect. But it works
+# better than anything I've played with so far.
+_podman_subcommand() {
+ local curcontext="$curcontext" state line
+ typeset -A opt_args
+ integer ret=1
+
+ # Run 'podman --help' / 'podman system --help' for our context (initially
+ # empty, then possibly under subcommands); from those, get a list of
+ # flags appropriate for this context and, if applicable, subcommands.
+ _read_podman_flags "$@"
+ _read_podman_commands "$@"
+
+ # Now, is this a sub-subcommand, or does it have args?
+ if (( $#_podman_commands )); then
+ # Subcommands required (podman, podman system, etc)
+ local cmd=${words// /_}
+ _arguments -C $_podman_flag_list \
+ "(-): :->command" \
+ "(-)*:: :->option-or-argument" \
+ && ret=0
+
+ case $state in
+ (command)
+ _describe -t command "podman $* command" _podman_commands && ret=0
+ ;;
+ (option-or-argument)
+ # I think this is when we have a _completed_ subcommand.
+ # Recurse back into here, offering options for that subcommand.
+ curcontext=${curcontext%:*:*}:podman-${words[1]}:
+ _podman_subcommand "$@" ${words[1]} && ret=0
+ ;;
+ esac
+ else
+ # At a terminus, i.e. podman info, podman history; find out
+ # what args it takes.
+ _podman_terminus "$@" && ret=0
+ fi
+
+ return ret
+}
+
+_podman() {
+ _podman_subcommand
+}
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 4
+# indent-tabs-mode: nil
+# sh-basic-offset: 4
+# End:
+# vim: ft=zsh sw=4 ts=4 et
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 703b942b6..3324ee8f9 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -472,6 +472,7 @@ export GOPATH=%{buildroot}/%{gopath}:$(pwd)/vendor:%{gopath}
%{_mandir}/man1/*.1*
%{_mandir}/man5/*.5*
%{_datadir}/bash-completion/completions/*
+%{_datadir}/zsh/site-functions/*
%{_libexecdir}/%{name}/conmon
%config(noreplace) %{_sysconfdir}/cni/net.d/87-%{name}-bridge.conflist
%{_datadir}/containers/%{repo}.conf
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index bea7acd69..872802016 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -337,11 +337,13 @@ func (c *Container) setupStorage(ctx context.Context) error {
}
// Set the default Entrypoint and Command
- if c.config.Entrypoint == nil {
- c.config.Entrypoint = containerInfo.Config.Config.Entrypoint
- }
- if c.config.Command == nil {
- c.config.Command = containerInfo.Config.Config.Cmd
+ if containerInfo.Config != nil {
+ if c.config.Entrypoint == nil {
+ c.config.Entrypoint = containerInfo.Config.Config.Entrypoint
+ }
+ if c.config.Command == nil {
+ c.config.Command = containerInfo.Config.Config.Cmd
+ }
}
artifacts := filepath.Join(c.config.StaticDir, artifactsDir)
diff --git a/libpod/events.go b/libpod/events.go
index 879aeb6c5..f09529a05 100644
--- a/libpod/events.go
+++ b/libpod/events.go
@@ -1,6 +1,8 @@
package libpod
import (
+ "os"
+
"github.com/containers/libpod/libpod/events"
"github.com/hpcloud/tail"
"github.com/pkg/errors"
@@ -85,7 +87,7 @@ func (r *Runtime) Events(fromStart, stream bool, options []events.EventFilter, e
func (r *Runtime) getTail(fromStart, stream bool) (*tail.Tail, error) {
reopen := true
- seek := tail.SeekInfo{Offset: 0, Whence: 2}
+ seek := tail.SeekInfo{Offset: 0, Whence: os.SEEK_END}
if fromStart || !stream {
seek.Whence = 0
reopen = false
diff --git a/libpod/runtime.go b/libpod/runtime.go
index fa208a2ca..9836b7aab 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -241,6 +241,12 @@ type runtimeConfiguredFrom struct {
libpodStaticDirSet bool
libpodTmpDirSet bool
volPathSet bool
+ conmonPath bool
+ conmonEnvVars bool
+ ociRuntimes bool
+ runtimePath bool
+ cniPluginDir bool
+ noPivotRoot bool
}
var (
@@ -324,6 +330,22 @@ func SetXdgRuntimeDir(val string) error {
// NewRuntime creates a new container runtime
// Options can be passed to override the default configuration for the runtime
func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
+ return newRuntimeFromConfig("", options...)
+}
+
+// NewRuntimeFromConfig creates a new container runtime using the given
+// configuration file for its default configuration. Passed RuntimeOption
+// functions can be used to mutate this configuration further.
+// An error will be returned if the configuration file at the given path does
+// not exist or cannot be loaded
+func NewRuntimeFromConfig(userConfigPath string, options ...RuntimeOption) (runtime *Runtime, err error) {
+ if userConfigPath == "" {
+ return nil, errors.New("invalid configuration file specified")
+ }
+ return newRuntimeFromConfig(userConfigPath, options...)
+}
+
+func newRuntimeFromConfig(userConfigPath string, options ...RuntimeOption) (runtime *Runtime, err error) {
runtime = new(Runtime)
runtime.config = new(RuntimeConfig)
runtime.configuredFrom = new(runtimeConfiguredFrom)
@@ -358,11 +380,6 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
rootlessConfigPath = filepath.Join(home, ".config/containers/libpod.conf")
- configPath = rootlessConfigPath
- if _, err := os.Stat(configPath); err != nil {
- foundConfig = false
- }
-
runtimeDir, err := util.GetRootlessRuntimeDir()
if err != nil {
return nil, err
@@ -374,6 +391,20 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
return nil, errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
}
+ }
+
+ if userConfigPath != "" {
+ configPath = userConfigPath
+ if _, err := os.Stat(configPath); err != nil {
+ // If the user specified a config file, we must fail immediately
+ // when it doesn't exist
+ return nil, errors.Wrapf(err, "cannot stat %s", configPath)
+ }
+ } else if rootless.IsRootless() {
+ configPath = rootlessConfigPath
+ if _, err := os.Stat(configPath); err != nil {
+ foundConfig = false
+ }
} else if _, err := os.Stat(OverrideConfigPath); err == nil {
// Use the override configuration path
configPath = OverrideConfigPath
@@ -409,6 +440,24 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
if tmpConfig.VolumePath != "" {
runtime.configuredFrom.volPathSet = true
}
+ if tmpConfig.ConmonPath != nil {
+ runtime.configuredFrom.conmonPath = true
+ }
+ if tmpConfig.ConmonEnvVars != nil {
+ runtime.configuredFrom.conmonEnvVars = true
+ }
+ if tmpConfig.OCIRuntimes != nil {
+ runtime.configuredFrom.ociRuntimes = true
+ }
+ if tmpConfig.RuntimePath != nil {
+ runtime.configuredFrom.runtimePath = true
+ }
+ if tmpConfig.CNIPluginDir != nil {
+ runtime.configuredFrom.cniPluginDir = true
+ }
+ if tmpConfig.NoPivotRoot {
+ runtime.configuredFrom.noPivotRoot = true
+ }
if _, err := toml.Decode(string(contents), runtime.config); err != nil {
return nil, errors.Wrapf(err, "error decoding configuration file %s", configPath)
@@ -428,12 +477,24 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
}
// Cherry pick the settings we want from the global configuration
- runtime.config.ConmonPath = tmpConfig.ConmonPath
- runtime.config.ConmonEnvVars = tmpConfig.ConmonEnvVars
- runtime.config.OCIRuntimes = tmpConfig.OCIRuntimes
- runtime.config.RuntimePath = tmpConfig.RuntimePath
- runtime.config.CNIPluginDir = tmpConfig.CNIPluginDir
- runtime.config.NoPivotRoot = tmpConfig.NoPivotRoot
+ if !runtime.configuredFrom.conmonPath {
+ runtime.config.ConmonPath = tmpConfig.ConmonPath
+ }
+ if !runtime.configuredFrom.conmonEnvVars {
+ runtime.config.ConmonEnvVars = tmpConfig.ConmonEnvVars
+ }
+ if !runtime.configuredFrom.ociRuntimes {
+ runtime.config.OCIRuntimes = tmpConfig.OCIRuntimes
+ }
+ if !runtime.configuredFrom.runtimePath {
+ runtime.config.RuntimePath = tmpConfig.RuntimePath
+ }
+ if !runtime.configuredFrom.cniPluginDir {
+ runtime.config.CNIPluginDir = tmpConfig.CNIPluginDir
+ }
+ if !runtime.configuredFrom.noPivotRoot {
+ runtime.config.NoPivotRoot = tmpConfig.NoPivotRoot
+ }
break
}
}
@@ -465,80 +526,9 @@ func NewRuntime(options ...RuntimeOption) (runtime *Runtime, err error) {
return runtime, nil
}
-// NewRuntimeFromConfig creates a new container runtime using the given
-// configuration file for its default configuration. Passed RuntimeOption
-// functions can be used to mutate this configuration further.
-// An error will be returned if the configuration file at the given path does
-// not exist or cannot be loaded
-func NewRuntimeFromConfig(configPath string, options ...RuntimeOption) (runtime *Runtime, err error) {
- runtime = new(Runtime)
- runtime.config = new(RuntimeConfig)
- runtime.configuredFrom = new(runtimeConfiguredFrom)
-
- // Set three fields not in the TOML config
- runtime.config.StateType = defaultRuntimeConfig.StateType
- runtime.config.OCIRuntime = defaultRuntimeConfig.OCIRuntime
-
- storageConf, err := util.GetDefaultStoreOptions()
- if err != nil {
- return nil, errors.Wrapf(err, "error retrieving storage config")
- }
- runtime.config.StorageConfig = storageConf
- runtime.config.StaticDir = filepath.Join(storageConf.GraphRoot, "libpod")
- runtime.config.VolumePath = filepath.Join(storageConf.GraphRoot, "volumes")
-
- tmpDir, err := getDefaultTmpDir()
- if err != nil {
- return nil, err
- }
- runtime.config.TmpDir = tmpDir
- if rootless.IsRootless() {
- runtimeDir, err := util.GetRootlessRuntimeDir()
- if err != nil {
- return nil, err
- }
- // containers/image uses XDG_RUNTIME_DIR to locate the auth file.
- // So make sure the env variable is set.
- if err := SetXdgRuntimeDir(runtimeDir); err != nil {
- return nil, errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
- }
- }
-
- // Check to see if the given configuration file exists
- if _, err := os.Stat(configPath); err != nil {
- return nil, errors.Wrapf(err, "error checking existence of configuration file %s", configPath)
- }
-
- // Read contents of the config file
- contents, err := ioutil.ReadFile(configPath)
- if err != nil {
- return nil, errors.Wrapf(err, "error reading configuration file %s", configPath)
- }
-
- // Decode configuration file
- if _, err := toml.Decode(string(contents), runtime.config); err != nil {
- return nil, errors.Wrapf(err, "error decoding configuration from file %s", configPath)
- }
-
- // Overwrite the config with user-given configuration options
- for _, opt := range options {
- if err := opt(runtime); err != nil {
- return nil, errors.Wrapf(err, "error configuring runtime")
- }
- }
-
- if err := makeRuntime(runtime); err != nil {
- return nil, err
- }
-
- return runtime, nil
-}
-
// Make a new runtime based on the given configuration
// Sets up containers/storage, state store, OCI runtime
func makeRuntime(runtime *Runtime) (err error) {
- runtime.config.EventsLogFilePath = filepath.Join(runtime.config.TmpDir, "events", "events.log")
-
// Backward compatibility for `runtime_path`
if runtime.config.RuntimePath != nil {
// Don't print twice in rootless mode.
@@ -697,6 +687,8 @@ func makeRuntime(runtime *Runtime) (err error) {
runtime.config.VolumePath = dbConfig.VolumePath
}
+ runtime.config.EventsLogFilePath = filepath.Join(runtime.config.TmpDir, "events", "events.log")
+
logrus.Debugf("Using graph driver %s", runtime.config.StorageConfig.GraphDriverName)
logrus.Debugf("Using graph root %s", runtime.config.StorageConfig.GraphRoot)
logrus.Debugf("Using run root %s", runtime.config.StorageConfig.RunRoot)
diff --git a/test/test_podman_build.sh b/test/test_podman_build.sh
index 9faefc78a..39f1e784d 100644
--- a/test/test_podman_build.sh
+++ b/test/test_podman_build.sh
@@ -34,6 +34,13 @@ echo ########################################################
echo ########################################################
+echo test "build directory before other options create a tag"
+echo ########################################################
+TARGET=tagged-image
+podman build $HOME/test/build/from-scratch --quiet=True -t $TARGET
+podman images | grep tagged-image
+
+echo ########################################################
echo test "build-preserve-subvolumes"
echo ########################################################
TARGET=volume-image