diff --git a/Makefile b/Makefile index bdbeae92b6..167bd9a5df 100644 --- a/Makefile +++ b/Makefile @@ -505,6 +505,7 @@ podman-remote-%-docs: podman-remote man-page-check: bin/podman hack/man-page-checker hack/xref-helpmsgs-manpages + hack/man-page-table-check .PHONY: swagger-check swagger-check: diff --git a/docs/source/markdown/podman-images.1.md.in b/docs/source/markdown/podman-images.1.md.in index 3926bdaa15..a1446bcf34 100644 --- a/docs/source/markdown/podman-images.1.md.in +++ b/docs/source/markdown/podman-images.1.md.in @@ -31,20 +31,20 @@ The *filters* argument format is of `key=value` or `key!=value`. If there is mor Supported filters: -| Filter | Description | -| :----------------: | --------------------------------------------------------------------------------------------- | -| *id* | Filter by image ID. | -| *before* | Filter by images created before the given IMAGE (name or tag). | -| *containers* | Filter by images with a running container. | -| *dangling* | Filter by dangling (unused) images. | -| *digest* | Filter by digest. | -| *intermediate* | Filter by images that are dangling and have no children | -| *label* | Filter by images with (or without, in the case of label!=[...] is used) the specified labels. | -| *manifest* | Filter by images that are manifest lists. | -| *readonly* | Filter by read-only or read/write images. | -| *reference* | Filter by image name. | -| *after*/*since* | Filter by images created after the given IMAGE (name or tag). | -| *until* | Filter by images created until the given duration or time. | +| Filter | Description | +|:---------------:|-----------------------------------------------------------------------------------------------| +| *id* | Filter by image ID. | +| *before* | Filter by images created before the given IMAGE (name or tag). | +| *containers* | Filter by images with a running container. | +| *dangling* | Filter by dangling (unused) images. | +| *digest* | Filter by digest. | +| *intermediate* | Filter by images that are dangling and have no children | +| *label* | Filter by images with (or without, in the case of label!=[...] is used) the specified labels. | +| *manifest* | Filter by images that are manifest lists. | +| *readonly* | Filter by read-only or read/write images. | +| *reference* | Filter by image name. | +| *after*/*since* | Filter by images created after the given IMAGE (name or tag). | +| *until* | Filter by images created until the given duration or time. | The `id` *filter* accepts the image ID string. diff --git a/docs/source/markdown/podman-systemd.unit.5.md b/docs/source/markdown/podman-systemd.unit.5.md index c7b615c7da..7c0677a063 100644 --- a/docs/source/markdown/podman-systemd.unit.5.md +++ b/docs/source/markdown/podman-systemd.unit.5.md @@ -84,56 +84,56 @@ There is only one required key, `Image`, which defines the container image the s Valid options for `[Container]` are listed below: -| **[Container] options** | **podman run equivalent** | -| ----------------- | ------------------ | -| AddCapability=CAP | --cap-add CAP | -| AddDevice=/dev/foo | --device /dev/foo | -| Annotation="YXZ" | --annotation "XYZ" | -| ContainerName=name | --name name | -| DropCapability=CAP | --cap-drop=CAP | -| Environment=foo=bar | --env foo=bar | -| EnvironmentFile=/tmp/env | --env-file /tmp/env | -| EnvironmentHost=true | --env-host | -| Exec=/usr/bin/command | Command after image specification - /usr/bin/command | -| ExposeHostPort=50-59 | --expose 50-59 | -| Group=1234 | --user UID:1234 | -| HealthCmd="/usr/bin/command" | --health-cmd="/usr/bin/command" | -| HealthInterval=2m | --health-interval=2m | -| HealthOnFailure=kill | --health-on-failure=kill | -| HealthRetries=5 | --health-retries=5 | -| HealthStartPeriod=1m | --health-start-period=period=1m | -| HealthStartupCmd="/usr/bin/command" | --health-startup-cmd="/usr/bin/command" | -| HealthStartupInterval=1m | --health-startup-interval=2m | -| HealthStartupRetries=8 | --health-startup-retries=8 | -| HealthStartupSuccess=2 | --health-startup-success=2 | -| HealthStartupTimeout=1m33s | --health-startup-timeout=1m33s | -| HealthTimeout=20s | --health-timeout=20s | -| HostName=new-host-name | --hostname="new-host-name" | -| Image=ubi8 | Image specification - ubi8 | -| IP=192.5.0.1 | --ip 192.5.0.0 | -| IP6=fd46:db93:aa76:ac37::10 | --ip6 2001:db8::1 | -| Label="YXZ" | --label "XYZ" | -| LogDriver=journald | --log-driver journald | -| Mount=type=bind,source=/path/on/host,destination=/path/in/container | --mount type=bind,source=/path/on/host,destination=/path/in/container | -| Network=host | --net host | -| NoNewPrivileges=true | --security-opt no-new-privileges | -| Rootfs=/var/lib/rootfs | --rootfs /var/lib/rootfs | -| Notify=true | --sdnotify container | -| PodmanArgs=--add-host foobar | --add-host foobar | -| PublishPort=true | --publish | -| ReadOnly=true | --read-only | -| RunInit=true | --init | -| SeccompProfile=/tmp/s.json | --security-opt seccomp=/tmp/s.json | -| SecurityLabelDisable=true | --security-opt label=disable | -| SecurityLabelFileType=usr_t | --security-opt label=filetype:usr_t | -| SecurityLabelLevel=s0:c1,c2 | --security-opt label=level:s0:c1,c2 | -| SecurityLabelType=spc_t | --security-opt label=type:spc_t | -| Timezone=local | --tz local | -| Tmpfs=/work | --tmpfs /work | -| User=bin | --user bin | -| UserNS=keep-id:uid=200,gid=210 | --userns keep-id:uid=200,gid=210 | -| VolatileTmp=true | --tmpfs /tmp | -| Volume=/source:/dest | --volume /source:/dest | +| **[Container] options** | **podman run equivalent** | +|--------------------------------|------------------------------------------------------| +| AddCapability=CAP | --cap-add CAP | +| AddDevice=/dev/foo | --device /dev/foo | +| Annotation="YXZ" | --annotation "XYZ" | +| ContainerName=name | --name name | +| DropCapability=CAP | --cap-drop=CAP | +| Environment=foo=bar | --env foo=bar | +| EnvironmentFile=/tmp/env | --env-file /tmp/env | +| EnvironmentHost=true | --env-host | +| Exec=/usr/bin/command | Command after image specification - /usr/bin/command | +| ExposeHostPort=50-59 | --expose 50-59 | +| Group=1234 | --user UID:1234 | +| HealthCmd="/usr/bin/command" | --health-cmd="/usr/bin/command" | +| HealthInterval=2m | --health-interval=2m | +| HealthOnFailure=kill | --health-on-failure=kill | +| HealthRetries=5 | --health-retries=5 | +| HealthStartPeriod=1m | --health-start-period=period=1m | +| HealthStartupCmd="command" | --health-startup-cmd="command" | +| HealthStartupInterval=1m | --health-startup-interval=2m | +| HealthStartupRetries=8 | --health-startup-retries=8 | +| HealthStartupSuccess=2 | --health-startup-success=2 | +| HealthStartupTimeout=1m33s | --health-startup-timeout=1m33s | +| HealthTimeout=20s | --health-timeout=20s | +| HostName=new-host-name | --hostname="new-host-name" | +| Image=ubi8 | Image specification - ubi8 | +| IP=192.5.0.1 | --ip 192.5.0.0 | +| IP6=fd46:db93:aa76:ac37::10 | --ip6 2001:db8::1 | +| Label="YXZ" | --label "XYZ" | +| LogDriver=journald | --log-driver journald | +| Mount=type=... | --mount type=... | +| Network=host | --net host | +| NoNewPrivileges=true | --security-opt no-new-privileges | +| Rootfs=/var/lib/rootfs | --rootfs /var/lib/rootfs | +| Notify=true | --sdnotify container | +| PodmanArgs=--add-host foobar | --add-host foobar | +| PublishPort=true | --publish | +| ReadOnly=true | --read-only | +| RunInit=true | --init | +| SeccompProfile=/tmp/s.json | --security-opt seccomp=/tmp/s.json | +| SecurityLabelDisable=true | --security-opt label=disable | +| SecurityLabelFileType=usr_t | --security-opt label=filetype:usr_t | +| SecurityLabelLevel=s0:c1,c2 | --security-opt label=level:s0:c1,c2 | +| SecurityLabelType=spc_t | --security-opt label=type:spc_t | +| Timezone=local | --tz local | +| Tmpfs=/work | --tmpfs /work | +| User=bin | --user bin | +| UserNS=keep-id:uid=200,gid=210 | --userns keep-id:uid=200,gid=210 | +| VolatileTmp=true | --tmpfs /tmp | +| Volume=/source:/dest | --volume /source:/dest | Description of `[Container]` section are: diff --git a/hack/man-page-table-check b/hack/man-page-table-check new file mode 100755 index 0000000000..98cb956b2e --- /dev/null +++ b/hack/man-page-table-check @@ -0,0 +1,176 @@ +#!/usr/bin/perl +# +# man-page-table-check - workaround for go-md2man bug that screws up tables +# +package Podman::ManPage::TableCheck; + +use v5.14; +use utf8; + +use strict; +use warnings; + +(our $ME = $0) =~ s|.*/||; + +############################################################################### +# BEGIN boilerplate args checking, usage messages + +sub usage { + print <<"END_USAGE"; +Usage: $ME [OPTIONS] + +$ME checks man pages (the *roff files produced +by go-md2man) for empty table cells. Reason: go-md2man cannot handle +markdown characters (e.g. asterisk) in tables. It produces horribly +broken *roff which in turn makes unreadable man pages. + +If $ME finds broken tables, it will highlight them +and display hints on how to resolve the problem. + +OPTIONS: + --help display this message +END_USAGE + + exit; +} + +# Command-line options. Note that this operates directly on @ARGV ! +our $debug = 0; +our $force = 0; +our $verbose = 0; +our $NOT = ''; # print "blahing the blah$NOT\n" if $debug +sub handle_opts { + use Getopt::Long; + GetOptions( + 'debug!' => \$debug, + + help => \&usage, + ) or die "Try `$ME --help' for help\n"; +} + +# END boilerplate args checking, usage messages +############################################################################### + +############################## CODE BEGINS HERE ############################### + +# The term is "modulino". +__PACKAGE__->main() unless caller(); + +# Main code. +sub main { + # Note that we operate directly on @ARGV, not on function parameters. + # This is deliberate: it's because Getopt::Long only operates on @ARGV + # and there's no clean way to make it use @_. + handle_opts(); # will set package globals + + die "$ME: Too many arguments; try $ME --help\n" if @ARGV; + + my $manpage_dir = 'docs/build/man'; # FIXME-hardcoding + opendir my $dir_fh, $manpage_dir + or die "$ME: Cannot opendir $manpage_dir: $!\n"; + my @manpages; + for my $ent (sort readdir $dir_fh) { + next unless $ent =~ /^[a-z].*\.[1-8][a-z]?$/; # groff files only + next if -l "$manpage_dir/$ent"; # skip links + push @manpages, $ent; + } + closedir $dir_fh; + + @manpages + or die "$ME: did not find any .[1-8] files under $manpage_dir\n"; + + my $errs = 0; + for my $file (@manpages) { + $errs += check_tables("$manpage_dir/$file"); + } + exit 0 if !$errs; + + die "\n$ME: found empty cells in the above man page(s) + +This is a bug in go-md2man: it gets really confused when it sees +misaligned vertical-bar signs ('|') in tables, or a left-hand +column with more than 31 characters. + +WORKAROUND: find the above line(s) in the docs/source/markdown file, +then fix the issue (left as exercise for the reader). Keep regenerating +docs until it passes: + + \$ make -C docs clean;make docs;$0 +" +} + + +sub check_tables { + my $path = shift; + + my $status = 0; + + my @cmd = ('man', '-l', '--no-hyphenation', '-Tlatin1', '-'); + pipe my $fh_read, my $fh_write; + my $kidpid = fork; + if ($kidpid) { # we are the parent + close $fh_write; + } + elsif (defined $kidpid) { # we are the child + close $fh_read; + + open my $fh_in, '<:utf8', $path + or die "$ME: Could not read $path: $!\n"; + # groff spits out nasty useless warnings + close STDERR; + open STDOUT, '>&', $fh_write; + open my $fh_man, '|-', @cmd + or die "$ME: Could not fork: $! (message will never be seen)\n"; + + while (my $line = <$fh_in>) { + $line =~ s/✅/OK/g; + print { $fh_man } $line; + } + close $fh_in or die; + close $fh_man or die; + exit 0; + } + else { # fork failed + die "$ME: could not fork: $!"; + } + + my $linecount = 0; + my $want = 0; + while (my $line = <$fh_read>) { + ++$linecount; + + chomp $line; + # Table borders (+----------+------------+) + if ($line =~ /^\s*\+-+\+-+/) { + $want = 1; + next; + } + + # Row immediately after table borders + elsif ($want) { +# print $line, "\n"; + # *Two* blank cells is OK, go-md2man always does this + # on the last row of each table. + if ($line !~ /^\s*\|\s+\|\s+\|/) { + if ($line =~ /\|\s+\|/) { + warn "\n$ME: $path:\n" if $status == 0; + warn " $line\n"; + $status = 1; + } + } + } + $want = 0; + } + close $fh_read; + die "$ME: $path: command failed: @cmd\n" if $?; + waitpid $kidpid, 0; + + if ($linecount < 10) { + die "$ME: $path: nothing seen!\n"; + } + + return $status; +} + + +1;