github.com/containers/podman/v5@v5.1.0-rc1/hack/man-page-table-check (about)

     1  #!/usr/bin/perl
     2  #
     3  # man-page-table-check - workaround for go-md2man bug that screws up tables
     4  #
     5  package Podman::ManPage::TableCheck;
     6  
     7  use v5.14;
     8  use utf8;
     9  
    10  use strict;
    11  use warnings;
    12  
    13  (our $ME = $0) =~ s|.*/||;
    14  
    15  ###############################################################################
    16  # BEGIN boilerplate args checking, usage messages
    17  
    18  sub usage {
    19      print  <<"END_USAGE";
    20  Usage: $ME [OPTIONS]
    21  
    22  $ME checks man pages (the *roff files produced
    23  by go-md2man) for empty table cells. Reason: go-md2man cannot handle
    24  markdown characters (e.g. asterisk) in tables. It produces horribly
    25  broken *roff which in turn makes unreadable man pages.
    26  
    27  If $ME finds broken tables, it will highlight them
    28  and display hints on how to resolve the problem.
    29  
    30  OPTIONS:
    31    --help         display this message
    32  END_USAGE
    33  
    34      exit;
    35  }
    36  
    37  # Command-line options.  Note that this operates directly on @ARGV !
    38  our $debug   = 0;
    39  our $force   = 0;
    40  our $verbose = 0;
    41  our $NOT     = '';              # print "blahing the blah$NOT\n" if $debug
    42  sub handle_opts {
    43      use Getopt::Long;
    44      GetOptions(
    45          'debug!'     => \$debug,
    46  
    47          help         => \&usage,
    48      ) or die "Try `$ME --help' for help\n";
    49  }
    50  
    51  # END   boilerplate args checking, usage messages
    52  ###############################################################################
    53  
    54  ############################## CODE BEGINS HERE ###############################
    55  
    56  # The term is "modulino".
    57  __PACKAGE__->main()                                     unless caller();
    58  
    59  # Main code.
    60  sub main {
    61      # Note that we operate directly on @ARGV, not on function parameters.
    62      # This is deliberate: it's because Getopt::Long only operates on @ARGV
    63      # and there's no clean way to make it use @_.
    64      handle_opts();                      # will set package globals
    65  
    66      die "$ME: Too many arguments; try $ME --help\n"                 if @ARGV;
    67  
    68      my $manpage_dir = 'docs/build/man';         # FIXME-hardcoding
    69      opendir my $dir_fh, $manpage_dir
    70          or die "$ME: Cannot opendir $manpage_dir: $!\n";
    71      my @manpages;
    72      for my $ent (sort readdir $dir_fh) {
    73          next unless $ent =~ /^[a-z].*\.[1-8][a-z]?$/;   # groff files only
    74          next if -l "$manpage_dir/$ent";                 # skip links
    75          push @manpages, $ent;
    76      }
    77      closedir $dir_fh;
    78  
    79      @manpages
    80          or die "$ME: did not find any .[1-8] files under $manpage_dir\n";
    81  
    82      my $errs = 0;
    83      for my $file (@manpages) {
    84          $errs += check_tables("$manpage_dir/$file");
    85      }
    86      exit 0 if !$errs;
    87  
    88      die "\n$ME: found empty cells in the above man page(s)
    89  
    90  This is a bug in go-md2man: it gets really confused when it sees
    91  misaligned vertical-bar signs ('|') in tables, or a left-hand
    92  column with more than 31 characters.
    93  
    94  WORKAROUND: find the above line(s) in the docs/source/markdown file,
    95  then fix the issue (left as exercise for the reader). Keep regenerating
    96  docs until it passes:
    97  
    98      \$ make -C docs clean;make docs;$0
    99  "
   100  }
   101  
   102  
   103  sub check_tables {
   104      my $path = shift;
   105  
   106      my $status = 0;
   107  
   108      my @cmd = ('man', '-l', '--no-hyphenation', '-Tlatin1', '-');
   109      pipe my $fh_read, my $fh_write;
   110      my $kidpid = fork;
   111      if ($kidpid) {                      # we are the parent
   112          close $fh_write;
   113      }
   114      elsif (defined $kidpid) {           # we are the child
   115          close $fh_read;
   116  
   117          open my $fh_in, '<:utf8', $path
   118              or die "$ME: Could not read $path: $!\n";
   119          # groff spits out nasty useless warnings
   120          close STDERR;
   121          open STDOUT, '>&', $fh_write;
   122          open my $fh_man, '|-', @cmd
   123              or die "$ME: Could not fork: $! (message will never be seen)\n";
   124  
   125          while (my $line = <$fh_in>) {
   126              $line =~ s/✅/OK/g;
   127              print { $fh_man } $line;
   128          }
   129          close $fh_in or die;
   130          close $fh_man or die;
   131          exit 0;
   132      }
   133      else {                              # fork failed
   134          die "$ME: could not fork: $!";
   135      }
   136  
   137      my $linecount = 0;
   138      my $want = 0;
   139      while (my $line = <$fh_read>) {
   140          ++$linecount;
   141  
   142          chomp $line;
   143          # Table borders (+----------+------------+)
   144          if ($line =~ /^\s*\+-+\+-+/) {
   145              $want = 1;
   146              next;
   147          }
   148  
   149          # Row immediately after table borders
   150          elsif ($want) {
   151  #            print $line, "\n";
   152              # *Two* blank cells is OK, go-md2man always does this
   153              # on the last row of each table.
   154              if ($line !~ /^\s*\|\s+\|\s+\|/) {
   155                  if ($line =~ /\|\s+\|/) {
   156                      warn "\n$ME: $path:\n"         if $status == 0;
   157                      warn "   $line\n";
   158                      $status = 1;
   159                  }
   160              }
   161          }
   162          $want = 0;
   163      }
   164      close $fh_read;
   165      die "$ME: $path: command failed: @cmd\n"    if $?;
   166      waitpid $kidpid, 0;
   167  
   168      if ($linecount < 10) {
   169          die "$ME: $path: nothing seen!\n";
   170      }
   171  
   172      return $status;
   173  }
   174  
   175  
   176  1;