mirror of
https://github.com/containers/podman.git
synced 2025-08-06 03:19:52 +08:00
man page crossrefs: add --filter autocompletes
For all commands with a --filter option, cross-reference against man pages, and vice-versa. I'm sorry. I know this script has gone off the deep end. [NO NEW TESTS NEEDED] although actually I would like to test some broken completions Signed-off-by: Ed Santiago <santiago@redhat.com>
This commit is contained in:
@ -1436,6 +1436,7 @@ func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete strin
|
|||||||
"pod=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeDefault) },
|
"pod=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeDefault) },
|
||||||
"volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
|
"volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
|
||||||
"event=": event,
|
"event=": event,
|
||||||
|
"label=": nil,
|
||||||
"type=": eventTypes,
|
"type=": eventTypes,
|
||||||
}
|
}
|
||||||
return completeKeyValues(toComplete, kv)
|
return completeKeyValues(toComplete, kv)
|
||||||
@ -1644,6 +1645,7 @@ func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete stri
|
|||||||
return []string{"stopped", "running",
|
return []string{"stopped", "running",
|
||||||
"paused", "exited", "dead", "created", "degraded"}, cobra.ShellCompDirectiveNoFileComp
|
"paused", "exited", "dead", "created", "degraded"}, cobra.ShellCompDirectiveNoFileComp
|
||||||
},
|
},
|
||||||
|
"until=": nil,
|
||||||
}
|
}
|
||||||
return completeKeyValues(toComplete, kv)
|
return completeKeyValues(toComplete, kv)
|
||||||
}
|
}
|
||||||
@ -1652,12 +1654,19 @@ func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete stri
|
|||||||
func AutocompleteImageFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
func AutocompleteImageFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
getImg := func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }
|
getImg := func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }
|
||||||
kv := keyValueCompletion{
|
kv := keyValueCompletion{
|
||||||
"before=": getImg,
|
"after=": getImg,
|
||||||
"dangling=": getBoolCompletion,
|
"before=": getImg,
|
||||||
"label=": nil,
|
"containers=": getBoolCompletion,
|
||||||
"readonly=": getBoolCompletion,
|
"dangling=": getBoolCompletion,
|
||||||
"reference=": nil,
|
"digest=": nil,
|
||||||
"since=": getImg,
|
"id=": getImg,
|
||||||
|
"intermediate=": getBoolCompletion,
|
||||||
|
"label=": nil,
|
||||||
|
"manifest=": getImg,
|
||||||
|
"readonly=": getBoolCompletion,
|
||||||
|
"reference=": nil,
|
||||||
|
"since=": getImg,
|
||||||
|
"until=": nil,
|
||||||
}
|
}
|
||||||
return completeKeyValues(toComplete, kv)
|
return completeKeyValues(toComplete, kv)
|
||||||
}
|
}
|
||||||
@ -1674,6 +1683,7 @@ func AutocompletePruneFilters(cmd *cobra.Command, args []string, toComplete stri
|
|||||||
// AutocompleteNetworkFilters - Autocomplete network ls --filter options.
|
// AutocompleteNetworkFilters - Autocomplete network ls --filter options.
|
||||||
func AutocompleteNetworkFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
func AutocompleteNetworkFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
|
||||||
kv := keyValueCompletion{
|
kv := keyValueCompletion{
|
||||||
|
"dangling=": getBoolCompletion,
|
||||||
"driver=": func(_ string) ([]string, cobra.ShellCompDirective) {
|
"driver=": func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||||
return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver, types.IPVLANNetworkDriver}, cobra.ShellCompDirectiveNoFileComp
|
return []string{types.BridgeNetworkDriver, types.MacVLANNetworkDriver, types.IPVLANNetworkDriver}, cobra.ShellCompDirectiveNoFileComp
|
||||||
},
|
},
|
||||||
@ -1690,13 +1700,17 @@ func AutocompleteVolumeFilters(cmd *cobra.Command, args []string, toComplete str
|
|||||||
local := func(_ string) ([]string, cobra.ShellCompDirective) {
|
local := func(_ string) ([]string, cobra.ShellCompDirective) {
|
||||||
return []string{"local"}, cobra.ShellCompDirectiveNoFileComp
|
return []string{"local"}, cobra.ShellCompDirectiveNoFileComp
|
||||||
}
|
}
|
||||||
|
getImg := func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }
|
||||||
kv := keyValueCompletion{
|
kv := keyValueCompletion{
|
||||||
|
"after=": getImg,
|
||||||
"dangling=": getBoolCompletion,
|
"dangling=": getBoolCompletion,
|
||||||
"driver=": local,
|
"driver=": local,
|
||||||
"label=": nil,
|
"label=": nil,
|
||||||
"name=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
|
"name=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) },
|
||||||
"opt=": nil,
|
"opt=": nil,
|
||||||
"scope=": local,
|
"scope=": local,
|
||||||
|
"since=": getImg,
|
||||||
|
"until=": nil,
|
||||||
}
|
}
|
||||||
return completeKeyValues(toComplete, kv)
|
return completeKeyValues(toComplete, kv)
|
||||||
}
|
}
|
||||||
|
@ -87,13 +87,16 @@ Setting `events_container_create_inspect_data=true` in containers.conf(5) instru
|
|||||||
|
|
||||||
Filter events that are displayed. They must be in the format of "filter=value". The following
|
Filter events that are displayed. They must be in the format of "filter=value". The following
|
||||||
filters are supported:
|
filters are supported:
|
||||||
* container=name_or_id
|
|
||||||
* event=event_status (described above)
|
| **Filter** | **Description** |
|
||||||
* image=name_or_id
|
|------------|-------------------------------------|
|
||||||
* label=key=value
|
| container | [Name or ID] Container's name or ID |
|
||||||
* pod=name_or_id
|
| event | event_status (described above) |
|
||||||
* volume=name_or_id
|
| image | [Name or ID] Image name or ID |
|
||||||
* type=event_type (described above)
|
| label | [key=value] label |
|
||||||
|
| pod | [Name or ID] Pod name or ID |
|
||||||
|
| volume | [Name or ID] Volume name or ID |
|
||||||
|
| type | Event_type (described above) |
|
||||||
|
|
||||||
In the case where an ID is used, the ID may be in its full or shortened form. The "die" event is mapped to "died" for Docker compatibility.
|
In the case where an ID is used, the ID may be in its full or shortened form. The "die" event is mapped to "died" for Docker compatibility.
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ Valid filters are listed below:
|
|||||||
| health | [Status] healthy or unhealthy |
|
| health | [Status] healthy or unhealthy |
|
||||||
| pod | [Pod] name or full or partial ID of pod |
|
| pod | [Pod] name or full or partial ID of pod |
|
||||||
| network | [Network] name or full ID of network |
|
| network | [Network] name or full ID of network |
|
||||||
|
| until | [DateTime] container created before the given duration or time. |
|
||||||
|
|
||||||
@@option latest
|
@@option latest
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ Valid filters are listed below:
|
|||||||
| health | [Status] healthy or unhealthy |
|
| health | [Status] healthy or unhealthy |
|
||||||
| pod | [Pod] name or full or partial ID of pod |
|
| pod | [Pod] name or full or partial ID of pod |
|
||||||
| network | [Network] name or full ID of network |
|
| network | [Network] name or full ID of network |
|
||||||
|
| until | [DateTime] container created before the given duration or time. |
|
||||||
|
|
||||||
|
|
||||||
#### **--format**=*format*
|
#### **--format**=*format*
|
||||||
|
@ -45,6 +45,7 @@ Valid filters are listed below:
|
|||||||
| health | [Status] healthy or unhealthy |
|
| health | [Status] healthy or unhealthy |
|
||||||
| pod | [Pod] name or full or partial ID of pod |
|
| pod | [Pod] name or full or partial ID of pod |
|
||||||
| network | [Network] name or full ID of network |
|
| network | [Network] name or full ID of network |
|
||||||
|
| until | [DateTime] Containers created before the given duration or time. |
|
||||||
|
|
||||||
@@option latest
|
@@option latest
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ Valid filters are listed below:
|
|||||||
| health | [Status] healthy or unhealthy |
|
| health | [Status] healthy or unhealthy |
|
||||||
| pod | [Pod] name or full or partial ID of pod |
|
| pod | [Pod] name or full or partial ID of pod |
|
||||||
| network | [Network] name or full ID of network |
|
| network | [Network] name or full ID of network |
|
||||||
|
| until | [DateTime] Containers created before the given duration or time. |
|
||||||
|
|
||||||
#### **--force**, **-f**
|
#### **--force**, **-f**
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ Valid filters are listed below:
|
|||||||
| health | [Status] healthy or unhealthy |
|
| health | [Status] healthy or unhealthy |
|
||||||
| pod | [Pod] name or full or partial ID of pod |
|
| pod | [Pod] name or full or partial ID of pod |
|
||||||
| network | [Network] name or full ID of network |
|
| network | [Network] name or full ID of network |
|
||||||
|
| until | [DateTime] Containers created before the given duration or time. |
|
||||||
|
|
||||||
@@option interactive
|
@@option interactive
|
||||||
|
|
||||||
|
@ -48,6 +48,7 @@ Valid filters are listed below:
|
|||||||
| health | [Status] healthy or unhealthy |
|
| health | [Status] healthy or unhealthy |
|
||||||
| pod | [Pod] name or full or partial ID of pod |
|
| pod | [Pod] name or full or partial ID of pod |
|
||||||
| network | [Network] name or full ID of network |
|
| network | [Network] name or full ID of network |
|
||||||
|
| until | [DateTime] Containers created before the given duration or time. |
|
||||||
|
|
||||||
@@option ignore
|
@@option ignore
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ Valid filters are listed below:
|
|||||||
| health | [Status] healthy or unhealthy |
|
| health | [Status] healthy or unhealthy |
|
||||||
| pod | [Pod] name or full or partial ID of pod |
|
| pod | [Pod] name or full or partial ID of pod |
|
||||||
| network | [Network] name or full ID of network |
|
| network | [Network] name or full ID of network |
|
||||||
|
| until | [DateTime] Containers created before the given duration or time. |
|
||||||
|
|
||||||
@@option latest
|
@@option latest
|
||||||
|
|
||||||
|
@ -23,11 +23,16 @@ The *filters* argument format is of `key=value`. If there is more than one *filt
|
|||||||
|
|
||||||
Supported filters:
|
Supported filters:
|
||||||
|
|
||||||
| Filter | Description |
|
| Filter | Description |
|
||||||
| :----------------: | --------------------------------------------------------------------------- |
|
|:-------------:|------------------------------------------------------------------------------------------------------------|
|
||||||
| *label* | Only remove volumes, with (or without, in the case of label!=[...] is used) the specified labels. |
|
| *dangling* | [Bool] Only remove volumes not referenced by any containers |
|
||||||
| *until* | Only remove volumes created before given timestamp. |
|
| *driver* | [String] Only remove volumes with the given driver |
|
||||||
| *after/since* | Filter by volumes created after the given VOLUME (name or tag) |
|
| *label* | [String] Only remove volumes, with (or without, in the case of label!=[...] is used) the specified labels. |
|
||||||
|
| *name* | [String] Only remove volume with the given name |
|
||||||
|
| *opt* | [String] Only remove volumes created with the given options |
|
||||||
|
| *scope* | [String] Only remove volumes with the given scope |
|
||||||
|
| *until* | [DateTime] Only remove volumes created before given timestamp. |
|
||||||
|
| *after/since* | [Volume] Filter by volumes created after the given VOLUME (name or tag) |
|
||||||
|
|
||||||
The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes volumes with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes volumes without the specified labels.
|
The `label` *filter* accepts two formats. One is the `label`=*key* or `label`=*key*=*value*, which removes volumes with the specified labels. The other format is the `label!`=*key* or `label!`=*key*=*value*, which removes volumes without the specified labels.
|
||||||
|
|
||||||
|
@ -203,6 +203,13 @@ sub xref_by_help {
|
|||||||
|
|
||||||
OPTION:
|
OPTION:
|
||||||
for my $k (sort keys %$help) {
|
for my $k (sort keys %$help) {
|
||||||
|
if (! ref($man)) {
|
||||||
|
# Super-unlikely but I've seen it
|
||||||
|
warn "$ME: 'podman @subcommand' is not documented in man pages!\n";
|
||||||
|
++$Errs;
|
||||||
|
next OPTION;
|
||||||
|
}
|
||||||
|
|
||||||
if (exists $man->{$k}) {
|
if (exists $man->{$k}) {
|
||||||
if (ref $help->{$k}) {
|
if (ref $help->{$k}) {
|
||||||
# This happens when 'podman foo --format' offers
|
# This happens when 'podman foo --format' offers
|
||||||
@ -233,7 +240,11 @@ sub xref_by_help {
|
|||||||
|
|
||||||
# Nope, it's not that case.
|
# Nope, it's not that case.
|
||||||
my $man = $man->{_path} || 'man';
|
my $man = $man->{_path} || 'man';
|
||||||
warn "$ME: 'podman @subcommand --help' lists '$k', which is not in $man\n";
|
# The usual case is "podman ... --help"...
|
||||||
|
my $what = '--help';
|
||||||
|
# ...but for *options* (e.g. --filter), we're checking command completion
|
||||||
|
$what = '<TAB>' if $subcommand[-1] =~ /^--/;
|
||||||
|
warn "$ME: 'podman @subcommand $what' lists '$k', which is not in $man\n";
|
||||||
++$Errs;
|
++$Errs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -296,7 +307,10 @@ sub xref_by_man {
|
|||||||
# Special case for hidden or external commands
|
# Special case for hidden or external commands
|
||||||
next if $Skip_Subcommand{$k};
|
next if $Skip_Subcommand{$k};
|
||||||
|
|
||||||
warn "$ME: 'podman @subcommand': $k in $man, but not --help\n";
|
# It's not always --help, sometimes we check <TAB> completion
|
||||||
|
my $what = '--help';
|
||||||
|
$what = 'command completion' if $subcommand[-1] =~ /^--/;
|
||||||
|
warn "$ME: 'podman @subcommand': '$k' in $man, but not in $what\n";
|
||||||
++$Errs;
|
++$Errs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,7 +434,17 @@ sub podman_help {
|
|||||||
++$Errs;
|
++$Errs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# Same thing, for --filter
|
||||||
|
elsif ($opt eq '--filter') {
|
||||||
|
my @completions = _completions(@_, '--filter=');
|
||||||
|
for my $c (@completions) {
|
||||||
|
if ($c =~ /^(\S+)=/) {
|
||||||
|
$help{$opt} = {} if ! ref($help{$opt});
|
||||||
|
$help{$opt}{$1} = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close $fh
|
close $fh
|
||||||
@ -447,9 +471,11 @@ sub podman_man {
|
|||||||
my $previous_subcmd = '';
|
my $previous_subcmd = '';
|
||||||
my $previous_flag = '';
|
my $previous_flag = '';
|
||||||
my $previous_format = '';
|
my $previous_format = '';
|
||||||
|
my $previous_filter = '';
|
||||||
|
LINE:
|
||||||
while (my $line = <$fh>) {
|
while (my $line = <$fh>) {
|
||||||
chomp $line;
|
chomp $line;
|
||||||
next unless $line; # skip empty lines
|
next LINE unless $line; # skip empty lines
|
||||||
|
|
||||||
# First line (page title) must match the command name.
|
# First line (page title) must match the command name.
|
||||||
if ($line =~ /^%\s+/) {
|
if ($line =~ /^%\s+/) {
|
||||||
@ -561,7 +587,7 @@ sub podman_man {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Options with no '=whatever'
|
# Options with no '=whatever'
|
||||||
next if !$line;
|
next LINE if !$line;
|
||||||
|
|
||||||
# Anything remaining *must* be of the form '=<possibilities>'
|
# Anything remaining *must* be of the form '=<possibilities>'
|
||||||
if ($line !~ /^=/) {
|
if ($line !~ /^=/) {
|
||||||
@ -639,6 +665,56 @@ sub podman_man {
|
|||||||
$previous_format = $format;
|
$previous_format = $format;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
# Same as above, but with --filter
|
||||||
|
elsif ($previous_flag eq '--filter') {
|
||||||
|
if ($line =~ /^\|\s+(\S+)\s+\|/) {
|
||||||
|
my $filter = $1;
|
||||||
|
|
||||||
|
# Special-case transformation: some man pages use
|
||||||
|
# asterisks, "*foo*", some don't. Ignore asterisks.
|
||||||
|
$filter =~ tr/\*//d;
|
||||||
|
|
||||||
|
# (Garbage: these are just table column titles & dividers)
|
||||||
|
next LINE if $filter eq 'Filter';
|
||||||
|
next LINE if $filter =~ /---+/;
|
||||||
|
|
||||||
|
# Another special case: treat slash-separated options
|
||||||
|
# ("after/since") as identical, and require that each
|
||||||
|
# be documented.
|
||||||
|
for my $f (split '/', $filter) {
|
||||||
|
# Special case for negated options ("label!="): allow,
|
||||||
|
# but only immediately after the positive case.
|
||||||
|
if ($f =~ s/!$//) {
|
||||||
|
if ($f ne $previous_filter) {
|
||||||
|
warn "$ME: $subpath:$.: filter '$f!' only allowed immediately after its positive\n";
|
||||||
|
++$Errs;
|
||||||
|
}
|
||||||
|
next LINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! ref($man{$previous_flag})) {
|
||||||
|
$man{$previous_flag} = { _path => $subpath };
|
||||||
|
}
|
||||||
|
$man{$previous_flag}{$f} = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sort order check, case-insensitive
|
||||||
|
# FIXME FIXME! Disabled for now because it would make
|
||||||
|
# this PR completely impossible to review (as opposed to
|
||||||
|
# only mostly-impossible)
|
||||||
|
#if (lc($filter) lt lc($previous_filter)) {
|
||||||
|
# warn "$ME: $subpath:$.: filter specifier '$filter' should precede '$previous_filter'\n";
|
||||||
|
# ++$Errs;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Dup check. Yes, it happens.
|
||||||
|
if (lc($filter) eq lc($previous_filter)) {
|
||||||
|
warn "$ME: $subpath:$.: filter specifier '$filter' is a dup\n";
|
||||||
|
++$Errs;
|
||||||
|
}
|
||||||
|
$previous_filter = $filter;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# It's easy to make mistakes in the SEE ALSO elements.
|
# It's easy to make mistakes in the SEE ALSO elements.
|
||||||
|
Reference in New Issue
Block a user