summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml21
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--cmd/podman/common/completion.go2
-rw-r--r--cmd/podman/common/create.go14
-rw-r--r--cmd/podman/containers/create.go6
-rw-r--r--cmd/podman/main.go9
-rw-r--r--cmd/podman/pods/clone.go6
-rw-r--r--cmd/podman/system/prune.go6
-rw-r--r--cmd/podman/utils/utils.go15
-rw-r--r--completions/bash/podman177
-rw-r--r--completions/bash/podman-remote177
-rw-r--r--completions/fish/podman-remote.fish3
-rw-r--r--completions/fish/podman.fish3
-rw-r--r--completions/powershell/podman-remote.ps15
-rw-r--r--completions/powershell/podman.ps15
-rw-r--r--completions/zsh/_podman32
-rw-r--r--completions/zsh/_podman-remote32
-rw-r--r--docs/source/markdown/podman-create.1.md18
-rw-r--r--docs/source/markdown/podman-exec.1.md7
-rw-r--r--docs/source/markdown/podman-network-ls.1.md3
-rw-r--r--docs/source/markdown/podman-pod-clone.1.md6
-rw-r--r--docs/source/markdown/podman-pod-create.1.md7
-rw-r--r--docs/source/markdown/podman-run.1.md14
-rw-r--r--docs/source/markdown/podman-system-prune.1.md6
-rw-r--r--docs/source/markdown/podman-system.1.md20
-rw-r--r--go.mod4
-rw-r--r--go.sum10
-rw-r--r--libpod/container_config.go10
-rw-r--r--libpod/container_internal_linux.go14
-rw-r--r--libpod/networking_linux.go8
-rw-r--r--pkg/api/handlers/compat/containers_stats.go8
-rw-r--r--pkg/api/handlers/libpod/containers.go4
-rw-r--r--pkg/domain/entities/system.go1
-rw-r--r--pkg/domain/infra/abi/network.go86
-rw-r--r--pkg/domain/infra/abi/system.go48
-rw-r--r--pkg/rootless/rootless_linux.c24
-rw-r--r--pkg/rootless/rootless_linux.go35
-rw-r--r--pkg/specgen/generate/container.go1
-rw-r--r--pkg/specgen/generate/container_create.go5
-rw-r--r--pkg/specgen/podspecgen.go4
-rw-r--r--test/apiv2/20-containers.at18
-rw-r--r--test/apiv2/35-networks.at4
-rw-r--r--test/e2e/network_test.go20
-rw-r--r--test/e2e/pod_clone_test.go17
-rw-r--r--test/e2e/pod_create_test.go23
-rw-r--r--test/e2e/prune_test.go23
-rw-r--r--vendor/github.com/spf13/cobra/CHANGELOG.md51
-rw-r--r--vendor/github.com/spf13/cobra/README.md6
-rw-r--r--vendor/github.com/spf13/cobra/active_help.go49
-rw-r--r--vendor/github.com/spf13/cobra/active_help.md157
-rw-r--r--vendor/github.com/spf13/cobra/bash_completions.go19
-rw-r--r--vendor/github.com/spf13/cobra/bash_completionsV2.go180
-rw-r--r--vendor/github.com/spf13/cobra/command.go26
-rw-r--r--vendor/github.com/spf13/cobra/completions.go27
-rw-r--r--vendor/github.com/spf13/cobra/fish_completions.go9
-rw-r--r--vendor/github.com/spf13/cobra/flag_groups.go223
-rw-r--r--vendor/github.com/spf13/cobra/go.mod2
-rw-r--r--vendor/github.com/spf13/cobra/go.sum12
-rw-r--r--vendor/github.com/spf13/cobra/powershell_completions.go7
-rw-r--r--vendor/github.com/spf13/cobra/projects_using_cobra.md13
-rw-r--r--vendor/github.com/spf13/cobra/shell_completions.md6
-rw-r--r--vendor/github.com/spf13/cobra/user_guide.md40
-rw-r--r--vendor/github.com/spf13/cobra/zsh_completions.go35
-rw-r--r--vendor/github.com/stretchr/testify/assert/assertions.go7
-rw-r--r--vendor/modules.txt4
65 files changed, 1363 insertions, 473 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index d5298d62e..06f4a565c 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -608,27 +608,28 @@ remote_system_test_task:
<<: *local_system_test_task
alias: remote_system_test
depends_on:
- - remote_integration_test
+ - build
+ - remote_integration_test
env:
TEST_FLAVOR: sys
PODBIN_NAME: remote
rootless_remote_system_test_task:
+ matrix:
+ # Minimal sanity testing: only the latest Fedora
+ - env:
+ DISTRO_NV: ${FEDORA_NAME}
+ # Not used here, is used in other tasks
+ VM_IMAGE_NAME: ${FEDORA_CACHE_IMAGE_NAME}
+ CTR_FQIN: ${FEDORA_CONTAINER_FQIN}
+ # ID for re-use of build output
+ _BUILD_CACHE_HANDLE: ${FEDORA_NAME}-build-${CIRRUS_BUILD_ID}
<<: *local_system_test_task
alias: rootless_remote_system_test
depends_on:
- build
- remote_integration_test
- matrix:
- # Minimal sanity testing: only the latest Fedora
- - env:
- DISTRO_NV: ${FEDORA_NAME}
- # Not used here, is used in other tasks
- VM_IMAGE_NAME: ${FEDORA_CACHE_IMAGE_NAME}
- CTR_FQIN: ${FEDORA_CONTAINER_FQIN}
- # ID for re-use of build output
- _BUILD_CACHE_HANDLE: ${FEDORA_NAME}-build-${CIRRUS_BUILD_ID}
gce_instance: *standardvm
env:
TEST_FLAVOR: sys
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6b63c7b5a..eddd35cba 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -70,7 +70,7 @@ $ cd $GOPATH/src/github.com/containers/podman
### Deal with make
-Podman use a Makefile to realize common action like building etc...
+Podman uses a Makefile to realize common actions like building etc...
You can list available actions by using:
```shell
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go
index aeb051001..89e53c180 100644
--- a/cmd/podman/common/completion.go
+++ b/cmd/podman/common/completion.go
@@ -71,7 +71,7 @@ func setupImageEngine(cmd *cobra.Command) (entities.ImageEngine, error) {
return nil, err
}
// we also need to set up the container engine since this
- // is required to setup the rootless namespace
+ // is required to set up the rootless namespace
if _, err = setupContainerEngine(cmd); err != nil {
return nil, err
}
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go
index 40bb0df78..e25bdd241 100644
--- a/cmd/podman/common/create.go
+++ b/cmd/podman/common/create.go
@@ -452,13 +452,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(secretFlagName, AutocompleteSecrets)
- shmSizeFlagName := "shm-size"
- createFlags.String(
- shmSizeFlagName, shmSize(),
- "Size of /dev/shm "+sizeWithUnitFormat,
- )
- _ = cmd.RegisterFlagCompletionFunc(shmSizeFlagName, completion.AutocompleteNone)
-
stopSignalFlagName := "stop-signal"
createFlags.StringVar(
&cf.StopSignal,
@@ -628,6 +621,13 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
}
if isInfra || (!clone && !isInfra) { // infra container flags, create should also pick these up
+ shmSizeFlagName := "shm-size"
+ createFlags.String(
+ shmSizeFlagName, shmSize(),
+ "Size of /dev/shm "+sizeWithUnitFormat,
+ )
+ _ = cmd.RegisterFlagCompletionFunc(shmSizeFlagName, completion.AutocompleteNone)
+
sysctlFlagName := "sysctl"
createFlags.StringSliceVar(
&cf.Sysctl,
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index a214ae8aa..c021aa031 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -217,9 +217,6 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra
}
if !isInfra {
- if c.Flag("shm-size").Changed {
- vals.ShmSize = c.Flag("shm-size").Value.String()
- }
if c.Flag("cpu-period").Changed && c.Flag("cpus").Changed {
return vals, errors.Errorf("--cpu-period and --cpus cannot be set together")
}
@@ -283,6 +280,9 @@ func CreateInit(c *cobra.Command, vals entities.ContainerCreateOptions, isInfra
return vals, errors.Errorf("--userns and --pod cannot be set together")
}
}
+ if c.Flag("shm-size").Changed {
+ vals.ShmSize = c.Flag("shm-size").Value.String()
+ }
if (c.Flag("dns").Changed || c.Flag("dns-opt").Changed || c.Flag("dns-search").Changed) && vals.Net != nil && (vals.Net.Network.NSMode == specgen.NoNetwork || vals.Net.Network.IsContainer()) {
return vals, errors.Errorf("conflicting options: dns and the network mode: " + string(vals.Net.Network.NSMode))
}
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index c6ba69e94..929c8a757 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -1,7 +1,6 @@
package main
import (
- "errors"
"fmt"
"os"
@@ -27,7 +26,6 @@ import (
"github.com/containers/storage/pkg/reexec"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
- "github.com/spf13/pflag"
)
func main() {
@@ -103,13 +101,6 @@ func parseCommands() *cobra.Command {
}
func flagErrorFuncfunc(c *cobra.Command, e error) error {
- // cobra compares via == and not errors.Is so we cannot wrap that error.
- // This is required to make podman -h work.
- // This can be removed once https://github.com/spf13/cobra/pull/1730
- // is merged and vendored into podman.
- if errors.Is(e, pflag.ErrHelp) {
- return e
- }
e = fmt.Errorf("%w\nSee '%s --help'", e, c.CommandPath())
return e
}
diff --git a/cmd/podman/pods/clone.go b/cmd/podman/pods/clone.go
index d95d74b05..391af1cf7 100644
--- a/cmd/podman/pods/clone.go
+++ b/cmd/podman/pods/clone.go
@@ -46,6 +46,7 @@ func cloneFlags(cmd *cobra.Command) {
common.DefineCreateDefaults(&podClone.InfraOptions)
common.DefineCreateFlags(cmd, &podClone.InfraOptions, true, false)
+
podClone.InfraOptions.MemorySwappiness = -1 // this is not implemented for pods yet, need to set -1 default manually
// need to fill an empty ctr create option for each container for sane defaults
@@ -72,6 +73,11 @@ func clone(cmd *cobra.Command, args []string) error {
}
podClone.ID = args[0]
+
+ if cmd.Flag("shm-size").Changed {
+ podClone.InfraOptions.ShmSize = cmd.Flag("shm-size").Value.String()
+ }
+
podClone.PerContainerOptions.IsClone = true
rep, err := registry.ContainerEngine().PodClone(context.Background(), podClone)
if err != nil {
diff --git a/cmd/podman/system/prune.go b/cmd/podman/system/prune.go
index ff78f93bb..1d6ba8155 100644
--- a/cmd/podman/system/prune.go
+++ b/cmd/podman/system/prune.go
@@ -75,6 +75,7 @@ func prune(cmd *cobra.Command, args []string) error {
}
}
+ // Remove all unused pods, containers, images, networks, and volume data.
pruneOptions.Filters, err = parse.FilterArgumentsIntoFilters(filters)
if err != nil {
return err
@@ -106,6 +107,11 @@ func prune(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
+ // Print Network prune results
+ err = utils.PrintNetworkPruneResults(response.NetworkPruneReports, true)
+ if err != nil {
+ return err
+ }
fmt.Printf("Total reclaimed space: %s\n", units.HumanSize((float64)(response.ReclaimedSpace)))
return nil
diff --git a/cmd/podman/utils/utils.go b/cmd/podman/utils/utils.go
index 6fd6647d0..73bb34983 100644
--- a/cmd/podman/utils/utils.go
+++ b/cmd/podman/utils/utils.go
@@ -84,3 +84,18 @@ func PrintImagePruneResults(imagePruneReports []*reports.PruneReport, heading bo
return nil
}
+
+func PrintNetworkPruneResults(networkPruneReport []*reports.PruneReport, heading bool) error {
+ var errs OutputErrors
+ if heading && len(networkPruneReport) > 0 {
+ fmt.Println("Deleted Networks")
+ }
+ for _, r := range networkPruneReport {
+ if r.Err == nil {
+ fmt.Println(r.Id)
+ } else {
+ errs = append(errs, r.Err)
+ }
+ }
+ return errs.PrintErrors()
+}
diff --git a/completions/bash/podman b/completions/bash/podman
index c7171a9cc..6e6be35a7 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -56,7 +56,7 @@ __podman_get_completion_results() {
directive=0
fi
__podman_debug "The completion directive is: ${directive}"
- __podman_debug "The completions are: ${out[*]}"
+ __podman_debug "The completions are: ${out}"
}
__podman_process_completion_results() {
@@ -89,13 +89,18 @@ __podman_process_completion_results() {
fi
fi
+ # Separate activeHelp from normal completions
+ local completions=()
+ local activeHelp=()
+ __podman_extract_activeHelp
+
if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
# File extension filtering
local fullFilter filter filteringCmd
- # Do not use quotes around the $out variable or else newline
+ # Do not use quotes around the $completions variable or else newline
# characters will be kept.
- for filter in ${out[*]}; do
+ for filter in ${completions[*]}; do
fullFilter+="$filter|"
done
@@ -107,7 +112,7 @@ __podman_process_completion_results() {
# Use printf to strip any trailing newline
local subdir
- subdir=$(printf "%s" "${out[0]}")
+ subdir=$(printf "%s" "${completions[0]}")
if [ -n "$subdir" ]; then
__podman_debug "Listing directories in $subdir"
pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
@@ -121,6 +126,43 @@ __podman_process_completion_results() {
__podman_handle_special_char "$cur" :
__podman_handle_special_char "$cur" =
+
+ # Print the activeHelp statements before we finish
+ if [ ${#activeHelp} -ne 0 ]; then
+ printf "\n";
+ printf "%s\n" "${activeHelp[@]}"
+ printf "\n"
+
+ # The prompt format is only available from bash 4.4.
+ # We test if it is available before using it.
+ if (x=${PS1@P}) 2> /dev/null; then
+ printf "%s" "${PS1@P}${COMP_LINE[@]}"
+ else
+ # Can't print the prompt. Just print the
+ # text the user had typed, it is workable enough.
+ printf "%s" "${COMP_LINE[@]}"
+ fi
+ fi
+}
+
+# Separate activeHelp lines from real completions.
+# Fills the $activeHelp and $completions arrays.
+__podman_extract_activeHelp() {
+ local activeHelpMarker="_activeHelp_ "
+ local endIndex=${#activeHelpMarker}
+
+ while IFS='' read -r comp; do
+ if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then
+ comp=${comp:endIndex}
+ __podman_debug "ActiveHelp found: $comp"
+ if [ -n "$comp" ]; then
+ activeHelp+=("$comp")
+ fi
+ else
+ # Not an activeHelp line but a normal completion
+ completions+=("$comp")
+ fi
+ done < <(printf "%s\n" "${out}")
}
__podman_handle_completion_types() {
@@ -132,17 +174,16 @@ __podman_handle_completion_types() {
# If the user requested inserting one completion at a time, or all
# completions at once on the command-line we must remove the descriptions.
# https://github.com/spf13/cobra/issues/1508
- local tab comp
- tab=$(printf '\t')
+ local tab=$'\t' comp
while IFS='' read -r comp; do
+ [[ -z $comp ]] && continue
# Strip any description
comp=${comp%%$tab*}
# Only consider the completions that match
- comp=$(compgen -W "$comp" -- "$cur")
- if [ -n "$comp" ]; then
+ if [[ $comp == "$cur"* ]]; then
COMPREPLY+=("$comp")
fi
- done < <(printf "%s\n" "${out[@]}")
+ done < <(printf "%s\n" "${completions[@]}")
;;
*)
@@ -153,44 +194,37 @@ __podman_handle_completion_types() {
}
__podman_handle_standard_completion_case() {
- local tab comp
- tab=$(printf '\t')
+ local tab=$'\t' comp
+
+ # Short circuit to optimize if we don't have descriptions
+ if [[ "${completions[*]}" != *$tab* ]]; then
+ IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur")
+ return 0
+ fi
local longest=0
+ local compline
# Look for the longest completion so that we can format things nicely
- while IFS='' read -r comp; do
+ while IFS='' read -r compline; do
+ [[ -z $compline ]] && continue
# Strip any description before checking the length
- comp=${comp%%$tab*}
+ comp=${compline%%$tab*}
# Only consider the completions that match
- comp=$(compgen -W "$comp" -- "$cur")
+ [[ $comp == "$cur"* ]] || continue
+ COMPREPLY+=("$compline")
if ((${#comp}>longest)); then
longest=${#comp}
fi
- done < <(printf "%s\n" "${out[@]}")
-
- local completions=()
- while IFS='' read -r comp; do
- if [ -z "$comp" ]; then
- continue
- fi
-
- __podman_debug "Original comp: $comp"
- comp="$(__podman_format_comp_descriptions "$comp" "$longest")"
- __podman_debug "Final comp: $comp"
- completions+=("$comp")
- done < <(printf "%s\n" "${out[@]}")
-
- while IFS='' read -r comp; do
- COMPREPLY+=("$comp")
- done < <(compgen -W "${completions[*]}" -- "$cur")
+ done < <(printf "%s\n" "${completions[@]}")
# If there is a single completion left, remove the description text
if [ ${#COMPREPLY[*]} -eq 1 ]; then
__podman_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
- comp="${COMPREPLY[0]%% *}"
+ comp="${COMPREPLY[0]%%$tab*}"
__podman_debug "Removed description from single completion, which is now: ${comp}"
- COMPREPLY=()
- COMPREPLY+=("$comp")
+ COMPREPLY[0]=$comp
+ else # Format the descriptions
+ __podman_format_comp_descriptions $longest
fi
}
@@ -209,45 +243,48 @@ __podman_handle_special_char()
__podman_format_comp_descriptions()
{
- local tab
- tab=$(printf '\t')
- local comp="$1"
- local longest=$2
-
- # Properly format the description string which follows a tab character if there is one
- if [[ "$comp" == *$tab* ]]; then
- desc=${comp#*$tab}
- comp=${comp%%$tab*}
-
- # $COLUMNS stores the current shell width.
- # Remove an extra 4 because we add 2 spaces and 2 parentheses.
- maxdesclength=$(( COLUMNS - longest - 4 ))
-
- # Make sure we can fit a description of at least 8 characters
- # if we are to align the descriptions.
- if [[ $maxdesclength -gt 8 ]]; then
- # Add the proper number of spaces to align the descriptions
- for ((i = ${#comp} ; i < longest ; i++)); do
- comp+=" "
- done
- else
- # Don't pad the descriptions so we can fit more text after the completion
- maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
- fi
+ local tab=$'\t'
+ local comp desc maxdesclength
+ local longest=$1
+
+ local i ci
+ for ci in ${!COMPREPLY[*]}; do
+ comp=${COMPREPLY[ci]}
+ # Properly format the description string which follows a tab character if there is one
+ if [[ "$comp" == *$tab* ]]; then
+ __podman_debug "Original comp: $comp"
+ desc=${comp#*$tab}
+ comp=${comp%%$tab*}
+
+ # $COLUMNS stores the current shell width.
+ # Remove an extra 4 because we add 2 spaces and 2 parentheses.
+ maxdesclength=$(( COLUMNS - longest - 4 ))
+
+ # Make sure we can fit a description of at least 8 characters
+ # if we are to align the descriptions.
+ if [[ $maxdesclength -gt 8 ]]; then
+ # Add the proper number of spaces to align the descriptions
+ for ((i = ${#comp} ; i < longest ; i++)); do
+ comp+=" "
+ done
+ else
+ # Don't pad the descriptions so we can fit more text after the completion
+ maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
+ fi
- # If there is enough space for any description text,
- # truncate the descriptions that are too long for the shell width
- if [ $maxdesclength -gt 0 ]; then
- if [ ${#desc} -gt $maxdesclength ]; then
- desc=${desc:0:$(( maxdesclength - 1 ))}
- desc+="…"
+ # If there is enough space for any description text,
+ # truncate the descriptions that are too long for the shell width
+ if [ $maxdesclength -gt 0 ]; then
+ if [ ${#desc} -gt $maxdesclength ]; then
+ desc=${desc:0:$(( maxdesclength - 1 ))}
+ desc+="…"
+ fi
+ comp+=" ($desc)"
fi
- comp+=" ($desc)"
+ COMPREPLY[ci]=$comp
+ __podman_debug "Final comp: $comp"
fi
- fi
-
- # Must use printf to escape all special characters
- printf "%q" "${comp}"
+ done
}
__start_podman()
diff --git a/completions/bash/podman-remote b/completions/bash/podman-remote
index b5150e208..b8343c270 100644
--- a/completions/bash/podman-remote
+++ b/completions/bash/podman-remote
@@ -56,7 +56,7 @@ __podman-remote_get_completion_results() {
directive=0
fi
__podman-remote_debug "The completion directive is: ${directive}"
- __podman-remote_debug "The completions are: ${out[*]}"
+ __podman-remote_debug "The completions are: ${out}"
}
__podman-remote_process_completion_results() {
@@ -89,13 +89,18 @@ __podman-remote_process_completion_results() {
fi
fi
+ # Separate activeHelp from normal completions
+ local completions=()
+ local activeHelp=()
+ __podman-remote_extract_activeHelp
+
if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
# File extension filtering
local fullFilter filter filteringCmd
- # Do not use quotes around the $out variable or else newline
+ # Do not use quotes around the $completions variable or else newline
# characters will be kept.
- for filter in ${out[*]}; do
+ for filter in ${completions[*]}; do
fullFilter+="$filter|"
done
@@ -107,7 +112,7 @@ __podman-remote_process_completion_results() {
# Use printf to strip any trailing newline
local subdir
- subdir=$(printf "%s" "${out[0]}")
+ subdir=$(printf "%s" "${completions[0]}")
if [ -n "$subdir" ]; then
__podman-remote_debug "Listing directories in $subdir"
pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
@@ -121,6 +126,43 @@ __podman-remote_process_completion_results() {
__podman-remote_handle_special_char "$cur" :
__podman-remote_handle_special_char "$cur" =
+
+ # Print the activeHelp statements before we finish
+ if [ ${#activeHelp} -ne 0 ]; then
+ printf "\n";
+ printf "%s\n" "${activeHelp[@]}"
+ printf "\n"
+
+ # The prompt format is only available from bash 4.4.
+ # We test if it is available before using it.
+ if (x=${PS1@P}) 2> /dev/null; then
+ printf "%s" "${PS1@P}${COMP_LINE[@]}"
+ else
+ # Can't print the prompt. Just print the
+ # text the user had typed, it is workable enough.
+ printf "%s" "${COMP_LINE[@]}"
+ fi
+ fi
+}
+
+# Separate activeHelp lines from real completions.
+# Fills the $activeHelp and $completions arrays.
+__podman-remote_extract_activeHelp() {
+ local activeHelpMarker="_activeHelp_ "
+ local endIndex=${#activeHelpMarker}
+
+ while IFS='' read -r comp; do
+ if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then
+ comp=${comp:endIndex}
+ __podman-remote_debug "ActiveHelp found: $comp"
+ if [ -n "$comp" ]; then
+ activeHelp+=("$comp")
+ fi
+ else
+ # Not an activeHelp line but a normal completion
+ completions+=("$comp")
+ fi
+ done < <(printf "%s\n" "${out}")
}
__podman-remote_handle_completion_types() {
@@ -132,17 +174,16 @@ __podman-remote_handle_completion_types() {
# If the user requested inserting one completion at a time, or all
# completions at once on the command-line we must remove the descriptions.
# https://github.com/spf13/cobra/issues/1508
- local tab comp
- tab=$(printf '\t')
+ local tab=$'\t' comp
while IFS='' read -r comp; do
+ [[ -z $comp ]] && continue
# Strip any description
comp=${comp%%$tab*}
# Only consider the completions that match
- comp=$(compgen -W "$comp" -- "$cur")
- if [ -n "$comp" ]; then
+ if [[ $comp == "$cur"* ]]; then
COMPREPLY+=("$comp")
fi
- done < <(printf "%s\n" "${out[@]}")
+ done < <(printf "%s\n" "${completions[@]}")
;;
*)
@@ -153,44 +194,37 @@ __podman-remote_handle_completion_types() {
}
__podman-remote_handle_standard_completion_case() {
- local tab comp
- tab=$(printf '\t')
+ local tab=$'\t' comp
+
+ # Short circuit to optimize if we don't have descriptions
+ if [[ "${completions[*]}" != *$tab* ]]; then
+ IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur")
+ return 0
+ fi
local longest=0
+ local compline
# Look for the longest completion so that we can format things nicely
- while IFS='' read -r comp; do
+ while IFS='' read -r compline; do
+ [[ -z $compline ]] && continue
# Strip any description before checking the length
- comp=${comp%%$tab*}
+ comp=${compline%%$tab*}
# Only consider the completions that match
- comp=$(compgen -W "$comp" -- "$cur")
+ [[ $comp == "$cur"* ]] || continue
+ COMPREPLY+=("$compline")
if ((${#comp}>longest)); then
longest=${#comp}
fi
- done < <(printf "%s\n" "${out[@]}")
-
- local completions=()
- while IFS='' read -r comp; do
- if [ -z "$comp" ]; then
- continue
- fi
-
- __podman-remote_debug "Original comp: $comp"
- comp="$(__podman-remote_format_comp_descriptions "$comp" "$longest")"
- __podman-remote_debug "Final comp: $comp"
- completions+=("$comp")
- done < <(printf "%s\n" "${out[@]}")
-
- while IFS='' read -r comp; do
- COMPREPLY+=("$comp")
- done < <(compgen -W "${completions[*]}" -- "$cur")
+ done < <(printf "%s\n" "${completions[@]}")
# If there is a single completion left, remove the description text
if [ ${#COMPREPLY[*]} -eq 1 ]; then
__podman-remote_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
- comp="${COMPREPLY[0]%% *}"
+ comp="${COMPREPLY[0]%%$tab*}"
__podman-remote_debug "Removed description from single completion, which is now: ${comp}"
- COMPREPLY=()
- COMPREPLY+=("$comp")
+ COMPREPLY[0]=$comp
+ else # Format the descriptions
+ __podman-remote_format_comp_descriptions $longest
fi
}
@@ -209,45 +243,48 @@ __podman-remote_handle_special_char()
__podman-remote_format_comp_descriptions()
{
- local tab
- tab=$(printf '\t')
- local comp="$1"
- local longest=$2
-
- # Properly format the description string which follows a tab character if there is one
- if [[ "$comp" == *$tab* ]]; then
- desc=${comp#*$tab}
- comp=${comp%%$tab*}
-
- # $COLUMNS stores the current shell width.
- # Remove an extra 4 because we add 2 spaces and 2 parentheses.
- maxdesclength=$(( COLUMNS - longest - 4 ))
-
- # Make sure we can fit a description of at least 8 characters
- # if we are to align the descriptions.
- if [[ $maxdesclength -gt 8 ]]; then
- # Add the proper number of spaces to align the descriptions
- for ((i = ${#comp} ; i < longest ; i++)); do
- comp+=" "
- done
- else
- # Don't pad the descriptions so we can fit more text after the completion
- maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
- fi
+ local tab=$'\t'
+ local comp desc maxdesclength
+ local longest=$1
+
+ local i ci
+ for ci in ${!COMPREPLY[*]}; do
+ comp=${COMPREPLY[ci]}
+ # Properly format the description string which follows a tab character if there is one
+ if [[ "$comp" == *$tab* ]]; then
+ __podman-remote_debug "Original comp: $comp"
+ desc=${comp#*$tab}
+ comp=${comp%%$tab*}
+
+ # $COLUMNS stores the current shell width.
+ # Remove an extra 4 because we add 2 spaces and 2 parentheses.
+ maxdesclength=$(( COLUMNS - longest - 4 ))
+
+ # Make sure we can fit a description of at least 8 characters
+ # if we are to align the descriptions.
+ if [[ $maxdesclength -gt 8 ]]; then
+ # Add the proper number of spaces to align the descriptions
+ for ((i = ${#comp} ; i < longest ; i++)); do
+ comp+=" "
+ done
+ else
+ # Don't pad the descriptions so we can fit more text after the completion
+ maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
+ fi
- # If there is enough space for any description text,
- # truncate the descriptions that are too long for the shell width
- if [ $maxdesclength -gt 0 ]; then
- if [ ${#desc} -gt $maxdesclength ]; then
- desc=${desc:0:$(( maxdesclength - 1 ))}
- desc+="…"
+ # If there is enough space for any description text,
+ # truncate the descriptions that are too long for the shell width
+ if [ $maxdesclength -gt 0 ]; then
+ if [ ${#desc} -gt $maxdesclength ]; then
+ desc=${desc:0:$(( maxdesclength - 1 ))}
+ desc+="…"
+ fi
+ comp+=" ($desc)"
fi
- comp+=" ($desc)"
+ COMPREPLY[ci]=$comp
+ __podman-remote_debug "Final comp: $comp"
fi
- fi
-
- # Must use printf to escape all special characters
- printf "%q" "${comp}"
+ done
}
__start_podman-remote()
diff --git a/completions/fish/podman-remote.fish b/completions/fish/podman-remote.fish
index bcfacbb00..67c964133 100644
--- a/completions/fish/podman-remote.fish
+++ b/completions/fish/podman-remote.fish
@@ -18,7 +18,8 @@ function __podman_remote_perform_completion
__podman_remote_debug "args: $args"
__podman_remote_debug "last arg: $lastArg"
- set -l requestComp "$args[1] __complete $args[2..-1] $lastArg"
+ # Disable ActiveHelp which is not supported for fish shell
+ set -l requestComp "PODMAN_REMOTE_ACTIVE_HELP=0 $args[1] __complete $args[2..-1] $lastArg"
__podman_remote_debug "Calling $requestComp"
set -l results (eval $requestComp 2> /dev/null)
diff --git a/completions/fish/podman.fish b/completions/fish/podman.fish
index 6394535a9..be18c45cd 100644
--- a/completions/fish/podman.fish
+++ b/completions/fish/podman.fish
@@ -18,7 +18,8 @@ function __podman_perform_completion
__podman_debug "args: $args"
__podman_debug "last arg: $lastArg"
- set -l requestComp "$args[1] __complete $args[2..-1] $lastArg"
+ # Disable ActiveHelp which is not supported for fish shell
+ set -l requestComp "PODMAN_ACTIVE_HELP=0 $args[1] __complete $args[2..-1] $lastArg"
__podman_debug "Calling $requestComp"
set -l results (eval $requestComp 2> /dev/null)
diff --git a/completions/powershell/podman-remote.ps1 b/completions/powershell/podman-remote.ps1
index 2edc79ffb..d810ab8dd 100644
--- a/completions/powershell/podman-remote.ps1
+++ b/completions/powershell/podman-remote.ps1
@@ -44,6 +44,7 @@ Register-ArgumentCompleter -CommandName 'podman-remote' -ScriptBlock {
# Prepare the command to request completions for the program.
# Split the command at the first space to separate the program and arguments.
$Program,$Arguments = $Command.Split(" ",2)
+
$RequestComp="$Program __complete $Arguments"
__podman-remote_debug "RequestComp: $RequestComp"
@@ -73,11 +74,13 @@ Register-ArgumentCompleter -CommandName 'podman-remote' -ScriptBlock {
}
__podman-remote_debug "Calling $RequestComp"
+ # First disable ActiveHelp which is not supported for Powershell
+ $env:PODMAN_REMOTE_ACTIVE_HELP=0
+
#call the command store the output in $out and redirect stderr and stdout to null
# $Out is an array contains each line per element
Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null
-
# get directive from last line
[int]$Directive = $Out[-1].TrimStart(':')
if ($Directive -eq "") {
diff --git a/completions/powershell/podman.ps1 b/completions/powershell/podman.ps1
index 1cd89d0a0..4d94b6fe8 100644
--- a/completions/powershell/podman.ps1
+++ b/completions/powershell/podman.ps1
@@ -44,6 +44,7 @@ Register-ArgumentCompleter -CommandName 'podman' -ScriptBlock {
# Prepare the command to request completions for the program.
# Split the command at the first space to separate the program and arguments.
$Program,$Arguments = $Command.Split(" ",2)
+
$RequestComp="$Program __complete $Arguments"
__podman_debug "RequestComp: $RequestComp"
@@ -73,11 +74,13 @@ Register-ArgumentCompleter -CommandName 'podman' -ScriptBlock {
}
__podman_debug "Calling $RequestComp"
+ # First disable ActiveHelp which is not supported for Powershell
+ $env:PODMAN_ACTIVE_HELP=0
+
#call the command store the output in $out and redirect stderr and stdout to null
# $Out is an array contains each line per element
Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null
-
# get directive from last line
[int]$Directive = $Out[-1].TrimStart(':')
if ($Directive -eq "") {
diff --git a/completions/zsh/_podman b/completions/zsh/_podman
index 7c3d6faf3..e2d086108 100644
--- a/completions/zsh/_podman
+++ b/completions/zsh/_podman
@@ -1,4 +1,4 @@
-#compdef _podman podman
+#compdef podman
# zsh completion for podman -*- shell-script -*-
@@ -86,7 +86,24 @@ _podman()
return
fi
+ local activeHelpMarker="_activeHelp_ "
+ local endIndex=${#activeHelpMarker}
+ local startIndex=$((${#activeHelpMarker}+1))
+ local hasActiveHelp=0
while IFS='\n' read -r comp; do
+ # Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker)
+ if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then
+ __podman_debug "ActiveHelp found: $comp"
+ comp="${comp[$startIndex,-1]}"
+ if [ -n "$comp" ]; then
+ compadd -x "${comp}"
+ __podman_debug "ActiveHelp will need delimiter"
+ hasActiveHelp=1
+ fi
+
+ continue
+ fi
+
if [ -n "$comp" ]; then
# If requested, completions are returned with a description.
# The description is preceded by a TAB character.
@@ -94,7 +111,7 @@ _podman()
# We first need to escape any : as part of the completion itself.
comp=${comp//:/\\:}
- local tab=$(printf '\t')
+ local tab="$(printf '\t')"
comp=${comp//$tab/:}
__podman_debug "Adding completion: ${comp}"
@@ -103,6 +120,17 @@ _podman()
fi
done < <(printf "%s\n" "${out[@]}")
+ # Add a delimiter after the activeHelp statements, but only if:
+ # - there are completions following the activeHelp statements, or
+ # - file completion will be performed (so there will be choices after the activeHelp)
+ if [ $hasActiveHelp -eq 1 ]; then
+ if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then
+ __podman_debug "Adding activeHelp delimiter"
+ compadd -x "--"
+ hasActiveHelp=0
+ fi
+ fi
+
if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then
__podman_debug "Activating nospace."
noSpace="-S ''"
diff --git a/completions/zsh/_podman-remote b/completions/zsh/_podman-remote
index a2d24af25..2d7e7a549 100644
--- a/completions/zsh/_podman-remote
+++ b/completions/zsh/_podman-remote
@@ -1,4 +1,4 @@
-#compdef _podman-remote podman-remote
+#compdef podman-remote
# zsh completion for podman-remote -*- shell-script -*-
@@ -86,7 +86,24 @@ _podman-remote()
return
fi
+ local activeHelpMarker="_activeHelp_ "
+ local endIndex=${#activeHelpMarker}
+ local startIndex=$((${#activeHelpMarker}+1))
+ local hasActiveHelp=0
while IFS='\n' read -r comp; do
+ # Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker)
+ if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then
+ __podman-remote_debug "ActiveHelp found: $comp"
+ comp="${comp[$startIndex,-1]}"
+ if [ -n "$comp" ]; then
+ compadd -x "${comp}"
+ __podman-remote_debug "ActiveHelp will need delimiter"
+ hasActiveHelp=1
+ fi
+
+ continue
+ fi
+
if [ -n "$comp" ]; then
# If requested, completions are returned with a description.
# The description is preceded by a TAB character.
@@ -94,7 +111,7 @@ _podman-remote()
# We first need to escape any : as part of the completion itself.
comp=${comp//:/\\:}
- local tab=$(printf '\t')
+ local tab="$(printf '\t')"
comp=${comp//$tab/:}
__podman-remote_debug "Adding completion: ${comp}"
@@ -103,6 +120,17 @@ _podman-remote()
fi
done < <(printf "%s\n" "${out[@]}")
+ # Add a delimiter after the activeHelp statements, but only if:
+ # - there are completions following the activeHelp statements, or
+ # - file completion will be performed (so there will be choices after the activeHelp)
+ if [ $hasActiveHelp -eq 1 ]; then
+ if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then
+ __podman-remote_debug "Adding activeHelp delimiter"
+ compadd -x "--"
+ hasActiveHelp=0
+ fi
+ fi
+
if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then
__podman-remote_debug "Activating nospace."
noSpace="-S ''"
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index f464acde0..624b0b384 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -349,7 +349,7 @@ You need to specify multi option commands in the form of a json string.
Set environment variables
-This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. If an environment variable ending in __*__ is specified, Podman will search the host environment for variables starting with the prefix and will add those variables to the container. If an environment variable with a trailing ***** is specified, then a value must be supplied.
+This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. As a special case, if an environment variable ending in __*__ is specified without a value, Podman will search the host environment for variables starting with the prefix and will add those variables to the container.
See [**Environment**](#environment) note below for precedence and examples.
@@ -1603,17 +1603,17 @@ Precedence order (later entries override earlier entries):
- **--env-file** : Any environment variables specified via env-files. If multiple files specified, then they override each other in order of entry.
- **--env** : Any environment variables specified will override previous settings.
-Create containers and set the environment ending with a __*__ and a *****
+Create containers and set the environment ending with a __*__.
+The trailing __*__ glob functionality is only active when no value is specified:
```
$ export ENV1=a
-$ podman create --name ctr --env ENV* alpine printenv ENV1
-$ podman start --attach ctr
-a
-
-$ podman create --name ctr --env ENV*****=b alpine printenv ENV*****
-$ podman start --attach ctr
-b
+$ podman create --name ctr1 --env 'ENV*' alpine env
+$ podman start --attach ctr1 | grep ENV
+ENV1=a
+$ podman create --name ctr2 --env 'ENV*=b' alpine env
+$ podman start --attach ctr2 | grep ENV
+ENV*=b
```
## CONMON
diff --git a/docs/source/markdown/podman-exec.1.md b/docs/source/markdown/podman-exec.1.md
index 5fb4ceace..da61f3456 100644
--- a/docs/source/markdown/podman-exec.1.md
+++ b/docs/source/markdown/podman-exec.1.md
@@ -21,10 +21,11 @@ Start the exec session, but do not attach to it. The command will run in the bac
Specify the key sequence for detaching a container. Format is a single character `[a-Z]` or one or more `ctrl-<value>` characters where `<value>` is one of: `a-z`, `@`, `^`, `[`, `,` or `_`. Specifying "" will disable this feature. The default is *ctrl-p,ctrl-q*.
-#### **--env**, **-e**
+#### **--env**, **-e**=*env*
-You may specify arbitrary environment variables that are available for the
-command to be executed.
+Set environment variables.
+
+This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. As a special case, if an environment variable ending in __*__ is specified without a value, Podman will search the host environment for variables starting with the prefix and will add those variables to the container.
#### **--env-file**=*file*
diff --git a/docs/source/markdown/podman-network-ls.1.md b/docs/source/markdown/podman-network-ls.1.md
index b341083f9..3c696d404 100644
--- a/docs/source/markdown/podman-network-ls.1.md
+++ b/docs/source/markdown/podman-network-ls.1.md
@@ -25,6 +25,7 @@ Supported filters:
| label | Filter by network with (or without, in the case of label!=[...] is used) the specified labels. |
| name | Filter by network name (accepts `regex`). |
| until | Filter by networks created before given timestamp. |
+| dangling | Filter by networks with no containers attached. |
The `driver` filter accepts values: `bridge`, `macvlan`, `ipvlan`.
@@ -33,6 +34,8 @@ The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*k
The `until` *filter* can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. 10m, 1h30m) computed relative to the machine’s time.
+The `dangling` *filter* accepts values `true` or `false`.
+
#### **--format**=*format*
Change the default output format. This can be of a supported type like 'json'
diff --git a/docs/source/markdown/podman-pod-clone.1.md b/docs/source/markdown/podman-pod-clone.1.md
index c2808c6d0..e44e9fa3c 100644
--- a/docs/source/markdown/podman-pod-clone.1.md
+++ b/docs/source/markdown/podman-pod-clone.1.md
@@ -124,6 +124,12 @@ Note: Labeling can be disabled for all pods/containers by setting label=false in
Note: Labeling can be disabled for all containers by setting label=false in the **containers.conf** (`/etc/containers/containers.conf` or `$HOME/.config/containers/containers.conf`) file.
+#### **--shm-size**=*size*
+
+Size of `/dev/shm` (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))
+If the unit is omitted, the system uses bytes. If the size is omitted, the system uses `64m`.
+When size is `0`, there is no limit on the amount of memory used for IPC by the pod. This option conflicts with **--ipc=host** when running containers.
+
#### **--start**
When set to true, this flag starts the newly created pod after the
diff --git a/docs/source/markdown/podman-pod-create.1.md b/docs/source/markdown/podman-pod-create.1.md
index 8d8bded37..e63623169 100644
--- a/docs/source/markdown/podman-pod-create.1.md
+++ b/docs/source/markdown/podman-pod-create.1.md
@@ -298,6 +298,12 @@ This boolean determines whether or not all containers entering the pod will use
Note: This options conflict with **--share=cgroup** since that would set the pod as the cgroup parent but enter the container into the same cgroupNS as the infra container.
+#### **--shm-size**=*size*
+
+Size of `/dev/shm` (format: `<number>[<unit>]`, where unit = b (bytes), k (kibibytes), m (mebibytes), or g (gibibytes))
+If the unit is omitted, the system uses bytes. If the size is omitted, the system uses `64m`.
+When size is `0`, there is no limit on the amount of memory used for IPC by the pod. This option conflicts with **--ipc=host** when running containers.
+
#### **--subgidname**=*name*
Name for GID map from the `/etc/subgid` file. Using this flag will run the container with user namespace enabled. This flag conflicts with `--userns` and `--gidmap`.
@@ -306,6 +312,7 @@ Name for GID map from the `/etc/subgid` file. Using this flag will run the conta
Name for UID map from the `/etc/subuid` file. Using this flag will run the container with user namespace enabled. This flag conflicts with `--userns` and `--uidmap`.
+
#### **--sysctl**=_name_=_value_
Configure namespace kernel parameters for all containers in the pod.
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 4535de3de..3b886e466 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -385,7 +385,7 @@ You need to specify multi option commands in the form of a json string.
Set environment variables.
-This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. If an environment variable ending in __*__ is specified, Podman will search the host environment for variables starting with the prefix and will add those variables to the container. If an environment variable with a trailing __*__ is specified, then a value must be supplied.
+This option allows arbitrary environment variables that are available for the process to be launched inside of the container. If an environment variable is specified without a value, Podman will check the host environment for a value and set the variable only if it is set on the host. As a special case, if an environment variable ending in __*__ is specified without a value, Podman will search the host environment for variables starting with the prefix and will add those variables to the container.
See [**Environment**](#environment) note below for precedence and examples.
@@ -1982,15 +1982,15 @@ in the following order of precedence (later entries override earlier entries):
- **--env-file**: Any environment variables specified via env-files. If multiple files specified, then they override each other in order of entry.
- **--env**: Any environment variables specified will override previous settings.
-Run containers and set the environment ending with a __*__ and a __*****__:
+Run containers and set the environment ending with a __*__.
+The trailing __*__ glob functionality is only active when no value is specified:
```
$ export ENV1=a
-$ podman run --env ENV* alpine printenv ENV1
-a
-
-$ podman run --env ENV*****=b alpine printenv ENV*****
-b
+$ podman run --env 'ENV*' alpine env | grep ENV
+ENV1=a
+$ podman run --env 'ENV*=b' alpine env | grep ENV
+ENV*=b
```
## CONMON
diff --git a/docs/source/markdown/podman-system-prune.1.md b/docs/source/markdown/podman-system-prune.1.md
index fb9ed44d6..c4c17fbe5 100644
--- a/docs/source/markdown/podman-system-prune.1.md
+++ b/docs/source/markdown/podman-system-prune.1.md
@@ -1,13 +1,13 @@
% podman-system-prune(1)
## NAME
-podman\-system\-prune - Remove all unused pod, container, image and volume data
+podman\-system\-prune - Remove all unused pods, containers, images, networks, and volume data
## SYNOPSIS
**podman system prune** [*options*]
## DESCRIPTION
-**podman system prune** removes all unused containers (both dangling and unreferenced), pods and optionally, volumes from local storage.
+**podman system prune** removes all unused containers (both dangling and unreferenced), pods, networks, and optionally, volumes from local storage.
With the **--all** option, you can delete all unused images. Unused images are dangling images as well as any image that does not have any containers based on it.
@@ -16,7 +16,7 @@ By default, volumes are not removed to prevent important data from being deleted
## OPTIONS
#### **--all**, **-a**
-Recursively remove all unused pod, container, image and volume data (Maximum 50 iterations.)
+Recursively remove all unused pods, containers, images, networks, and volume data. (Maximum 50 iterations.)
#### **--filter**=*filters*
diff --git a/docs/source/markdown/podman-system.1.md b/docs/source/markdown/podman-system.1.md
index ae18aca88..7469eb79d 100644
--- a/docs/source/markdown/podman-system.1.md
+++ b/docs/source/markdown/podman-system.1.md
@@ -11,16 +11,16 @@ The system command allows you to manage the podman systems
## COMMANDS
-| Command | Man Page | Description |
-| ------- | ------------------------------------------------------------ | -------------------------------------------------------------------- |
-| connection | [podman-system-connection(1)](podman-system-connection.1.md) | Manage the destination(s) for Podman service(s) |
-| df | [podman-system-df(1)](podman-system-df.1.md) | Show podman disk usage. |
-| info | [podman-system-info(1)](podman-info.1.md) | Displays Podman related system information. |
-| migrate | [podman-system-migrate(1)](podman-system-migrate.1.md) | Migrate existing containers to a new podman version. |
-| prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused pod, container, image and volume data. |
-| renumber | [podman-system-renumber(1)](podman-system-renumber.1.md) | Migrate lock numbers to handle a change in maximum number of locks. |
-| reset | [podman-system-reset(1)](podman-system-reset.1.md) | Reset storage back to initial state. |
-| service | [podman-system-service(1)](podman-system-service.1.md) | Run an API service |
+| Command | Man Page | Description |
+| ------- | ------------------------------------------------------------ | ------------------------------------------------------------------------ |
+| connection | [podman-system-connection(1)](podman-system-connection.1.md) | Manage the destination(s) for Podman service(s) |
+| df | [podman-system-df(1)](podman-system-df.1.md) | Show podman disk usage. |
+| info | [podman-system-info(1)](podman-info.1.md) | Displays Podman related system information. |
+| migrate | [podman-system-migrate(1)](podman-system-migrate.1.md) | Migrate existing containers to a new podman version. |
+| prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused pods, containers, images, networks, and volume data. |
+| renumber | [podman-system-renumber(1)](podman-system-renumber.1.md) | Migrate lock numbers to handle a change in maximum number of locks. |
+| reset | [podman-system-reset(1)](podman-system-reset.1.md) | Reset storage back to initial state. |
+| service | [podman-system-service(1)](podman-system-service.1.md) | Run an API service |
## SEE ALSO
**[podman(1)](podman.1.md)**
diff --git a/go.mod b/go.mod
index ccd645fd7..6141fe007 100644
--- a/go.mod
+++ b/go.mod
@@ -55,9 +55,9 @@ require (
github.com/pmezard/go-difflib v1.0.0
github.com/rootless-containers/rootlesskit v1.0.1
github.com/sirupsen/logrus v1.8.1
- github.com/spf13/cobra v1.4.0
+ github.com/spf13/cobra v1.5.0
github.com/spf13/pflag v1.0.5
- github.com/stretchr/testify v1.7.2
+ github.com/stretchr/testify v1.7.4
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635
github.com/uber/jaeger-client-go v2.30.0+incompatible
github.com/ulikunitz/xz v0.5.10
diff --git a/go.sum b/go.sum
index 814fc05bd..4440331cd 100644
--- a/go.sum
+++ b/go.sum
@@ -394,6 +394,7 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
@@ -1242,8 +1243,9 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
-github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
+github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
+github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -1264,8 +1266,9 @@ github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag
github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v0.0.0-20170130113145-4d4bfba8f1d1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.1.4/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
@@ -1276,8 +1279,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
+github.com/stretchr/testify v1.7.4 h1:wZRexSlwd7ZXfKINDLsO4r7WBt3gTKONc6K/VesHvHM=
+github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/sylabs/sif/v2 v2.7.0/go.mod h1:TiyBWsgWeh5yBeQFNuQnvROwswqK7YJT8JA1L53bsXQ=
github.com/sylabs/sif/v2 v2.7.1 h1:XXt9AP39sQfsMCGOGQ/XP9H47yqZOvAonalkaCaNIYM=
diff --git a/libpod/container_config.go b/libpod/container_config.go
index 6558f3c89..45ff03d58 100644
--- a/libpod/container_config.go
+++ b/libpod/container_config.go
@@ -194,7 +194,7 @@ type ContainerSecurityConfig struct {
// If not explicitly set, an unused random MLS label will be assigned by
// containers/storage (but only if SELinux is enabled).
MountLabel string `json:"MountLabel,omitempty"`
- // LabelOpts are options passed in by the user to setup SELinux labels.
+ // LabelOpts are options passed in by the user to set up SELinux labels.
// These are used by the containers/storage library.
LabelOpts []string `json:"labelopts,omitempty"`
// User and group to use in the container. Can be specified as only user
@@ -386,7 +386,7 @@ type ContainerMiscConfig struct {
IsService bool `json:"isService"`
// SdNotifyMode tells libpod what to do with a NOTIFY_SOCKET if passed
SdNotifyMode string `json:"sdnotifyMode,omitempty"`
- // Systemd tells libpod to setup the container in systemd mode, a value of nil denotes false
+ // Systemd tells libpod to set up the container in systemd mode, a value of nil denotes false
Systemd *bool `json:"systemd,omitempty"`
// HealthCheckConfig has the health check command and related timings
HealthCheckConfig *manifest.Schema2HealthConfig `json:"healthcheck"`
@@ -432,4 +432,10 @@ type InfraInherit struct {
SeccompProfilePath string `json:"seccomp_profile_path,omitempty"`
SelinuxOpts []string `json:"selinux_opts,omitempty"`
Volumes []*specgen.NamedVolume `json:"volumes,omitempty"`
+ ShmSize *int64 `json:"shm_size"`
+}
+
+// IsDefaultShmSize determines if the user actually set the shm in the parent ctr or if it has been set to the default size
+func (inherit *InfraInherit) IsDefaultShmSize() bool {
+ return inherit.ShmSize == nil || *inherit.ShmSize == 65536000
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 2f36995b3..245fb587d 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -367,7 +367,7 @@ func (c *Container) getUserOverrides() *lookup.Overrides {
func lookupHostUser(name string) (*runcuser.ExecUser, error) {
var execUser runcuser.ExecUser
- // Lookup User on host
+ // Look up User on host
u, err := util.LookupUser(name)
if err != nil {
return &execUser, err
@@ -2600,13 +2600,13 @@ func (c *Container) generateCurrentUserGroupEntry() (string, int, error) {
return "", 0, errors.Wrapf(err, "failed to get current group")
}
- // Lookup group name to see if it exists in the image.
+ // Look up group name to see if it exists in the image.
_, err = lookup.GetGroup(c.state.Mountpoint, g.Name)
if err != runcuser.ErrNoGroupEntries {
return "", 0, err
}
- // Lookup GID to see if it exists in the image.
+ // Look up GID to see if it exists in the image.
_, err = lookup.GetGroup(c.state.Mountpoint, g.Gid)
if err != runcuser.ErrNoGroupEntries {
return "", 0, err
@@ -2676,7 +2676,7 @@ func (c *Container) generatePasswdEntry() (string, error) {
addedUID := 0
for _, userid := range c.config.HostUsers {
- // Lookup User on host
+ // Look up User on host
u, err := util.LookupUser(userid)
if err != nil {
return "", err
@@ -2728,13 +2728,13 @@ func (c *Container) generateCurrentUserPasswdEntry() (string, int, int, error) {
}
func (c *Container) userPasswdEntry(u *user.User) (string, error) {
- // Lookup the user to see if it exists in the container image.
+ // Look up the user to see if it exists in the container image.
_, err := lookup.GetUser(c.state.Mountpoint, u.Username)
if err != runcuser.ErrNoPasswdEntries {
return "", err
}
- // Lookup the UID to see if it exists in the container image.
+ // Look up the UID to see if it exists in the container image.
_, err = lookup.GetUser(c.state.Mountpoint, u.Uid)
if err != runcuser.ErrNoPasswdEntries {
return "", err
@@ -2806,7 +2806,7 @@ func (c *Container) generateUserPasswdEntry(addedUID int) (string, error) {
return "", nil
}
- // Lookup the user to see if it exists in the container image
+ // Look up the user to see if it exists in the container image
_, err = lookup.GetUser(c.state.Mountpoint, userspec)
if err != runcuser.ErrNoPasswdEntries {
return "", err
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index ee80b00fe..cb1547a93 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -109,7 +109,7 @@ func (r *RootlessNetNS) getPath(path string) string {
func (r *RootlessNetNS) Do(toRun func() error) error {
err := r.ns.Do(func(_ ns.NetNS) error {
// Before we can run the given function,
- // we have to setup all mounts correctly.
+ // we have to set up all mounts correctly.
// The order of the mounts is IMPORTANT.
// The idea of the extra mount ns is to make /run and /var/lib/cni writeable
@@ -419,7 +419,7 @@ func (r *Runtime) GetRootlessNetNs(new bool) (*RootlessNetNS, error) {
if err != nil {
return nil, errors.Wrap(err, "error creating rootless network namespace")
}
- // setup slirp4netns here
+ // set up slirp4netns here
path := r.config.Engine.NetworkCmdPath
if path == "" {
var err error
@@ -656,9 +656,9 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) (status map[str
return nil, err
}
- // setup rootless port forwarder when rootless with ports and the network status is empty,
+ // set up rootless port forwarder when rootless with ports and the network status is empty,
// if this is called from network reload the network status will not be empty and we should
- // not setup port because they are still active
+ // not set up port because they are still active
if rootless.IsRootless() && len(ctr.config.PortMappings) > 0 && ctr.getNetworkStatus() == nil {
// set up port forwarder for rootless netns
netnsPath := ctrNS.Path()
diff --git a/pkg/api/handlers/compat/containers_stats.go b/pkg/api/handlers/compat/containers_stats.go
index 6855e369b..66743ce06 100644
--- a/pkg/api/handlers/compat/containers_stats.go
+++ b/pkg/api/handlers/compat/containers_stats.go
@@ -132,6 +132,12 @@ streamLabel: // A label to flatten the scope
InstanceID: "",
}
+ cfg := ctnr.Config()
+ memoryLimit := cgroupStat.Memory.Usage.Limit
+ if cfg.Spec.Linux != nil && cfg.Spec.Linux.Resources != nil && cfg.Spec.Linux.Resources.Memory != nil && *cfg.Spec.Linux.Resources.Memory.Limit > 0 {
+ memoryLimit = uint64(*cfg.Spec.Linux.Resources.Memory.Limit)
+ }
+
systemUsage, _ := cgroups.GetSystemCPUUsage()
s := StatsJSON{
Stats: Stats{
@@ -173,7 +179,7 @@ streamLabel: // A label to flatten the scope
MaxUsage: cgroupStat.Memory.Usage.Limit,
Stats: nil,
Failcnt: 0,
- Limit: cgroupStat.Memory.Usage.Limit,
+ Limit: memoryLimit,
Commit: 0,
CommitPeak: 0,
PrivateWorkingSet: 0,
diff --git a/pkg/api/handlers/libpod/containers.go b/pkg/api/handlers/libpod/containers.go
index 6b5bee403..deddcaf93 100644
--- a/pkg/api/handlers/libpod/containers.go
+++ b/pkg/api/handlers/libpod/containers.go
@@ -115,10 +115,6 @@ func ListContainers(w http.ResponseWriter, r *http.Request) {
utils.InternalServerError(w, err)
return
}
- if len(pss) == 0 {
- utils.WriteResponse(w, http.StatusOK, "[]")
- return
- }
utils.WriteResponse(w, http.StatusOK, pss)
}
diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go
index 21026477d..331d2bcdc 100644
--- a/pkg/domain/entities/system.go
+++ b/pkg/domain/entities/system.go
@@ -28,6 +28,7 @@ type SystemPruneReport struct {
PodPruneReport []*PodPruneReport
ContainerPruneReports []*reports.PruneReport
ImagePruneReports []*reports.PruneReport
+ NetworkPruneReports []*reports.PruneReport
VolumePruneReports []*reports.PruneReport
ReclaimedSpace uint64
}
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index 47f7917f4..8b95607f4 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -2,6 +2,7 @@ package abi
import (
"context"
+ "strconv"
"github.com/containers/common/libnetwork/types"
netutil "github.com/containers/common/libnetwork/util"
@@ -12,10 +13,39 @@ import (
)
func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.NetworkListOptions) ([]types.Network, error) {
+ // dangling filter is not provided by netutil
+ var wantDangling bool
+
+ val, filterDangling := options.Filters["dangling"]
+ if filterDangling {
+ switch len(val) {
+ case 0:
+ return nil, errors.Errorf("got no values for filter key \"dangling\"")
+ case 1:
+ var err error
+ wantDangling, err = strconv.ParseBool(val[0])
+ if err != nil {
+ return nil, errors.Errorf("invalid dangling filter value \"%v\"", val[0])
+ }
+ delete(options.Filters, "dangling")
+ default:
+ return nil, errors.Errorf("got more than one value for filter key \"dangling\"")
+ }
+ }
+
filters, err := netutil.GenerateNetworkFilters(options.Filters)
if err != nil {
return nil, err
}
+
+ if filterDangling {
+ danglingFilterFunc, err := ic.createDanglingFilterFunc(wantDangling)
+ if err != nil {
+ return nil, err
+ }
+
+ filters = append(filters, danglingFilterFunc)
+ }
nets, err := ic.Libpod.Network().NetworkList(filters...)
return nets, err
}
@@ -142,8 +172,35 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string
}, nil
}
-// Network prune removes unused cni networks
+// Network prune removes unused networks
func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.NetworkPruneOptions) ([]*entities.NetworkPruneReport, error) {
+ // get all filters
+ filters, err := netutil.GenerateNetworkPruneFilters(options.Filters)
+ if err != nil {
+ return nil, err
+ }
+ danglingFilterFunc, err := ic.createDanglingFilterFunc(true)
+ if err != nil {
+ return nil, err
+ }
+ filters = append(filters, danglingFilterFunc)
+ nets, err := ic.Libpod.Network().NetworkList(filters...)
+ if err != nil {
+ return nil, err
+ }
+
+ pruneReport := make([]*entities.NetworkPruneReport, 0, len(nets))
+ for _, net := range nets {
+ pruneReport = append(pruneReport, &entities.NetworkPruneReport{
+ Name: net.Name,
+ Error: ic.Libpod.Network().NetworkRemove(net.Name),
+ })
+ }
+ return pruneReport, nil
+}
+
+// danglingFilter function is special and not implemented in libnetwork filters
+func (ic *ContainerEngine) createDanglingFilterFunc(wantDangling bool) (types.FilterFunc, error) {
cons, err := ic.Libpod.GetAllContainers()
if err != nil {
return nil, err
@@ -163,31 +220,12 @@ func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.Ne
// ignore the default network, this one cannot be deleted
networksToKeep[ic.Libpod.GetDefaultNetworkName()] = true
- // get all filters
- filters, err := netutil.GenerateNetworkPruneFilters(options.Filters)
- if err != nil {
- return nil, err
- }
- danglingFilterFunc := func(net types.Network) bool {
+ return func(net types.Network) bool {
for network := range networksToKeep {
if network == net.Name {
- return false
+ return !wantDangling
}
}
- return true
- }
- filters = append(filters, danglingFilterFunc)
- nets, err := ic.Libpod.Network().NetworkList(filters...)
- if err != nil {
- return nil, err
- }
-
- pruneReport := make([]*entities.NetworkPruneReport, 0, len(nets))
- for _, net := range nets {
- pruneReport = append(pruneReport, &entities.NetworkPruneReport{
- Name: net.Name,
- Error: ic.Libpod.Network().NetworkRemove(net.Name),
- })
- }
- return pruneReport, nil
+ return wantDangling
+ }, nil
}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 762f0d79a..6be37c87f 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -125,8 +125,14 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, noMoveProcess bool)
paths = append(paths, ctr.Config().ConmonPidFile)
}
- became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths)
- utils.MovePauseProcessToScope(pausePidPath)
+ if len(paths) > 0 {
+ became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths)
+ } else {
+ became, ret, err = rootless.BecomeRootInUserNS(pausePidPath)
+ if err == nil {
+ utils.MovePauseProcessToScope(pausePidPath)
+ }
+ }
if err != nil {
logrus.Error(errors.Wrapf(err, "invalid internal status, try resetting the pause process with %q", os.Args[0]+" system migrate"))
os.Exit(1)
@@ -137,7 +143,7 @@ func (ic *ContainerEngine) SetupRootless(_ context.Context, noMoveProcess bool)
return nil
}
-// SystemPrune removes unused data from the system. Pruning pods, containers, volumes and images.
+// SystemPrune removes unused data from the system. Pruning pods, containers, networks, volumes and images.
func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.SystemPruneOptions) (*entities.SystemPruneReport, error) {
var systemPruneReport = new(entities.SystemPruneReport)
filters := []string{}
@@ -148,6 +154,9 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
found := true
for found {
found = false
+
+ // TODO: Figure out cleaner way to handle all of the different PruneOptions
+ // Remove all unused pods.
podPruneReport, err := ic.prunePodHelper(ctx)
if err != nil {
return nil, err
@@ -155,9 +164,10 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
if len(podPruneReport) > 0 {
found = true
}
+
systemPruneReport.PodPruneReport = append(systemPruneReport.PodPruneReport, podPruneReport...)
- // TODO: Figure out cleaner way to handle all of the different PruneOptions
+ // Remove all unused containers.
containerPruneOptions := entities.ContainerPruneOptions{}
containerPruneOptions.Filters = (url.Values)(options.Filters)
@@ -165,16 +175,18 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
if err != nil {
return nil, err
}
+
reclaimedSpace += reports.PruneReportsSize(containerPruneReports)
systemPruneReport.ContainerPruneReports = append(systemPruneReport.ContainerPruneReports, containerPruneReports...)
+
+ // Remove all unused images.
imagePruneOptions := entities.ImagePruneOptions{
All: options.All,
Filter: filters,
}
+
imageEngine := ImageEngine{Libpod: ic.Libpod}
imagePruneReports, err := imageEngine.Prune(ctx, imagePruneOptions)
- reclaimedSpace += reports.PruneReportsSize(imagePruneReports)
-
if err != nil {
return nil, err
}
@@ -182,10 +194,33 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
found = true
}
+ reclaimedSpace += reports.PruneReportsSize(imagePruneReports)
systemPruneReport.ImagePruneReports = append(systemPruneReport.ImagePruneReports, imagePruneReports...)
+
+ // Remove all unused networks.
+ networkPruneOptions := entities.NetworkPruneOptions{}
+ networkPruneOptions.Filters = options.Filters
+
+ networkPruneReport, err := ic.NetworkPrune(ctx, networkPruneOptions)
+ if err != nil {
+ return nil, err
+ }
+ if len(networkPruneReport) > 0 {
+ found = true
+ }
+ for _, net := range networkPruneReport {
+ systemPruneReport.NetworkPruneReports = append(systemPruneReport.NetworkPruneReports, &reports.PruneReport{
+ Id: net.Name,
+ Err: net.Error,
+ Size: 0,
+ })
+ }
+
+ // Remove unused volume data.
if options.Volume {
volumePruneOptions := entities.VolumePruneOptions{}
volumePruneOptions.Filters = (url.Values)(options.Filters)
+
volumePruneReport, err := ic.VolumePrune(ctx, volumePruneOptions)
if err != nil {
return nil, err
@@ -193,6 +228,7 @@ func (ic *ContainerEngine) SystemPrune(ctx context.Context, options entities.Sys
if len(volumePruneReport) > 0 {
found = true
}
+
reclaimedSpace += reports.PruneReportsSize(volumePruneReport)
systemPruneReport.VolumePruneReports = append(systemPruneReport.VolumePruneReports, volumePruneReport...)
}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 94bd40f86..3588313c6 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -178,7 +178,7 @@ get_cmd_line_args ()
char *tmp = realloc (buffer, allocated);
if (tmp == NULL)
return NULL;
- buffer = tmp;
+ buffer = tmp;
}
}
@@ -243,7 +243,7 @@ can_use_shortcut ()
}
if (argv[argc+1] != NULL && (strcmp (argv[argc], "container") == 0 ||
- strcmp (argv[argc], "image") == 0) &&
+ strcmp (argv[argc], "image") == 0) &&
(strcmp (argv[argc+1], "mount") == 0 || strcmp (argv[argc+1], "scp") == 0))
{
ret = false;
@@ -512,7 +512,9 @@ create_pause_process (const char *pause_pid_file_path, char **argv)
r = TEMP_FAILURE_RETRY (read (p[0], &b, 1));
close (p[0]);
- reexec_in_user_namespace_wait (pid, 0);
+ r = reexec_in_user_namespace_wait (pid, 0);
+ if (r != 0)
+ return -1;
return r == 1 && b == '0' ? 0 : -1;
}
@@ -757,6 +759,7 @@ reexec_userns_join (int pid_to_join, char *pause_pid_file_path)
}
execvp (argv[0], argv);
+ fprintf (stderr, "failed to execvp %s: %m\n", argv[0]);
_exit (EXIT_FAILURE);
}
@@ -788,7 +791,10 @@ copy_file_to_fd (const char *file_to_read, int outfd)
fd = open (file_to_read, O_RDONLY);
if (fd < 0)
- return fd;
+ {
+ fprintf (stderr, "open `%s`: %m\n", file_to_read);
+ return fd;
+ }
for (;;)
{
@@ -796,7 +802,10 @@ copy_file_to_fd (const char *file_to_read, int outfd)
r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof buf));
if (r < 0)
- return r;
+ {
+ fprintf (stderr, "read from `%s`: %m\n", file_to_read);
+ return r;
+ }
if (r == 0)
break;
@@ -805,7 +814,10 @@ copy_file_to_fd (const char *file_to_read, int outfd)
{
w = TEMP_FAILURE_RETRY (write (outfd, &buf[t], r - t));
if (w < 0)
- return w;
+ {
+ fprintf (stderr, "write file to output fd `%s`: %m\n", file_to_read);
+ return w;
+ }
t += w;
}
}
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 5af9a978b..d0bdf0ffe 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -182,7 +182,7 @@ func joinUserAndMountNS(pid uint, pausePid string) (bool, int, error) {
pidC := C.reexec_userns_join(C.int(pid), cPausePid)
if int(pidC) < 0 {
- return false, -1, errors.Errorf("cannot re-exec process")
+ return false, -1, errors.Errorf("cannot re-exec process to join the existing user namespace")
}
ret := C.reexec_in_user_namespace_wait(pidC, 0)
@@ -461,13 +461,8 @@ func BecomeRootInUserNS(pausePid string) (bool, int, error) {
// different uidmap and the unprivileged user has no way to read the
// file owned by the root in the container.
func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []string) (bool, int, error) {
- if len(paths) == 0 {
- return BecomeRootInUserNS(pausePidPath)
- }
-
var lastErr error
var pausePid int
- foundProcess := false
for _, path := range paths {
if !needNewNamespace {
@@ -479,12 +474,9 @@ func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []st
pausePid, err = strconv.Atoi(string(data))
if err != nil {
- lastErr = errors.Wrapf(err, "cannot parse file %s", path)
+ lastErr = errors.Wrapf(err, "cannot parse file %q", path)
continue
}
-
- lastErr = nil
- break
} else {
r, w, err := os.Pipe()
if err != nil {
@@ -511,26 +503,29 @@ func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []st
n, err := r.Read(b)
if err != nil {
- lastErr = errors.Wrapf(err, "cannot read %s\n", path)
+ lastErr = errors.Wrapf(err, "cannot read %q", path)
continue
}
pausePid, err = strconv.Atoi(string(b[:n]))
- if err == nil && unix.Kill(pausePid, 0) == nil {
- foundProcess = true
- lastErr = nil
- break
+ if err != nil {
+ lastErr = err
+ continue
}
}
- }
- if !foundProcess && pausePidPath != "" {
- return BecomeRootInUserNS(pausePidPath)
+
+ if pausePid > 0 && unix.Kill(pausePid, 0) == nil {
+ joined, pid, err := joinUserAndMountNS(uint(pausePid), pausePidPath)
+ if err == nil {
+ return joined, pid, nil
+ }
+ lastErr = err
+ }
}
if lastErr != nil {
return false, 0, lastErr
}
-
- return joinUserAndMountNS(uint(pausePid), pausePidPath)
+ return false, 0, errors.Wrapf(unix.ESRCH, "could not find any running process")
}
// ReadMappingsProc parses and returns the ID mappings at the specified path.
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go
index 0ed3c79ef..30c759495 100644
--- a/pkg/specgen/generate/container.go
+++ b/pkg/specgen/generate/container.go
@@ -506,6 +506,7 @@ func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID s
specg.Mounts = mounts
specg.HostDeviceList = conf.DeviceHostSrc
specg.Networks = conf.Networks
+ specg.ShmSize = &conf.ShmSize
mapSecurityConfig(conf, specg)
diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go
index 7faf13465..0dec943d1 100644
--- a/pkg/specgen/generate/container_create.go
+++ b/pkg/specgen/generate/container_create.go
@@ -564,5 +564,10 @@ func Inherit(infra libpod.Container, s *specgen.SpecGenerator, rt *libpod.Runtim
if err != nil {
return nil, nil, nil, err
}
+
+ // this causes errors when shmSize is the default value, it will still get passed down unless we manually override.
+ if s.IpcNS.NSMode == specgen.Host && (compatibleOptions.ShmSize != nil && compatibleOptions.IsDefaultShmSize()) {
+ s.ShmSize = nil
+ }
return options, infraSpec, compatibleOptions, nil
}
diff --git a/pkg/specgen/podspecgen.go b/pkg/specgen/podspecgen.go
index 777097ac5..02ba06be1 100644
--- a/pkg/specgen/podspecgen.go
+++ b/pkg/specgen/podspecgen.go
@@ -183,6 +183,10 @@ type PodStorageConfig struct {
// comma-separated options. Valid options are 'ro', 'rw', and 'z'.
// Options will be used for all volumes sourced from the container.
VolumesFrom []string `json:"volumes_from,omitempty"`
+ // ShmSize is the size of the tmpfs to mount in at /dev/shm, in bytes.
+ // Conflicts with ShmSize if IpcNS is not private.
+ // Optional.
+ ShmSize *int64 `json:"shm_size,omitempty"`
}
// PodCgroupConfig contains configuration options about a pod's cgroups.
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index 383c527b4..cfd6aab33 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -16,7 +16,12 @@ podman pull $ENV_WORKDIR_IMG &>/dev/null
# Ensure clean slate
podman rm -a -f &>/dev/null
-t GET "libpod/containers/json (at start: clean slate)" 200 length=0
+t GET "libpod/containers/json (at start: clean slate)" 200 \
+ "[]" \
+ length=0
+# check content type: https://github.com/containers/podman/issues/14647
+response_headers=$(cat "$WORKDIR/curl.headers.out")
+like "$response_headers" ".*Content-Type: application/json.*" "header does not contain application/json"
# Regression test for #12904 (race condition in logging code)
mytext="hi-there-$(random_string 15)"
@@ -95,6 +100,17 @@ fi
t DELETE libpod/containers/$cid 200 .[0].Id=$cid
+# Issue #14676: make sure the stats show the memory limit specified for the container
+if root; then
+ CTRNAME=ctr-with-limit
+ podman run --name $CTRNAME -d -m 512m -v /tmp:/tmp $IMAGE top
+
+ t GET libpod/containers/$CTRNAME/stats?stream=false 200 \
+ .memory_stats.limit=536870912
+
+ podman rm -f $CTRNAME
+fi
+
# Issue #6799: it should be possible to start a container, even w/o args.
t POST libpod/containers/create?name=test_noargs Image=${IMAGE} 201 \
.Id~[0-9a-f]\\{64\\}
diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at
index 4aad4563d..fcff26521 100644
--- a/test/apiv2/35-networks.at
+++ b/test/apiv2/35-networks.at
@@ -78,8 +78,8 @@ t GET networks?filters="{\"id\":[\"$network1_id\"]}" 200 \
.[0].Name=network1 \
.[0].Id=$network1_id
# invalid filter
-t GET networks?filters='{"dangling":["1"]}' 500 \
- .cause='invalid filter "dangling"'
+t GET networks?filters='{"dangling":["true","0"]}' 500 \
+ .cause="got more than one value for filter key \"dangling\""
# (#9293 with no networks the endpoint should return empty array instead of null)
t GET networks?filters='{"name":["doesnotexists"]}' 200 \
"[]"
diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
index 715455521..2fdd62f7e 100644
--- a/test/e2e/network_test.go
+++ b/test/e2e/network_test.go
@@ -163,6 +163,26 @@ var _ = Describe("Podman network", func() {
Expect(session.OutputToString()).To(Not(ContainSubstring(name)))
})
+ It("podman network list --filter dangling", func() {
+ name, path := generateNetworkConfig(podmanTest)
+ defer removeConf(path)
+
+ session := podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=true"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring(name))
+
+ session = podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=false"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).NotTo(ContainSubstring(name))
+
+ session = podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring(`invalid dangling filter value "foo"`))
+ })
+
It("podman network ID test", func() {
net := "networkIDTest"
// the network id should be the sha256 hash of the network name
diff --git a/test/e2e/pod_clone_test.go b/test/e2e/pod_clone_test.go
index b62e1205c..b90bf10da 100644
--- a/test/e2e/pod_clone_test.go
+++ b/test/e2e/pod_clone_test.go
@@ -138,4 +138,21 @@ var _ = Describe("Podman pod clone", func() {
Expect(data.Mounts[0]).To(HaveField("Name", volName))
})
+ It("podman pod clone --shm-size", func() {
+ podCreate := podmanTest.Podman([]string{"pod", "create"})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate).Should(Exit(0))
+
+ podClone := podmanTest.Podman([]string{"pod", "clone", "--shm-size", "10mb", podCreate.OutputToString()})
+ podClone.WaitWithDefaultTimeout()
+ Expect(podClone).Should(Exit(0))
+
+ run := podmanTest.Podman([]string{"run", "-it", "--pod", podClone.OutputToString(), ALPINE, "mount"})
+ run.WaitWithDefaultTimeout()
+ Expect(run).Should(Exit(0))
+ t, strings := run.GrepString("shm on /dev/shm type tmpfs")
+ Expect(t).To(BeTrue())
+ Expect(strings[0]).Should(ContainSubstring("size=10240k"))
+ })
+
})
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index 4919cc670..a48193e90 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -1134,4 +1134,27 @@ ENTRYPOINT ["sleep","99999"]
Expect(session.OutputToString()).Should(ContainSubstring("/vol2"))
})
+ It("podman pod create --shm-size", func() {
+ podCreate := podmanTest.Podman([]string{"pod", "create", "--shm-size", "10mb"})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate).Should(Exit(0))
+
+ run := podmanTest.Podman([]string{"run", "-it", "--pod", podCreate.OutputToString(), ALPINE, "mount"})
+ run.WaitWithDefaultTimeout()
+ Expect(run).Should(Exit(0))
+ t, strings := run.GrepString("shm on /dev/shm type tmpfs")
+ Expect(t).To(BeTrue())
+ Expect(strings[0]).Should(ContainSubstring("size=10240k"))
+ })
+
+ It("podman pod create --shm-size and --ipc=host conflict", func() {
+ podCreate := podmanTest.Podman([]string{"pod", "create", "--shm-size", "10mb"})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate).Should(Exit(0))
+
+ run := podmanTest.Podman([]string{"run", "-dt", "--pod", podCreate.OutputToString(), "--ipc", "host", ALPINE})
+ run.WaitWithDefaultTimeout()
+ Expect(run).ShouldNot(Exit(0))
+ })
+
})
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index 75adf1724..119c8d41e 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -258,6 +258,29 @@ var _ = Describe("Podman prune", func() {
Expect(pods.OutputToStringArray()).To(HaveLen(2))
})
+ It("podman system prune networks", func() {
+ // About netavark network backend test.
+ session := podmanTest.Podman([]string{"network", "create", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"system", "prune", "-f"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // Default network should exists.
+ session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^podman$"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToStringArray()).To(HaveLen(1))
+
+ // Remove all unused networks.
+ session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^test$"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToStringArray()).To(HaveLen(0))
+ })
+
It("podman system prune - pod,container stopped", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
diff --git a/vendor/github.com/spf13/cobra/CHANGELOG.md b/vendor/github.com/spf13/cobra/CHANGELOG.md
deleted file mode 100644
index 8a23b4f85..000000000
--- a/vendor/github.com/spf13/cobra/CHANGELOG.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# Cobra Changelog
-
-## v1.1.3
-
-* **Fix:** release-branch.cobra1.1 only: Revert "Deprecate Go < 1.14" to maintain backward compatibility
-
-## v1.1.2
-
-### Notable Changes
-
-* Bump license year to 2021 in golden files (#1309) @Bowbaq
-* Enhance PowerShell completion with custom comp (#1208) @Luap99
-* Update gopkg.in/yaml.v2 to v2.4.0: The previous breaking change in yaml.v2 v2.3.0 has been reverted, see go-yaml/yaml#670
-* Documentation readability improvements (#1228 etc.) @zaataylor etc.
-* Use golangci-lint: Repair warnings and errors resulting from linting (#1044) @umarcor
-
-## v1.1.1
-
-* **Fix:** yaml.v2 2.3.0 contained a unintended breaking change. This release reverts to yaml.v2 v2.2.8 which has recent critical CVE fixes, but does not have the breaking changes. See https://github.com/spf13/cobra/pull/1259 for context.
-* **Fix:** correct internal formatting for go-md2man v2 (which caused man page generation to be broken). See https://github.com/spf13/cobra/issues/1049 for context.
-
-## v1.1.0
-
-### Notable Changes
-
-* Extend Go completions and revamp zsh comp (#1070)
-* Fix man page doc generation - no auto generated tag when `cmd.DisableAutoGenTag = true` (#1104) @jpmcb
-* Add completion for help command (#1136)
-* Complete subcommands when TraverseChildren is set (#1171)
-* Fix stderr printing functions (#894)
-* fix: fish output redirection (#1247)
-
-## v1.0.0
-
-Announcing v1.0.0 of Cobra. 🎉
-
-### Notable Changes
-* Fish completion (including support for Go custom completion) @marckhouzam
-* API (urgent): Rename BashCompDirectives to ShellCompDirectives @marckhouzam
-* Remove/replace SetOutput on Command - deprecated @jpmcb
-* add support for autolabel stale PR @xchapter7x
-* Add Labeler Actions @xchapter7x
-* Custom completions coded in Go (instead of Bash) @marckhouzam
-* Partial Revert of #922 @jharshman
-* Add Makefile to project @jharshman
-* Correct documentation for InOrStdin @desponda
-* Apply formatting to templates @jharshman
-* Revert change so help is printed on stdout again @marckhouzam
-* Update md2man to v2.0.0 @pdf
-* update viper to v1.4.0 @umarcor
-* Update cmd/root.go example in README.md @jharshman
diff --git a/vendor/github.com/spf13/cobra/README.md b/vendor/github.com/spf13/cobra/README.md
index 7adef143b..2bf152082 100644
--- a/vendor/github.com/spf13/cobra/README.md
+++ b/vendor/github.com/spf13/cobra/README.md
@@ -2,7 +2,7 @@
Cobra is a library for creating powerful modern CLI applications.
-Cobra is used in many Go projects such as [Kubernetes](http://kubernetes.io/),
+Cobra is used in many Go projects such as [Kubernetes](https://kubernetes.io/),
[Hugo](https://gohugo.io), and [Github CLI](https://github.com/cli/cli) to
name a few. [This list](./projects_using_cobra.md) contains a more extensive list of projects using Cobra.
@@ -28,7 +28,7 @@ Cobra provides:
* Automatically generated man pages for your application
* Command aliases so you can change things without breaking them
* The flexibility to define your own help, usage, etc.
-* Optional seamless integration with [viper](http://github.com/spf13/viper) for 12-factor apps
+* Optional seamless integration with [viper](https://github.com/spf13/viper) for 12-factor apps
# Concepts
@@ -102,7 +102,7 @@ It can be installed by running:
go install github.com/spf13/cobra-cli@latest
```
-For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/master/README.md)
+For complete details on using the Cobra-CLI generator, please read [The Cobra Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md)
For complete details on using the Cobra library, please read the [The Cobra User Guide](user_guide.md).
diff --git a/vendor/github.com/spf13/cobra/active_help.go b/vendor/github.com/spf13/cobra/active_help.go
new file mode 100644
index 000000000..0c631913d
--- /dev/null
+++ b/vendor/github.com/spf13/cobra/active_help.go
@@ -0,0 +1,49 @@
+package cobra
+
+import (
+ "fmt"
+ "os"
+ "strings"
+)
+
+const (
+ activeHelpMarker = "_activeHelp_ "
+ // The below values should not be changed: programs will be using them explicitly
+ // in their user documentation, and users will be using them explicitly.
+ activeHelpEnvVarSuffix = "_ACTIVE_HELP"
+ activeHelpGlobalEnvVar = "COBRA_ACTIVE_HELP"
+ activeHelpGlobalDisable = "0"
+)
+
+// AppendActiveHelp adds the specified string to the specified array to be used as ActiveHelp.
+// Such strings will be processed by the completion script and will be shown as ActiveHelp
+// to the user.
+// The array parameter should be the array that will contain the completions.
+// This function can be called multiple times before and/or after completions are added to
+// the array. Each time this function is called with the same array, the new
+// ActiveHelp line will be shown below the previous ones when completion is triggered.
+func AppendActiveHelp(compArray []string, activeHelpStr string) []string {
+ return append(compArray, fmt.Sprintf("%s%s", activeHelpMarker, activeHelpStr))
+}
+
+// GetActiveHelpConfig returns the value of the ActiveHelp environment variable
+// <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of the root command in upper
+// case, with all - replaced by _.
+// It will always return "0" if the global environment variable COBRA_ACTIVE_HELP
+// is set to "0".
+func GetActiveHelpConfig(cmd *Command) string {
+ activeHelpCfg := os.Getenv(activeHelpGlobalEnvVar)
+ if activeHelpCfg != activeHelpGlobalDisable {
+ activeHelpCfg = os.Getenv(activeHelpEnvVar(cmd.Root().Name()))
+ }
+ return activeHelpCfg
+}
+
+// activeHelpEnvVar returns the name of the program-specific ActiveHelp environment
+// variable. It has the format <PROGRAM>_ACTIVE_HELP where <PROGRAM> is the name of the
+// root command in upper case, with all - replaced by _.
+func activeHelpEnvVar(name string) string {
+ // This format should not be changed: users will be using it explicitly.
+ activeHelpEnvVar := strings.ToUpper(fmt.Sprintf("%s%s", name, activeHelpEnvVarSuffix))
+ return strings.ReplaceAll(activeHelpEnvVar, "-", "_")
+}
diff --git a/vendor/github.com/spf13/cobra/active_help.md b/vendor/github.com/spf13/cobra/active_help.md
new file mode 100644
index 000000000..5e7f59af3
--- /dev/null
+++ b/vendor/github.com/spf13/cobra/active_help.md
@@ -0,0 +1,157 @@
+# Active Help
+
+Active Help is a framework provided by Cobra which allows a program to define messages (hints, warnings, etc) that will be printed during program usage. It aims to make it easier for your users to learn how to use your program. If configured by the program, Active Help is printed when the user triggers shell completion.
+
+For example,
+```
+bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding.
+
+bash-5.1$ bin/helm package [tab]
+Please specify the path to the chart to package
+
+bash-5.1$ bin/helm package [tab][tab]
+bin/ internal/ scripts/ pkg/ testdata/
+```
+
+**Hint**: A good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions to guide the user in knowing what is expected by the program.
+## Supported shells
+
+Active Help is currently only supported for the following shells:
+- Bash (using [bash completion V2](shell_completions.md#bash-completion-v2) only). Note that bash 4.4 or higher is required for the prompt to appear when an Active Help message is printed.
+- Zsh
+
+## Adding Active Help messages
+
+As Active Help uses the shell completion system, the implementation of Active Help messages is done by enhancing custom dynamic completions. If you are not familiar with dynamic completions, please refer to [Shell Completions](shell_completions.md).
+
+Adding Active Help is done through the use of the `cobra.AppendActiveHelp(...)` function, where the program repeatedly adds Active Help messages to the list of completions. Keep reading for details.
+
+### Active Help for nouns
+
+Adding Active Help when completing a noun is done within the `ValidArgsFunction(...)` of a command. Please notice the use of `cobra.AppendActiveHelp(...)` in the following example:
+
+```go
+cmd := &cobra.Command{
+ Use: "add [NAME] [URL]",
+ Short: "add a chart repository",
+ Args: require.ExactArgs(2),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return addRepo(args)
+ },
+ ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ var comps []string
+ if len(args) == 0 {
+ comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+ } else if len(args) == 1 {
+ comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+ } else {
+ comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+ }
+ return comps, cobra.ShellCompDirectiveNoFileComp
+ },
+}
+```
+The example above defines the completions (none, in this specific example) as well as the Active Help messages for the `helm repo add` command. It yields the following behavior:
+```
+bash-5.1$ helm repo add [tab]
+You must choose a name for the repo you are adding
+
+bash-5.1$ helm repo add grafana [tab]
+You must specify the URL for the repo you are adding
+
+bash-5.1$ helm repo add grafana https://grafana.github.io/helm-charts [tab]
+This command does not take any more arguments
+```
+**Hint**: As can be seen in the above example, a good place to use Active Help messages is when the normal completion system does not provide any suggestions. In such cases, Active Help nicely supplements the normal shell completions.
+
+### Active Help for flags
+
+Providing Active Help for flags is done in the same fashion as for nouns, but using the completion function registered for the flag. For example:
+```go
+_ = cmd.RegisterFlagCompletionFunc("version", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ if len(args) != 2 {
+ return cobra.AppendActiveHelp(nil, "You must first specify the chart to install before the --version flag can be completed"), cobra.ShellCompDirectiveNoFileComp
+ }
+ return compVersionFlag(args[1], toComplete)
+ })
+```
+The example above prints an Active Help message when not enough information was given by the user to complete the `--version` flag.
+```
+bash-5.1$ bin/helm install myrelease --version 2.0.[tab]
+You must first specify the chart to install before the --version flag can be completed
+
+bash-5.1$ bin/helm install myrelease bitnami/solr --version 2.0.[tab][tab]
+2.0.1 2.0.2 2.0.3
+```
+
+## User control of Active Help
+
+You may want to allow your users to disable Active Help or choose between different levels of Active Help. It is entirely up to the program to define the type of configurability of Active Help that it wants to offer, if any.
+Allowing to configure Active Help is entirely optional; you can use Active Help in your program without doing anything about Active Help configuration.
+
+The way to configure Active Help is to use the program's Active Help environment
+variable. That variable is named `<PROGRAM>_ACTIVE_HELP` where `<PROGRAM>` is the name of your
+program in uppercase with any `-` replaced by an `_`. The variable should be set by the user to whatever
+Active Help configuration values are supported by the program.
+
+For example, say `helm` has chosen to support three levels for Active Help: `on`, `off`, `local`. Then a user
+would set the desired behavior to `local` by doing `export HELM_ACTIVE_HELP=local` in their shell.
+
+For simplicity, when in `cmd.ValidArgsFunction(...)` or a flag's completion function, the program should read the
+Active Help configuration using the `cobra.GetActiveHelpConfig(cmd)` function and select what Active Help messages
+should or should not be added (instead of reading the environment variable directly).
+
+For example:
+```go
+ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
+ activeHelpLevel := cobra.GetActiveHelpConfig(cmd)
+
+ var comps []string
+ if len(args) == 0 {
+ if activeHelpLevel != "off" {
+ comps = cobra.AppendActiveHelp(comps, "You must choose a name for the repo you are adding")
+ }
+ } else if len(args) == 1 {
+ if activeHelpLevel != "off" {
+ comps = cobra.AppendActiveHelp(comps, "You must specify the URL for the repo you are adding")
+ }
+ } else {
+ if activeHelpLevel == "local" {
+ comps = cobra.AppendActiveHelp(comps, "This command does not take any more arguments")
+ }
+ }
+ return comps, cobra.ShellCompDirectiveNoFileComp
+},
+```
+**Note 1**: If the `<PROGRAM>_ACTIVE_HELP` environment variable is set to the string "0", Cobra will automatically disable all Active Help output (even if some output was specified by the program using the `cobra.AppendActiveHelp(...)` function). Using "0" can simplify your code in situations where you want to blindly disable Active Help without having to call `cobra.GetActiveHelpConfig(cmd)` explicitly.
+
+**Note 2**: If a user wants to disable Active Help for every single program based on Cobra, she can set the environment variable `COBRA_ACTIVE_HELP` to "0". In this case `cobra.GetActiveHelpConfig(cmd)` will return "0" no matter what the variable `<PROGRAM>_ACTIVE_HELP` is set to.
+
+**Note 3**: If the user does not set `<PROGRAM>_ACTIVE_HELP` or `COBRA_ACTIVE_HELP` (which will be a common case), the default value for the Active Help configuration returned by `cobra.GetActiveHelpConfig(cmd)` will be the empty string.
+## Active Help with Cobra's default completion command
+
+Cobra provides a default `completion` command for programs that wish to use it.
+When using the default `completion` command, Active Help is configurable in the same
+fashion as described above using environment variables. You may wish to document this in more
+details for your users.
+
+## Debugging Active Help
+
+Debugging your Active Help code is done in the same way as debugging your dynamic completion code, which is with Cobra's hidden `__complete` command. Please refer to [debugging shell completion](shell_completions.md#debugging) for details.
+
+When debugging with the `__complete` command, if you want to specify different Active Help configurations, you should use the active help environment variable. That variable is named `<PROGRAM>_ACTIVE_HELP` where any `-` is replaced by an `_`. For example, we can test deactivating some Active Help as shown below:
+```
+$ HELM_ACTIVE_HELP=1 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+_activeHelp_ WARNING: cannot re-use a name that is still in use
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+
+$ HELM_ACTIVE_HELP=0 bin/helm __complete install wordpress bitnami/h<ENTER>
+bitnami/haproxy
+bitnami/harbor
+:0
+Completion ended with directive: ShellCompDirectiveDefault
+```
diff --git a/vendor/github.com/spf13/cobra/bash_completions.go b/vendor/github.com/spf13/cobra/bash_completions.go
index 6c360c595..cb7e19537 100644
--- a/vendor/github.com/spf13/cobra/bash_completions.go
+++ b/vendor/github.com/spf13/cobra/bash_completions.go
@@ -73,7 +73,8 @@ __%[1]s_handle_go_custom_completion()
# Prepare the command to request completions for the program.
# Calling ${words[0]} instead of directly %[1]s allows to handle aliases
args=("${words[@]:1}")
- requestComp="${words[0]} %[2]s ${args[*]}"
+ # Disable ActiveHelp which is not supported for bash completion v1
+ requestComp="%[8]s=0 ${words[0]} %[2]s ${args[*]}"
lastParam=${words[$((${#words[@]}-1))]}
lastChar=${lastParam:$((${#lastParam}-1)):1}
@@ -99,7 +100,7 @@ __%[1]s_handle_go_custom_completion()
directive=0
fi
__%[1]s_debug "${FUNCNAME[0]}: the completion directive is: ${directive}"
- __%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out[*]}"
+ __%[1]s_debug "${FUNCNAME[0]}: the completions are: ${out}"
if [ $((directive & shellCompDirectiveError)) -ne 0 ]; then
# Error code. No completion.
@@ -125,7 +126,7 @@ __%[1]s_handle_go_custom_completion()
local fullFilter filter filteringCmd
# Do not use quotes around the $out variable or else newline
# characters will be kept.
- for filter in ${out[*]}; do
+ for filter in ${out}; do
fullFilter+="$filter|"
done
@@ -136,7 +137,7 @@ __%[1]s_handle_go_custom_completion()
# File completion for directories only
local subdir
# Use printf to strip any trailing newline
- subdir=$(printf "%%s" "${out[0]}")
+ subdir=$(printf "%%s" "${out}")
if [ -n "$subdir" ]; then
__%[1]s_debug "Listing directories in $subdir"
__%[1]s_handle_subdirs_in_dir_flag "$subdir"
@@ -147,7 +148,7 @@ __%[1]s_handle_go_custom_completion()
else
while IFS='' read -r comp; do
COMPREPLY+=("$comp")
- done < <(compgen -W "${out[*]}" -- "$cur")
+ done < <(compgen -W "${out}" -- "$cur")
fi
}
@@ -383,11 +384,11 @@ __%[1]s_handle_word()
`, name, ShellCompNoDescRequestCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
- ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
+ ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name)))
}
func writePostscript(buf io.StringWriter, name string) {
- name = strings.Replace(name, ":", "__", -1)
+ name = strings.ReplaceAll(name, ":", "__")
WriteStringAndCheck(buf, fmt.Sprintf("__start_%s()\n", name))
WriteStringAndCheck(buf, fmt.Sprintf(`{
local cur prev words cword split
@@ -645,8 +646,8 @@ func gen(buf io.StringWriter, cmd *Command) {
gen(buf, c)
}
commandName := cmd.CommandPath()
- commandName = strings.Replace(commandName, " ", "_", -1)
- commandName = strings.Replace(commandName, ":", "__", -1)
+ commandName = strings.ReplaceAll(commandName, " ", "_")
+ commandName = strings.ReplaceAll(commandName, ":", "__")
if cmd.Root() == cmd {
WriteStringAndCheck(buf, fmt.Sprintf("_%s_root_command()\n{\n", commandName))
diff --git a/vendor/github.com/spf13/cobra/bash_completionsV2.go b/vendor/github.com/spf13/cobra/bash_completionsV2.go
index 82d26c175..767bf0312 100644
--- a/vendor/github.com/spf13/cobra/bash_completionsV2.go
+++ b/vendor/github.com/spf13/cobra/bash_completionsV2.go
@@ -78,7 +78,7 @@ __%[1]s_get_completion_results() {
directive=0
fi
__%[1]s_debug "The completion directive is: ${directive}"
- __%[1]s_debug "The completions are: ${out[*]}"
+ __%[1]s_debug "The completions are: ${out}"
}
__%[1]s_process_completion_results() {
@@ -111,13 +111,18 @@ __%[1]s_process_completion_results() {
fi
fi
+ # Separate activeHelp from normal completions
+ local completions=()
+ local activeHelp=()
+ __%[1]s_extract_activeHelp
+
if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then
# File extension filtering
local fullFilter filter filteringCmd
- # Do not use quotes around the $out variable or else newline
+ # Do not use quotes around the $completions variable or else newline
# characters will be kept.
- for filter in ${out[*]}; do
+ for filter in ${completions[*]}; do
fullFilter+="$filter|"
done
@@ -129,7 +134,7 @@ __%[1]s_process_completion_results() {
# Use printf to strip any trailing newline
local subdir
- subdir=$(printf "%%s" "${out[0]}")
+ subdir=$(printf "%%s" "${completions[0]}")
if [ -n "$subdir" ]; then
__%[1]s_debug "Listing directories in $subdir"
pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return
@@ -143,6 +148,43 @@ __%[1]s_process_completion_results() {
__%[1]s_handle_special_char "$cur" :
__%[1]s_handle_special_char "$cur" =
+
+ # Print the activeHelp statements before we finish
+ if [ ${#activeHelp} -ne 0 ]; then
+ printf "\n";
+ printf "%%s\n" "${activeHelp[@]}"
+ printf "\n"
+
+ # The prompt format is only available from bash 4.4.
+ # We test if it is available before using it.
+ if (x=${PS1@P}) 2> /dev/null; then
+ printf "%%s" "${PS1@P}${COMP_LINE[@]}"
+ else
+ # Can't print the prompt. Just print the
+ # text the user had typed, it is workable enough.
+ printf "%%s" "${COMP_LINE[@]}"
+ fi
+ fi
+}
+
+# Separate activeHelp lines from real completions.
+# Fills the $activeHelp and $completions arrays.
+__%[1]s_extract_activeHelp() {
+ local activeHelpMarker="%[8]s"
+ local endIndex=${#activeHelpMarker}
+
+ while IFS='' read -r comp; do
+ if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then
+ comp=${comp:endIndex}
+ __%[1]s_debug "ActiveHelp found: $comp"
+ if [ -n "$comp" ]; then
+ activeHelp+=("$comp")
+ fi
+ else
+ # Not an activeHelp line but a normal completion
+ completions+=("$comp")
+ fi
+ done < <(printf "%%s\n" "${out}")
}
__%[1]s_handle_completion_types() {
@@ -154,17 +196,16 @@ __%[1]s_handle_completion_types() {
# If the user requested inserting one completion at a time, or all
# completions at once on the command-line we must remove the descriptions.
# https://github.com/spf13/cobra/issues/1508
- local tab comp
- tab=$(printf '\t')
+ local tab=$'\t' comp
while IFS='' read -r comp; do
+ [[ -z $comp ]] && continue
# Strip any description
comp=${comp%%%%$tab*}
# Only consider the completions that match
- comp=$(compgen -W "$comp" -- "$cur")
- if [ -n "$comp" ]; then
+ if [[ $comp == "$cur"* ]]; then
COMPREPLY+=("$comp")
fi
- done < <(printf "%%s\n" "${out[@]}")
+ done < <(printf "%%s\n" "${completions[@]}")
;;
*)
@@ -175,44 +216,37 @@ __%[1]s_handle_completion_types() {
}
__%[1]s_handle_standard_completion_case() {
- local tab comp
- tab=$(printf '\t')
+ local tab=$'\t' comp
+
+ # Short circuit to optimize if we don't have descriptions
+ if [[ "${completions[*]}" != *$tab* ]]; then
+ IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur")
+ return 0
+ fi
local longest=0
+ local compline
# Look for the longest completion so that we can format things nicely
- while IFS='' read -r comp; do
+ while IFS='' read -r compline; do
+ [[ -z $compline ]] && continue
# Strip any description before checking the length
- comp=${comp%%%%$tab*}
+ comp=${compline%%%%$tab*}
# Only consider the completions that match
- comp=$(compgen -W "$comp" -- "$cur")
+ [[ $comp == "$cur"* ]] || continue
+ COMPREPLY+=("$compline")
if ((${#comp}>longest)); then
longest=${#comp}
fi
- done < <(printf "%%s\n" "${out[@]}")
-
- local completions=()
- while IFS='' read -r comp; do
- if [ -z "$comp" ]; then
- continue
- fi
-
- __%[1]s_debug "Original comp: $comp"
- comp="$(__%[1]s_format_comp_descriptions "$comp" "$longest")"
- __%[1]s_debug "Final comp: $comp"
- completions+=("$comp")
- done < <(printf "%%s\n" "${out[@]}")
-
- while IFS='' read -r comp; do
- COMPREPLY+=("$comp")
- done < <(compgen -W "${completions[*]}" -- "$cur")
+ done < <(printf "%%s\n" "${completions[@]}")
# If there is a single completion left, remove the description text
if [ ${#COMPREPLY[*]} -eq 1 ]; then
__%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}"
- comp="${COMPREPLY[0]%%%% *}"
+ comp="${COMPREPLY[0]%%%%$tab*}"
__%[1]s_debug "Removed description from single completion, which is now: ${comp}"
- COMPREPLY=()
- COMPREPLY+=("$comp")
+ COMPREPLY[0]=$comp
+ else # Format the descriptions
+ __%[1]s_format_comp_descriptions $longest
fi
}
@@ -231,45 +265,48 @@ __%[1]s_handle_special_char()
__%[1]s_format_comp_descriptions()
{
- local tab
- tab=$(printf '\t')
- local comp="$1"
- local longest=$2
-
- # Properly format the description string which follows a tab character if there is one
- if [[ "$comp" == *$tab* ]]; then
- desc=${comp#*$tab}
- comp=${comp%%%%$tab*}
-
- # $COLUMNS stores the current shell width.
- # Remove an extra 4 because we add 2 spaces and 2 parentheses.
- maxdesclength=$(( COLUMNS - longest - 4 ))
-
- # Make sure we can fit a description of at least 8 characters
- # if we are to align the descriptions.
- if [[ $maxdesclength -gt 8 ]]; then
- # Add the proper number of spaces to align the descriptions
- for ((i = ${#comp} ; i < longest ; i++)); do
- comp+=" "
- done
- else
- # Don't pad the descriptions so we can fit more text after the completion
- maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
- fi
+ local tab=$'\t'
+ local comp desc maxdesclength
+ local longest=$1
+
+ local i ci
+ for ci in ${!COMPREPLY[*]}; do
+ comp=${COMPREPLY[ci]}
+ # Properly format the description string which follows a tab character if there is one
+ if [[ "$comp" == *$tab* ]]; then
+ __%[1]s_debug "Original comp: $comp"
+ desc=${comp#*$tab}
+ comp=${comp%%%%$tab*}
+
+ # $COLUMNS stores the current shell width.
+ # Remove an extra 4 because we add 2 spaces and 2 parentheses.
+ maxdesclength=$(( COLUMNS - longest - 4 ))
+
+ # Make sure we can fit a description of at least 8 characters
+ # if we are to align the descriptions.
+ if [[ $maxdesclength -gt 8 ]]; then
+ # Add the proper number of spaces to align the descriptions
+ for ((i = ${#comp} ; i < longest ; i++)); do
+ comp+=" "
+ done
+ else
+ # Don't pad the descriptions so we can fit more text after the completion
+ maxdesclength=$(( COLUMNS - ${#comp} - 4 ))
+ fi
- # If there is enough space for any description text,
- # truncate the descriptions that are too long for the shell width
- if [ $maxdesclength -gt 0 ]; then
- if [ ${#desc} -gt $maxdesclength ]; then
- desc=${desc:0:$(( maxdesclength - 1 ))}
- desc+="…"
+ # If there is enough space for any description text,
+ # truncate the descriptions that are too long for the shell width
+ if [ $maxdesclength -gt 0 ]; then
+ if [ ${#desc} -gt $maxdesclength ]; then
+ desc=${desc:0:$(( maxdesclength - 1 ))}
+ desc+="…"
+ fi
+ comp+=" ($desc)"
fi
- comp+=" ($desc)"
+ COMPREPLY[ci]=$comp
+ __%[1]s_debug "Final comp: $comp"
fi
- fi
-
- # Must use printf to escape all special characters
- printf "%%q" "${comp}"
+ done
}
__start_%[1]s()
@@ -310,7 +347,8 @@ fi
# ex: ts=4 sw=4 et filetype=sh
`, name, compCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
- ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
+ ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs,
+ activeHelpMarker))
}
// GenBashCompletionFileV2 generates Bash completion version 2.
diff --git a/vendor/github.com/spf13/cobra/command.go b/vendor/github.com/spf13/cobra/command.go
index 2cc18891d..675bb1340 100644
--- a/vendor/github.com/spf13/cobra/command.go
+++ b/vendor/github.com/spf13/cobra/command.go
@@ -18,6 +18,7 @@ package cobra
import (
"bytes"
"context"
+ "errors"
"fmt"
"io"
"os"
@@ -166,7 +167,7 @@ type Command struct {
// errWriter is a writer defined by the user that replaces stderr
errWriter io.Writer
- //FParseErrWhitelist flag parse errors to be ignored
+ // FParseErrWhitelist flag parse errors to be ignored
FParseErrWhitelist FParseErrWhitelist
// CompletionOptions is a set of options to control the handling of shell completion
@@ -224,12 +225,23 @@ type Command struct {
SuggestionsMinimumDistance int
}
-// Context returns underlying command context. If command wasn't
-// executed with ExecuteContext Context returns Background context.
+// Context returns underlying command context. If command was executed
+// with ExecuteContext or the context was set with SetContext, the
+// previously set context will be returned. Otherwise, nil is returned.
+//
+// Notice that a call to Execute and ExecuteC will replace a nil context of
+// a command with a context.Background, so a background context will be
+// returned by Context after one of these functions has been called.
func (c *Command) Context() context.Context {
return c.ctx
}
+// SetContext sets context for the command. It is set to context.Background by default and will be overwritten by
+// Command.ExecuteContext or Command.ExecuteContextC
+func (c *Command) SetContext(ctx context.Context) {
+ c.ctx = ctx
+}
+
// SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
// particularly useful when testing.
func (c *Command) SetArgs(a []string) {
@@ -852,6 +864,10 @@ func (c *Command) execute(a []string) (err error) {
if err := c.validateRequiredFlags(); err != nil {
return err
}
+ if err := c.validateFlagGroups(); err != nil {
+ return err
+ }
+
if c.RunE != nil {
if err := c.RunE(c, argWoFlags); err != nil {
return err
@@ -975,7 +991,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
if err != nil {
// Always show help if requested, even if SilenceErrors is in
// effect
- if err == flag.ErrHelp {
+ if errors.Is(err, flag.ErrHelp) {
cmd.HelpFunc()(cmd, args)
return cmd, nil
}
@@ -997,7 +1013,7 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
func (c *Command) ValidateArgs(args []string) error {
if c.Args == nil {
- return nil
+ return ArbitraryArgs(c, args)
}
return c.Args(c, args)
}
diff --git a/vendor/github.com/spf13/cobra/completions.go b/vendor/github.com/spf13/cobra/completions.go
index 9ecd56a47..2c2483998 100644
--- a/vendor/github.com/spf13/cobra/completions.go
+++ b/vendor/github.com/spf13/cobra/completions.go
@@ -103,6 +103,14 @@ func NoFileCompletions(cmd *Command, args []string, toComplete string) ([]string
return nil, ShellCompDirectiveNoFileComp
}
+// FixedCompletions can be used to create a completion function which always
+// returns the same results.
+func FixedCompletions(choices []string, directive ShellCompDirective) func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
+ return func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
+ return choices, directive
+ }
+}
+
// RegisterFlagCompletionFunc should be called to register a function to provide completion for a flag.
func (c *Command) RegisterFlagCompletionFunc(flagName string, f func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective)) error {
flag := c.Flag(flagName)
@@ -170,6 +178,12 @@ func (c *Command) initCompleteCmd(args []string) {
noDescriptions := (cmd.CalledAs() == ShellCompNoDescRequestCmd)
for _, comp := range completions {
+ if GetActiveHelpConfig(finalCmd) == activeHelpGlobalDisable {
+ // Remove all activeHelp entries in this case
+ if strings.HasPrefix(comp, activeHelpMarker) {
+ continue
+ }
+ }
if noDescriptions {
// Remove any description that may be included following a tab character.
comp = strings.Split(comp, "\t")[0]
@@ -311,8 +325,11 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
var completions []string
var directive ShellCompDirective
+ // Enforce flag groups before doing flag completions
+ finalCmd.enforceFlagGroupsForCompletion()
+
// Note that we want to perform flagname completion even if finalCmd.DisableFlagParsing==true;
- // doing this allows for completion of persistant flag names even for commands that disable flag parsing.
+ // doing this allows for completion of persistent flag names even for commands that disable flag parsing.
//
// When doing completion of a flag name, as soon as an argument starts with
// a '-' we know it is a flag. We cannot use isFlagArg() here as it requires
@@ -644,7 +661,7 @@ To load completions for every new session, execute once:
#### macOS:
- %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
+ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s
You will need to start a new shell for this setup to take effect.
`, c.Root().Name()),
@@ -669,6 +686,10 @@ to enable it. You can execute the following once:
echo "autoload -U compinit; compinit" >> ~/.zshrc
+To load completions in your current shell session:
+
+ source <(%[1]s completion zsh); compdef _%[1]s %[1]s
+
To load completions for every new session, execute once:
#### Linux:
@@ -677,7 +698,7 @@ To load completions for every new session, execute once:
#### macOS:
- %[1]s completion zsh > /usr/local/share/zsh/site-functions/_%[1]s
+ %[1]s completion zsh > $(brew --prefix)/share/zsh/site-functions/_%[1]s
You will need to start a new shell for this setup to take effect.
`, c.Root().Name()),
diff --git a/vendor/github.com/spf13/cobra/fish_completions.go b/vendor/github.com/spf13/cobra/fish_completions.go
index bb57fd568..005ee6be7 100644
--- a/vendor/github.com/spf13/cobra/fish_completions.go
+++ b/vendor/github.com/spf13/cobra/fish_completions.go
@@ -11,8 +11,8 @@ import (
func genFishComp(buf io.StringWriter, name string, includeDesc bool) {
// Variables should not contain a '-' or ':' character
nameForVar := name
- nameForVar = strings.Replace(nameForVar, "-", "_", -1)
- nameForVar = strings.Replace(nameForVar, ":", "_", -1)
+ nameForVar = strings.ReplaceAll(nameForVar, "-", "_")
+ nameForVar = strings.ReplaceAll(nameForVar, ":", "_")
compCmd := ShellCompRequestCmd
if !includeDesc {
@@ -38,7 +38,8 @@ function __%[1]s_perform_completion
__%[1]s_debug "args: $args"
__%[1]s_debug "last arg: $lastArg"
- set -l requestComp "$args[1] %[3]s $args[2..-1] $lastArg"
+ # Disable ActiveHelp which is not supported for fish shell
+ set -l requestComp "%[9]s=0 $args[1] %[3]s $args[2..-1] $lastArg"
__%[1]s_debug "Calling $requestComp"
set -l results (eval $requestComp 2> /dev/null)
@@ -196,7 +197,7 @@ complete -c %[2]s -n '__%[1]s_prepare_completions' -f -a '$__%[1]s_comp_results'
`, nameForVar, name, compCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
- ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
+ ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name)))
}
// GenFishCompletion generates fish completion file and writes to the passed writer.
diff --git a/vendor/github.com/spf13/cobra/flag_groups.go b/vendor/github.com/spf13/cobra/flag_groups.go
new file mode 100644
index 000000000..dc7843119
--- /dev/null
+++ b/vendor/github.com/spf13/cobra/flag_groups.go
@@ -0,0 +1,223 @@
+// Copyright © 2022 Steve Francia <spf@spf13.com>.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cobra
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ flag "github.com/spf13/pflag"
+)
+
+const (
+ requiredAsGroup = "cobra_annotation_required_if_others_set"
+ mutuallyExclusive = "cobra_annotation_mutually_exclusive"
+)
+
+// MarkFlagsRequiredTogether marks the given flags with annotations so that Cobra errors
+// if the command is invoked with a subset (but not all) of the given flags.
+func (c *Command) MarkFlagsRequiredTogether(flagNames ...string) {
+ c.mergePersistentFlags()
+ for _, v := range flagNames {
+ f := c.Flags().Lookup(v)
+ if f == nil {
+ panic(fmt.Sprintf("Failed to find flag %q and mark it as being required in a flag group", v))
+ }
+ if err := c.Flags().SetAnnotation(v, requiredAsGroup, append(f.Annotations[requiredAsGroup], strings.Join(flagNames, " "))); err != nil {
+ // Only errs if the flag isn't found.
+ panic(err)
+ }
+ }
+}
+
+// MarkFlagsMutuallyExclusive marks the given flags with annotations so that Cobra errors
+// if the command is invoked with more than one flag from the given set of flags.
+func (c *Command) MarkFlagsMutuallyExclusive(flagNames ...string) {
+ c.mergePersistentFlags()
+ for _, v := range flagNames {
+ f := c.Flags().Lookup(v)
+ if f == nil {
+ panic(fmt.Sprintf("Failed to find flag %q and mark it as being in a mutually exclusive flag group", v))
+ }
+ // Each time this is called is a single new entry; this allows it to be a member of multiple groups if needed.
+ if err := c.Flags().SetAnnotation(v, mutuallyExclusive, append(f.Annotations[mutuallyExclusive], strings.Join(flagNames, " "))); err != nil {
+ panic(err)
+ }
+ }
+}
+
+// validateFlagGroups validates the mutuallyExclusive/requiredAsGroup logic and returns the
+// first error encountered.
+func (c *Command) validateFlagGroups() error {
+ if c.DisableFlagParsing {
+ return nil
+ }
+
+ flags := c.Flags()
+
+ // groupStatus format is the list of flags as a unique ID,
+ // then a map of each flag name and whether it is set or not.
+ groupStatus := map[string]map[string]bool{}
+ mutuallyExclusiveGroupStatus := map[string]map[string]bool{}
+ flags.VisitAll(func(pflag *flag.Flag) {
+ processFlagForGroupAnnotation(flags, pflag, requiredAsGroup, groupStatus)
+ processFlagForGroupAnnotation(flags, pflag, mutuallyExclusive, mutuallyExclusiveGroupStatus)
+ })
+
+ if err := validateRequiredFlagGroups(groupStatus); err != nil {
+ return err
+ }
+ if err := validateExclusiveFlagGroups(mutuallyExclusiveGroupStatus); err != nil {
+ return err
+ }
+ return nil
+}
+
+func hasAllFlags(fs *flag.FlagSet, flagnames ...string) bool {
+ for _, fname := range flagnames {
+ f := fs.Lookup(fname)
+ if f == nil {
+ return false
+ }
+ }
+ return true
+}
+
+func processFlagForGroupAnnotation(flags *flag.FlagSet, pflag *flag.Flag, annotation string, groupStatus map[string]map[string]bool) {
+ groupInfo, found := pflag.Annotations[annotation]
+ if found {
+ for _, group := range groupInfo {
+ if groupStatus[group] == nil {
+ flagnames := strings.Split(group, " ")
+
+ // Only consider this flag group at all if all the flags are defined.
+ if !hasAllFlags(flags, flagnames...) {
+ continue
+ }
+
+ groupStatus[group] = map[string]bool{}
+ for _, name := range flagnames {
+ groupStatus[group][name] = false
+ }
+ }
+
+ groupStatus[group][pflag.Name] = pflag.Changed
+ }
+ }
+}
+
+func validateRequiredFlagGroups(data map[string]map[string]bool) error {
+ keys := sortedKeys(data)
+ for _, flagList := range keys {
+ flagnameAndStatus := data[flagList]
+
+ unset := []string{}
+ for flagname, isSet := range flagnameAndStatus {
+ if !isSet {
+ unset = append(unset, flagname)
+ }
+ }
+ if len(unset) == len(flagnameAndStatus) || len(unset) == 0 {
+ continue
+ }
+
+ // Sort values, so they can be tested/scripted against consistently.
+ sort.Strings(unset)
+ return fmt.Errorf("if any flags in the group [%v] are set they must all be set; missing %v", flagList, unset)
+ }
+
+ return nil
+}
+
+func validateExclusiveFlagGroups(data map[string]map[string]bool) error {
+ keys := sortedKeys(data)
+ for _, flagList := range keys {
+ flagnameAndStatus := data[flagList]
+ var set []string
+ for flagname, isSet := range flagnameAndStatus {
+ if isSet {
+ set = append(set, flagname)
+ }
+ }
+ if len(set) == 0 || len(set) == 1 {
+ continue
+ }
+
+ // Sort values, so they can be tested/scripted against consistently.
+ sort.Strings(set)
+ return fmt.Errorf("if any flags in the group [%v] are set none of the others can be; %v were all set", flagList, set)
+ }
+ return nil
+}
+
+func sortedKeys(m map[string]map[string]bool) []string {
+ keys := make([]string, len(m))
+ i := 0
+ for k := range m {
+ keys[i] = k
+ i++
+ }
+ sort.Strings(keys)
+ return keys
+}
+
+// enforceFlagGroupsForCompletion will do the following:
+// - when a flag in a group is present, other flags in the group will be marked required
+// - when a flag in a mutually exclusive group is present, other flags in the group will be marked as hidden
+// This allows the standard completion logic to behave appropriately for flag groups
+func (c *Command) enforceFlagGroupsForCompletion() {
+ if c.DisableFlagParsing {
+ return
+ }
+
+ flags := c.Flags()
+ groupStatus := map[string]map[string]bool{}
+ mutuallyExclusiveGroupStatus := map[string]map[string]bool{}
+ c.Flags().VisitAll(func(pflag *flag.Flag) {
+ processFlagForGroupAnnotation(flags, pflag, requiredAsGroup, groupStatus)
+ processFlagForGroupAnnotation(flags, pflag, mutuallyExclusive, mutuallyExclusiveGroupStatus)
+ })
+
+ // If a flag that is part of a group is present, we make all the other flags
+ // of that group required so that the shell completion suggests them automatically
+ for flagList, flagnameAndStatus := range groupStatus {
+ for _, isSet := range flagnameAndStatus {
+ if isSet {
+ // One of the flags of the group is set, mark the other ones as required
+ for _, fName := range strings.Split(flagList, " ") {
+ _ = c.MarkFlagRequired(fName)
+ }
+ }
+ }
+ }
+
+ // If a flag that is mutually exclusive to others is present, we hide the other
+ // flags of that group so the shell completion does not suggest them
+ for flagList, flagnameAndStatus := range mutuallyExclusiveGroupStatus {
+ for flagName, isSet := range flagnameAndStatus {
+ if isSet {
+ // One of the flags of the mutually exclusive group is set, mark the other ones as hidden
+ // Don't mark the flag that is already set as hidden because it may be an
+ // array or slice flag and therefore must continue being suggested
+ for _, fName := range strings.Split(flagList, " ") {
+ if fName != flagName {
+ flag := c.Flags().Lookup(fName)
+ flag.Hidden = true
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/spf13/cobra/go.mod b/vendor/github.com/spf13/cobra/go.mod
index 2d6855911..1d45d9f9a 100644
--- a/vendor/github.com/spf13/cobra/go.mod
+++ b/vendor/github.com/spf13/cobra/go.mod
@@ -3,7 +3,7 @@ module github.com/spf13/cobra
go 1.15
require (
- github.com/cpuguy83/go-md2man/v2 v2.0.1
+ github.com/cpuguy83/go-md2man/v2 v2.0.2
github.com/inconshreveable/mousetrap v1.0.0
github.com/spf13/pflag v1.0.5
gopkg.in/yaml.v2 v2.4.0
diff --git a/vendor/github.com/spf13/cobra/go.sum b/vendor/github.com/spf13/cobra/go.sum
index 431058ed0..8ed228800 100644
--- a/vendor/github.com/spf13/cobra/go.sum
+++ b/vendor/github.com/spf13/cobra/go.sum
@@ -1,18 +1,12 @@
-github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
-github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
+github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
+github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
-github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/vendor/github.com/spf13/cobra/powershell_completions.go b/vendor/github.com/spf13/cobra/powershell_completions.go
index 62d719f0b..379e7c088 100644
--- a/vendor/github.com/spf13/cobra/powershell_completions.go
+++ b/vendor/github.com/spf13/cobra/powershell_completions.go
@@ -61,6 +61,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
# Prepare the command to request completions for the program.
# Split the command at the first space to separate the program and arguments.
$Program,$Arguments = $Command.Split(" ",2)
+
$RequestComp="$Program %[2]s $Arguments"
__%[1]s_debug "RequestComp: $RequestComp"
@@ -90,11 +91,13 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
}
__%[1]s_debug "Calling $RequestComp"
+ # First disable ActiveHelp which is not supported for Powershell
+ $env:%[8]s=0
+
#call the command store the output in $out and redirect stderr and stdout to null
# $Out is an array contains each line per element
Invoke-Expression -OutVariable out "$RequestComp" 2>&1 | Out-Null
-
# get directive from last line
[int]$Directive = $Out[-1].TrimStart(':')
if ($Directive -eq "") {
@@ -242,7 +245,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
}
`, name, compCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
- ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
+ ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs, activeHelpEnvVar(name)))
}
func (c *Command) genPowerShellCompletion(w io.Writer, includeDesc bool) error {
diff --git a/vendor/github.com/spf13/cobra/projects_using_cobra.md b/vendor/github.com/spf13/cobra/projects_using_cobra.md
index 9674c348c..ac680118e 100644
--- a/vendor/github.com/spf13/cobra/projects_using_cobra.md
+++ b/vendor/github.com/spf13/cobra/projects_using_cobra.md
@@ -1,8 +1,8 @@
## Projects using Cobra
- [Arduino CLI](https://github.com/arduino/arduino-cli)
-- [Bleve](http://www.blevesearch.com/)
-- [CockroachDB](http://www.cockroachlabs.com/)
+- [Bleve](https://blevesearch.com/)
+- [CockroachDB](https://www.cockroachlabs.com/)
- [Cosmos SDK](https://github.com/cosmos/cosmos-sdk)
- [Datree](https://github.com/datreeio/datree)
- [Delve](https://github.com/derekparker/delve)
@@ -14,14 +14,15 @@
- [Github CLI](https://github.com/cli/cli)
- [GitHub Labeler](https://github.com/erdaltsksn/gh-label)
- [Golangci-lint](https://golangci-lint.run)
-- [GopherJS](http://www.gopherjs.org/)
+- [GopherJS](https://github.com/gopherjs/gopherjs)
- [GoReleaser](https://goreleaser.com)
- [Helm](https://helm.sh)
- [Hugo](https://gohugo.io)
- [Infracost](https://github.com/infracost/infracost)
- [Istio](https://istio.io)
- [Kool](https://github.com/kool-dev/kool)
-- [Kubernetes](http://kubernetes.io/)
+- [Kubernetes](https://kubernetes.io/)
+- [Kubescape](https://github.com/armosec/kubescape)
- [Linkerd](https://linkerd.io/)
- [Mattermost-server](https://github.com/mattermost/mattermost-server)
- [Mercure](https://mercure.rocks/)
@@ -36,9 +37,11 @@
- [Ory Hydra](https://github.com/ory/hydra)
- [Ory Kratos](https://github.com/ory/kratos)
- [Pixie](https://github.com/pixie-io/pixie)
+- [Polygon Edge](https://github.com/0xPolygon/polygon-edge)
- [Pouch](https://github.com/alibaba/pouch)
-- [ProjectAtomic (enterprise)](http://www.projectatomic.io/)
+- [ProjectAtomic (enterprise)](https://www.projectatomic.io/)
- [Prototool](https://github.com/uber/prototool)
+- [Pulumi](https://www.pulumi.com)
- [QRcp](https://github.com/claudiodangelis/qrcp)
- [Random](https://github.com/erdaltsksn/random)
- [Rclone](https://rclone.org/)
diff --git a/vendor/github.com/spf13/cobra/shell_completions.md b/vendor/github.com/spf13/cobra/shell_completions.md
index 33a4c65a5..1e2058ed6 100644
--- a/vendor/github.com/spf13/cobra/shell_completions.md
+++ b/vendor/github.com/spf13/cobra/shell_completions.md
@@ -40,7 +40,7 @@ Bash:
# Linux:
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
# macOS:
- $ %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
+ $ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s
Zsh:
@@ -122,7 +122,7 @@ For example, if you want `kubectl get [tab][tab]` to show a list of valid "nouns
Some simplified code from `kubectl get` looks like:
```go
-validArgs []string = { "pod", "node", "service", "replicationcontroller" }
+validArgs = []string{ "pod", "node", "service", "replicationcontroller" }
cmd := &cobra.Command{
Use: "get [(-o|--output=)json|yaml|template|...] (RESOURCE [NAME] | RESOURCE/NAME ...)",
@@ -148,7 +148,7 @@ node pod replicationcontroller service
If your nouns have aliases, you can define them alongside `ValidArgs` using `ArgAliases`:
```go
-argAliases []string = { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
+argAliases = []string { "pods", "nodes", "services", "svc", "replicationcontrollers", "rc" }
cmd := &cobra.Command{
...
diff --git a/vendor/github.com/spf13/cobra/user_guide.md b/vendor/github.com/spf13/cobra/user_guide.md
index 4a3c2b0da..5a7acf88e 100644
--- a/vendor/github.com/spf13/cobra/user_guide.md
+++ b/vendor/github.com/spf13/cobra/user_guide.md
@@ -32,7 +32,7 @@ func main() {
Cobra-CLI is its own program that will create your application and add any
commands you want. It's the easiest way to incorporate Cobra into your application.
-For complete details on using the Cobra generator, please refer to [The Cobra-CLI Generator README](https://github.com/spf13/cobra-cli/blob/master/README.md)
+For complete details on using the Cobra generator, please refer to [The Cobra-CLI Generator README](https://github.com/spf13/cobra-cli/blob/main/README.md)
## Using the Cobra Library
@@ -51,7 +51,7 @@ var rootCmd = &cobra.Command{
Short: "Hugo is a very fast static site generator",
Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.
- Complete documentation is available at http://hugo.spf13.com`,
+ Complete documentation is available at https://gohugo.io/documentation/`,
Run: func(cmd *cobra.Command, args []string) {
// Do Stuff Here
},
@@ -300,10 +300,34 @@ rootCmd.PersistentFlags().StringVarP(&Region, "region", "r", "", "AWS region (re
rootCmd.MarkPersistentFlagRequired("region")
```
+### Flag Groups
+
+If you have different flags that must be provided together (e.g. if they provide the `--username` flag they MUST provide the `--password` flag as well) then
+Cobra can enforce that requirement:
+```go
+rootCmd.Flags().StringVarP(&u, "username", "u", "", "Username (required if password is set)")
+rootCmd.Flags().StringVarP(&pw, "password", "p", "", "Password (required if username is set)")
+rootCmd.MarkFlagsRequiredTogether("username", "password")
+```
+
+You can also prevent different flags from being provided together if they represent mutually
+exclusive options such as specifying an output format as either `--json` or `--yaml` but never both:
+```go
+rootCmd.Flags().BoolVar(&u, "json", false, "Output in JSON")
+rootCmd.Flags().BoolVar(&pw, "yaml", false, "Output in YAML")
+rootCmd.MarkFlagsMutuallyExclusive("json", "yaml")
+```
+
+In both of these cases:
+ - both local and persistent flags can be used
+ - **NOTE:** the group is only enforced on commands where every flag is defined
+ - a flag may appear in multiple groups
+ - a group may contain any number of flags
+
## Positional and Custom Arguments
-Validation of positional arguments can be specified using the `Args` field
-of `Command`.
+Validation of positional arguments can be specified using the `Args` field of `Command`.
+If `Args` is undefined or `nil`, it defaults to `ArbitraryArgs`.
The following validators are built in:
@@ -405,7 +429,7 @@ a count and a string.`,
}
```
-For a more complete example of a larger application, please checkout [Hugo](http://gohugo.io/).
+For a more complete example of a larger application, please checkout [Hugo](https://gohugo.io/).
## Help Command
@@ -603,7 +627,7 @@ Did you mean this?
Run 'hugo --help' for usage.
```
-Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](http://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.
+Suggestions are automatic based on every subcommand registered and use an implementation of [Levenshtein distance](https://en.wikipedia.org/wiki/Levenshtein_distance). Every registered command that matches a minimum distance of 2 (ignoring case) will be displayed as a suggestion.
If you need to disable suggestions or tweak the string distance in your command, use:
@@ -636,3 +660,7 @@ Cobra can generate documentation based on subcommands, flags, etc. Read more abo
## Generating shell completions
Cobra can generate a shell-completion file for the following shells: bash, zsh, fish, PowerShell. If you add more information to your commands, these completions can be amazingly powerful and flexible. Read more about it in [Shell Completions](shell_completions.md).
+
+## Providing Active Help
+
+Cobra makes use of the shell-completion system to define a framework allowing you to provide Active Help to your users. Active Help are messages (hints, warnings, etc) printed as the program is being used. Read more about it in [Active Help](active_help.md).
diff --git a/vendor/github.com/spf13/cobra/zsh_completions.go b/vendor/github.com/spf13/cobra/zsh_completions.go
index 624adab53..65cd94c60 100644
--- a/vendor/github.com/spf13/cobra/zsh_completions.go
+++ b/vendor/github.com/spf13/cobra/zsh_completions.go
@@ -75,7 +75,7 @@ func genZshComp(buf io.StringWriter, name string, includeDesc bool) {
if !includeDesc {
compCmd = ShellCompNoDescRequestCmd
}
- WriteStringAndCheck(buf, fmt.Sprintf(`#compdef _%[1]s %[1]s
+ WriteStringAndCheck(buf, fmt.Sprintf(`#compdef %[1]s
# zsh completion for %-36[1]s -*- shell-script -*-
@@ -163,7 +163,24 @@ _%[1]s()
return
fi
+ local activeHelpMarker="%[8]s"
+ local endIndex=${#activeHelpMarker}
+ local startIndex=$((${#activeHelpMarker}+1))
+ local hasActiveHelp=0
while IFS='\n' read -r comp; do
+ # Check if this is an activeHelp statement (i.e., prefixed with $activeHelpMarker)
+ if [ "${comp[1,$endIndex]}" = "$activeHelpMarker" ];then
+ __%[1]s_debug "ActiveHelp found: $comp"
+ comp="${comp[$startIndex,-1]}"
+ if [ -n "$comp" ]; then
+ compadd -x "${comp}"
+ __%[1]s_debug "ActiveHelp will need delimiter"
+ hasActiveHelp=1
+ fi
+
+ continue
+ fi
+
if [ -n "$comp" ]; then
# If requested, completions are returned with a description.
# The description is preceded by a TAB character.
@@ -171,7 +188,7 @@ _%[1]s()
# We first need to escape any : as part of the completion itself.
comp=${comp//:/\\:}
- local tab=$(printf '\t')
+ local tab="$(printf '\t')"
comp=${comp//$tab/:}
__%[1]s_debug "Adding completion: ${comp}"
@@ -180,6 +197,17 @@ _%[1]s()
fi
done < <(printf "%%s\n" "${out[@]}")
+ # Add a delimiter after the activeHelp statements, but only if:
+ # - there are completions following the activeHelp statements, or
+ # - file completion will be performed (so there will be choices after the activeHelp)
+ if [ $hasActiveHelp -eq 1 ]; then
+ if [ ${#completions} -ne 0 ] || [ $((directive & shellCompDirectiveNoFileComp)) -eq 0 ]; then
+ __%[1]s_debug "Adding activeHelp delimiter"
+ compadd -x "--"
+ hasActiveHelp=0
+ fi
+ fi
+
if [ $((directive & shellCompDirectiveNoSpace)) -ne 0 ]; then
__%[1]s_debug "Activating nospace."
noSpace="-S ''"
@@ -254,5 +282,6 @@ if [ "$funcstack[1]" = "_%[1]s" ]; then
fi
`, name, compCmd,
ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,
- ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs))
+ ShellCompDirectiveFilterFileExt, ShellCompDirectiveFilterDirs,
+ activeHelpMarker))
}
diff --git a/vendor/github.com/stretchr/testify/assert/assertions.go b/vendor/github.com/stretchr/testify/assert/assertions.go
index 0357b2231..580fdea4c 100644
--- a/vendor/github.com/stretchr/testify/assert/assertions.go
+++ b/vendor/github.com/stretchr/testify/assert/assertions.go
@@ -563,16 +563,17 @@ func isEmpty(object interface{}) bool {
switch objValue.Kind() {
// collection types are empty when they have no element
- case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
+ case reflect.Chan, reflect.Map, reflect.Slice:
return objValue.Len() == 0
- // pointers are empty if nil or if the value they point to is empty
+ // pointers are empty if nil or if the value they point to is empty
case reflect.Ptr:
if objValue.IsNil() {
return true
}
deref := objValue.Elem().Interface()
return isEmpty(deref)
- // for all other types, compare against the zero value
+ // for all other types, compare against the zero value
+ // array types are empty when they match their zero-initialized state
default:
zero := reflect.Zero(objValue.Type())
return reflect.DeepEqual(object, zero.Interface())
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 6bd06d4af..9b0e22391 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -634,7 +634,7 @@ github.com/seccomp/libseccomp-golang
## explicit
github.com/sirupsen/logrus
github.com/sirupsen/logrus/hooks/syslog
-# github.com/spf13/cobra v1.4.0
+# github.com/spf13/cobra v1.5.0
## explicit
github.com/spf13/cobra
# github.com/spf13/pflag v1.0.5
@@ -642,7 +642,7 @@ github.com/spf13/cobra
github.com/spf13/pflag
# github.com/stefanberger/go-pkcs11uri v0.0.0-20201008174630-78d3cae3a980
github.com/stefanberger/go-pkcs11uri
-# github.com/stretchr/testify v1.7.2
+# github.com/stretchr/testify v1.7.4
## explicit
github.com/stretchr/testify/assert
github.com/stretchr/testify/require