Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Man pages: fix broken tables #18678

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
28 changes: 14 additions & 14 deletions docs/source/markdown/podman-images.1.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
100 changes: 50 additions & 50 deletions docs/source/markdown/podman-systemd.unit.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
176 changes: 176 additions & 0 deletions hack/man-page-table-check
Original file line number Diff line number Diff line change
@@ -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;