diff --git a/docs/source/markdown/podman-auto-update.1.md.in b/docs/source/markdown/podman-auto-update.1.md.in index 6471e4efc2..99edd39cb2 100644 --- a/docs/source/markdown/podman-auto-update.1.md.in +++ b/docs/source/markdown/podman-auto-update.1.md.in @@ -61,12 +61,12 @@ Valid placeholders for the Go template are listed below: | **Placeholder** | **Description** | | --------------- | -------------------------------------- | -| .Unit | Name of the systemd unit | -| .ContainerName | Name of the container | -| .ContainerID | ID of the container | | .Container | ID and name of the container | +| .ContainerID | ID of the container | +| .ContainerName | Name of the container | | .Image | Name of the image | | .Policy | Auto-update policy of the container | +| .Unit | Name of the systemd unit | | .Updated | Update status: true,false,failed | #### **--rollback** diff --git a/docs/source/markdown/podman-container-inspect.1.md.in b/docs/source/markdown/podman-container-inspect.1.md.in index 81c462894f..b016df8758 100644 --- a/docs/source/markdown/podman-container-inspect.1.md.in +++ b/docs/source/markdown/podman-container-inspect.1.md.in @@ -38,6 +38,7 @@ Valid placeholders for the Go template are listed below: | .HostsPath | Path to container /etc/hosts file (string) | | .ID | Container ID (full 64-char hash) | | .Image | Container image ID (64-char hash) | +| .ImageDigest | Container image digest (sha256:+64-char hash) | | .ImageName | Container image name (string) | | .IsInfra | Is this an infra container? (string: true/false) | | .IsService | Is this a service container? (string: true/false) | diff --git a/docs/source/markdown/podman-events.1.md b/docs/source/markdown/podman-events.1.md index 9467929254..02d10dcd8d 100644 --- a/docs/source/markdown/podman-events.1.md +++ b/docs/source/markdown/podman-events.1.md @@ -101,19 +101,20 @@ In the case where an ID is used, the ID may be in its full or shortened form. T Format the output to JSON Lines or using the given Go template. -| **Placeholder** | **Description** | -|--------------------|-----------------------------------------------| -| .Attributes | created_at, _by, labels, and more (map[]) | -| .ContainerExitCode | Exit code (int) | -| .Details ... | Internal structure, not actually useful | -| .HealthStatus | Health Status (string) | -| .ID | Container ID (full 64-bit SHA) | -| .Image | Name of image being run (string) | -| .Name | Container name (string) | -| .Network | Name of network being used (string) | -| .Status | Event status (e.g., create, start, died, ...) | -| .Time | Event timestamp (string) | -| .Type | Event type (e.g., image, container, pod, ...) | +| **Placeholder** | **Description** | +|-----------------------|-----------------------------------------------| +| .Attributes | created_at, _by, labels, and more (map[]) | +| .ContainerExitCode | Exit code (int) | +| .ContainerInspectData | Payload of the container's inspect | +| .HealthStatus | Health Status (string) | +| .ID | Container ID (full 64-bit SHA) | +| .Image | Name of image being run (string) | +| .Name | Container name (string) | +| .Network | Name of network being used (string) | +| .PodID | ID of pod associated with container, if any | +| .Status | Event status (e.g., create, start, died, ...) | +| .Time | Event timestamp (string) | +| .Type | Event type (e.g., image, container, pod, ...) | #### **--help** diff --git a/docs/source/markdown/podman-history.1.md b/docs/source/markdown/podman-history.1.md index fb186127a1..62503a1f71 100644 --- a/docs/source/markdown/podman-history.1.md +++ b/docs/source/markdown/podman-history.1.md @@ -25,16 +25,16 @@ Alter the output for a format like 'json' or a Go template. Valid placeholders for the Go template are listed below: -| **Placeholder** | **Description** | -| --------------- | ----------------------------------------------------------------------------- | -| .ID | Image ID | -| .Created | if --human, time elapsed since creation, otherwise time stamp of creation | -| .CreatedAt | Time when the image layer was created | -| .CreatedBy | Command used to create the layer | -| .CreatedSince | Elapsed time since the image layer was created | -| .Size | Size of layer on disk | -| .Comment | Comment for the layer | -| .Tags | Image tags | +| **Placeholder** | **Description** | +|------------------------|---------------------------------------------------------------------------| +| .ID | Image ID | +| .Created | if --human, time elapsed since creation, otherwise time stamp of creation | +| .CreatedAt | Time when the image layer was created | +| .CreatedBy | Command used to create the layer | +| .CreatedSince | Elapsed time since the image layer was created | +| .Size | Size of layer on disk | +| .Comment | Comment for the layer | +| .Tags | Image tags | #### **--help**, **-h** diff --git a/docs/source/markdown/podman-images.1.md.in b/docs/source/markdown/podman-images.1.md.in index 48fbb10e6d..f41c6b6611 100644 --- a/docs/source/markdown/podman-images.1.md.in +++ b/docs/source/markdown/podman-images.1.md.in @@ -88,7 +88,6 @@ Valid placeholders for the Go template are listed below: | .History | History of the image layer | | .ID | Image ID (truncated) | | .Id | Image ID (full SHA) | -| .ImageSummary | Internal data structure, not actually useful | | .IsDangling | Is image dangling? (true/false) | | .IsReadOnly | Is unage read-only? (true/false) | | .Labels | map[] of labels | diff --git a/docs/source/markdown/podman-network-inspect.1.md b/docs/source/markdown/podman-network-inspect.1.md index f812542dba..c54a4e832c 100644 --- a/docs/source/markdown/podman-network-inspect.1.md +++ b/docs/source/markdown/podman-network-inspect.1.md @@ -14,20 +14,21 @@ Display the (JSON format) network configuration. Pretty-print networks to JSON or using a Go template. -| **Placeholder** | **Description** | -| ----------------- | ----------------------------------------- | -| .ID | Network ID | -| .Name | Network name | -| .Driver | Network driver | -| .Labels | Network labels | -| .Options | Network options | -| .IPAMOptions | Network ipam options | -| .Created | Timestamp when the network was created | -| .Internal | Network is internal (boolean) | -| .IPv6Enabled | Network has ipv6 subnet (boolean) | -| .DNSEnabled | Network has dns enabled (boolean) | -| .NetworkInterface | Name of the network interface on the host | -| .Subnets | List of subnets on this network | +| **Placeholder** | **Description** | +|--------------------|-------------------------------------------| +| .ID | Network ID | +| .Name | Network name | +| .Driver | Network driver | +| .Labels | Network labels | +| .Options | Network options | +| .IPAMOptions | Network ipam options | +| .Created | Timestamp when the network was created | +| .Internal | Network is internal (boolean) | +| .IPv6Enabled | Network has ipv6 subnet (boolean) | +| .DNSEnabled | Network has dns enabled (boolean) | +| .NetworkDNSServers | Array of DNS servers used in this network | +| .NetworkInterface | Name of the network interface on the host | +| .Subnets | List of subnets on this network | ## EXAMPLE diff --git a/docs/source/markdown/podman-network-ls.1.md.in b/docs/source/markdown/podman-network-ls.1.md.in index 03f16fc8b3..dc327de52a 100644 --- a/docs/source/markdown/podman-network-ls.1.md.in +++ b/docs/source/markdown/podman-network-ls.1.md.in @@ -42,20 +42,21 @@ Change the default output format. This can be of a supported type like 'json' or a Go template. Valid placeholders for the Go template are listed below: -| **Placeholder** | **Description** | -| ----------------- | ----------------------------------------- | -| .ID | Network ID | -| .Name | Network name | -| .Driver | Network driver | -| .Labels | Network labels | -| .Options | Network options | -| .IPAMOptions | Network ipam options | -| .Created | Timestamp when the network was created | -| .Internal | Network is internal (boolean) | -| .IPv6Enabled | Network has ipv6 subnet (boolean) | -| .DNSEnabled | Network has dns enabled (boolean) | -| .NetworkInterface | Name of the network interface on the host | -| .Subnets | List of subnets on this network | +| **Placeholder** | **Description** | +|--------------------|-------------------------------------------| +| .ID | Network ID | +| .Name | Network name | +| .Driver | Network driver | +| .Labels | Network labels | +| .Options | Network options | +| .IPAMOptions | Network ipam options | +| .Created | Timestamp when the network was created | +| .Internal | Network is internal (boolean) | +| .IPv6Enabled | Network has ipv6 subnet (boolean) | +| .DNSEnabled | Network has dns enabled (boolean) | +| .NetworkDNSServers | Array of DNS servers used in this network | +| .NetworkInterface | Name of the network interface on the host | +| .Subnets | List of subnets on this network | #### **--no-trunc** diff --git a/docs/source/markdown/podman-pod-ps.1.md.in b/docs/source/markdown/podman-pod-ps.1.md.in index 3d46749792..27ad5788c9 100644 --- a/docs/source/markdown/podman-pod-ps.1.md.in +++ b/docs/source/markdown/podman-pod-ps.1.md.in @@ -77,17 +77,20 @@ Pretty-print containers to JSON or using a Go template Valid placeholders for the Go template are listed below: -| **Placeholder** | **Description** | -| ------------------- | ----------------------------------------------------------------------------------------------- | -| .ID | Container ID | -| .Name | Name of pod | -| .Status | Status of pod | -| .Labels | All the labels assigned to the pod | -| .NumberOfContainers | Show the number of containers attached to pod | -| .Cgroup | Cgroup path of pod | -| .Created | Creation time of pod | -| .InfraID | Pod infra container ID | -| .Networks | Show all networks connected to the infra container | +| **Placeholder** | **Description** | +|---------------------|----------------------------------------------------| +| .Cgroup | Cgroup path of pod | +| .ContainerIds | Comma-separated list of container IDs in the pod | +| .ContainerNames | Comma-separated list of container names in the pod | +| .ContainerStatuses | Comma-separated list of container statuses | +| .Created | Creation time of pod | +| .ID | Container ID | +| .InfraID | Pod infra container ID | +| .Labels | All the labels assigned to the pod | +| .Name | Name of pod | +| .Networks | Show all networks connected to the infra container | +| .NumberOfContainers | Show the number of containers attached to pod | +| .Status | Status of pod | #### **--help**, **-h** diff --git a/docs/source/markdown/podman-ps.1.md b/docs/source/markdown/podman-ps.1.md index 450737c3dd..43a5eb82cb 100644 --- a/docs/source/markdown/podman-ps.1.md +++ b/docs/source/markdown/podman-ps.1.md @@ -67,22 +67,33 @@ Pretty-print containers to JSON or using a Go template Valid placeholders for the Go template are listed below: -| **Placeholder** | **Description** | -| --------------- | ------------------------------------------------ | -| .ID | Container ID | -| .Image | Image Name/ID | -| .ImageID | Image ID | -| .Command | Quoted command used | -| .CreatedAt | Creation time for container | -| .RunningFor | Time elapsed since container was started | -| .Status | Status of container | -| .Pod | Pod the container is associated with | -| .Ports | Exposed ports | -| .Size | Size of container | -| .Names | Name of container | -| .Networks | Show all networks connected to the container | -| .Labels | All the labels assigned to the container | -| .Mounts | Volumes mounted in the container | +| **Placeholder** | **Description** | +|--------------------|----------------------------------------------| +| .AutoRemove | If true, container will be removed on exit | +| .Command | Quoted command used | +| .Created | Creation time for container, Y-M-D H:M:S | +| .CreatedAt | Creation time for container (same as above) | +| .CreatedHuman | Creation time, relative | +| .ExitCode | Container exit code | +| .Exited | "true" if container has exited | +| .ExitedAt | Time (epoch seconds) that container exited | +| .ID | Container ID | +| .Image | Image Name/ID | +| .ImageID | Image ID | +| .IsInfra | "true" if infra container | +| .Labels | All the labels assigned to the container | +| .Mounts | Volumes mounted in the container | +| .Names | Name of container | +| .Networks | Show all networks connected to the container | +| .Pid | Process ID on host system | +| .Pod | Pod the container is associated with (SHA) | +| .PodName | Seems to be empty no matter what | +| .Ports | Exposed ports | +| .RunningFor | Time elapsed since container was started | +| .Size | Size of container | +| .StartedAt | Time (epoch seconds) the container started | +| .State | Human-friendly description of ctr state | +| .Status | Status of container | #### **--help**, **-h** diff --git a/docs/source/markdown/podman-secret-inspect.1.md b/docs/source/markdown/podman-secret-inspect.1.md index b5bcd2b921..ccf55f6c57 100644 --- a/docs/source/markdown/podman-secret-inspect.1.md +++ b/docs/source/markdown/podman-secret-inspect.1.md @@ -20,13 +20,14 @@ Secrets can be queried individually by providing their full name or a unique par Format secret output using Go template. | **Placeholder** | **Description** | -| ------------------------ | ----------------------------------------------------------------- | +|--------------------------|-------------------------------------------------------------------| | .CreatedAt | When secret was created (relative timestamp, human-readable) | | .ID | ID of secret | | .Spec | Details of secret | | .Spec.Driver | Driver info | | .Spec.Driver.Name | Driver name (string) | | .Spec.Driver.Options ... | Driver options (map of driver-specific options) | +| .Spec.Labels | Labels for this secret | | .Spec.Name | Name of secret | | .UpdatedAt | When secret was last updated (relative timestamp, human-readable) | diff --git a/hack/xref-helpmsgs-manpages b/hack/xref-helpmsgs-manpages index 57e83b2164..51772d484c 100755 --- a/hack/xref-helpmsgs-manpages +++ b/hack/xref-helpmsgs-manpages @@ -35,6 +35,43 @@ my $Markdown_Path = "$Docs_Path/markdown"; # Global error count my $Errs = 0; +# Table of exceptions for documenting fields in '--format {{.Foo}}' +# +# Autocomplete is wonderful, and it's even better when we document the +# existing options. Unfortunately, sometimes internal structures get +# exposed that are of no use to anyone and cannot be guaranteed. Avoid +# documenting those. This table lists those exceptions. Format is: +# +# foo .Bar +# +# ...such that "podman foo --format '{{.Bar}}'" will not be documented. +# +my $Format_Exceptions = <<'END_EXCEPTIONS'; +# Deep internal structs; pretty sure these are permanent exceptions +events .Details +history .ImageHistoryLayer +images .ImageSummary +network-ls .Network + +# FIXME: this one, maybe? But someone needs to write the text +machine-list .Starting + +# No clue what these are. Some are just different-case dups of others. +pod-ps .Containers .Id .InfraId .ListPodsReport .Namespace +ps .Cgroup .CGROUPNS .IPC .ListContainer .MNT .Namespaces .NET .PIDNS .User .USERNS .UTS + +# I think .Destination is an internal struct, but .IsMachine maybe needs doc? +system-connection-list .Destination .IsMachine +END_EXCEPTIONS + +my %Format_Exceptions; +for my $line (split "\n", $Format_Exceptions) { + $line =~ s/#.*$//; # strip comments + next unless $line; # skip empty lines + my ($subcommand, @fields) = split(' ', $line); + $Format_Exceptions{"podman-$subcommand"} = \@fields; +} + # END user-customizable section ############################################################################### @@ -126,14 +163,38 @@ sub main { sub xref_by_help { my ($help, $man, @subcommand) = @_; + OPTION: for my $k (sort keys %$help) { if (exists $man->{$k}) { if (ref $help->{$k}) { + # This happens when 'podman foo --format' offers + # autocompletion that looks like a Go template, but those + # template options aren't documented in the man pages. + if ($k eq '--format' && ! ref($man->{$k})) { + warn "$ME: 'podman @subcommand': --format options are available through autocomplete, but are not documented in $man->{_path}\n"; + + # FIXME: don't make this an error... yet. + # ++$Errs; + next OPTION; + } + xref_by_help($help->{$k}, $man->{$k}, @subcommand, $k); } # Otherwise, non-ref is leaf node such as a --option } else { + # Not documented in man. However, handle '...' as a special case + # in formatting strings. E.g., 'podman info .Host' is documented + # in the man page as '.Host ...' to indicate that the subfields + # are way too many to list individually. + my $k_copy = $k; + while ($k_copy =~ s/\.[^.]+$//) { + if (($man->{$k_copy}||'') eq '...') { + next OPTION; + } + } + + # Nope, it's not that case. my $man = $man->{_path} || 'man'; warn "$ME: 'podman @subcommand --help' lists '$k', which is not in $man\n"; ++$Errs; @@ -152,11 +213,23 @@ sub xref_by_man { my ($help, $man, @subcommand) = @_; # FIXME: this generates way too much output + KEYWORD: for my $k (grep { $_ ne '_path' } sort keys %$man) { + if ($k eq '--format' && ref($man->{$k}) && ! ref($help->{$k})) { + warn "$ME: 'podman @subcommand': --format options documented in man page, but not available via autocomplete\n"; + next KEYWORD; + } + if (exists $help->{$k}) { if (ref $man->{$k}) { xref_by_man($help->{$k}, $man->{$k}, @subcommand, $k); } + elsif ($k =~ /^-/) { + # This is OK: we don't recurse into options + } + else { + # FIXME: should never get here, but we do. Figure it out later. + } } elsif ($k ne '--help' && $k ne '-h') { my $man = $man->{_path} || 'man'; @@ -254,15 +327,39 @@ sub podman_help { } } elsif ($section eq 'options') { + my $opt = ''; + # Handle '--foo' or '-f, --foo' if ($line =~ /^\s{1,10}(--\S+)\s/) { print "> podman @_ $1\n" if $debug; - $help{$1} = 1; + $opt = $1; + $help{$opt} = 1; } elsif ($line =~ /^\s{1,10}(-\S),\s+(--\S+)\s/) { print "> podman @_ $1, $2\n" if $debug; - $help{$1} = $help{$2} = 1; + $opt = $2; + $help{$1} = $help{$opt} = 1; } + + # Special case for --format: run podman with autocomplete. + # If that lists one or more '{{.Foo}}' or '{{.Foo.' entries + # (indicating terminal or nonterminal nodes respectively) + # convert our option data structure from scalar (indicating + # that we just cross-check for existence in the man page) + # to hashref (indicating that we recurse down and cross-check + # each individual param). + if ($opt eq '--format') { + my @completions = _completions(@_, '--format', '{{.'); + for my $c (@completions) { + if ($c =~ /^\{\{(\.\S+)(\.|\}\})$/) { + # First time through: convert to a hashref + $help{$opt} = {} if ! ref($help{$opt}); + + # Remember this param + $help{$opt}{$1} = 1; + } + } + } } } close $fh @@ -420,6 +517,31 @@ sub podman_man { } } } + + # --format does not always mean a Go format! E.g., push --format=oci + if ($previous_flag eq '--format') { + # ...but if there's a table like '| .Foo | blah blah |' + # then it's definitely a Go template. '.Foo ...' (three dots) + # indicates that .Foo includes a number of subfields .Foo.Xxx, + # .Foo.Yyy too numerous to list individually in man pages. + # 1 12 3 32 + if ($line =~ /^\|\s+(\.\S+)(\s+(\.\.\.))?\s+\|/) { + my ($format, $etc) = ($1, $3); + + # Confirmed: we have a table with '.Foo' strings, so + # this is a Go template. Override previous (scalar) + # setting of the --format flag with a hash, indicating + # that we will recursively cross-check each param. + if (! ref($man{$previous_flag})) { + $man{$previous_flag} = { _path => $subpath }; + } + + # ...and document this format option. $etc, if set, + # will be '...' which indicates that $format has + # too many subformats to document individually. + $man{$previous_flag}{$format} = $etc || 1; + } + } } # It's easy to make mistakes in the SEE ALSO elements. @@ -429,6 +551,13 @@ sub podman_man { } close $fh; + # Done reading man page. If there are any '--format' exceptions defined + # for this command, flag them as seen, and as '...' so we don't + # complain about any sub-fields. + if (my $fields = $Format_Exceptions{$command}) { + $man{"--format"}{$_} = '...' for @$fields; + } + # Special case: the 'image trust' man page tries hard to cover both set # and show, which means it ends up not being machine-readable. if ($command eq 'podman-image-trust') { @@ -511,6 +640,45 @@ sub podman_rst { return \%rst; } +################## +# _completions # run podman __completeNoDesc, return list of completions +################## +sub _completions { + my $kidpid = open my $podman_fh, '-|'; + if (! defined $kidpid) { + die "$ME: Could not fork: $!\n"; + } + + if ($kidpid == 0) { + # We are the child + close STDERR; + exec $PODMAN, '__completeNoDesc', @_; + die "$ME: Could not exec: $!\n"; + } + + # We are the parent + my @completions; + while (my $line = <$podman_fh>) { + chomp $line; + push @completions, $line; + + # Recursively expand Go templates, like '{{.Server.Os}}' + if ($line =~ /^\{\{\..*\.$/) { + my @cmd_copy = @_; # clone of podman subcommands... + pop @cmd_copy; # ...so we can recurse with new format + my @subcompletions = _completions(@cmd_copy, $line); + + # A huge number of deep fields are time-related. Don't document them. + my @is_time = grep { /Nanosecond|UnixNano|YearDay/ } @subcompletions; + push @completions, @subcompletions + unless @is_time >= 3; + } + } + close $podman_fh + or warn "$ME: Error running podman __completeNoDesc @_\n"; + return @completions; +} + # END data gathering ############################################################################### # BEGIN sanity checking of SEE ALSO links