openafs/doc/man-pages/generate-man
Michael Meffie c66971ce42 man-pages: Generate man pages with Pod::Man
The generate-man script is currently a shell script which invokes the
pod2man command for each pod file to be converted into a man page. This
makes the pod conversion slow, since we load Perl and create a Pod::Man
parser for each pod file.  In addition to being slow, generate-man
leaves behind a partially created man page when an error is
encountered during the pod2man execution.

To fix these issues, rewrite generate-man as a Perl script which uses
the Pod::Man module directly.  The Pod::Man parser is created only once
and is reused to generate each man page.  The Pod::Man module supports
this type of batch mode operation by clearing its internal state after
each man page is created.

We have some special processing to determine the man page names for the
pages in section 3, so create a sub class to handle the pod filename to
man page title determination, and add a helper function to support
processing more than one section with a single parser instance.

Be sure to cleanup any partially created man pages if an error is
encountered during the pod to man conversion.  This will let us use this
script in the Makefiles in the future.

Change-Id: I8d3cce1edc62c490e93d05f72609dfde4b599a1b
Reviewed-on: https://gerrit.openafs.org/15774
Reviewed-by: Mark Vitale <mvitale@sinenomine.net>
Tested-by: Mark Vitale <mvitale@sinenomine.net>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Cheyenne Wills <cwills@sinenomine.net>
Reviewed-by: Michael Meffie <mmeffie@sinenomine.net>
2024-07-09 12:25:55 -04:00

102 lines
2.9 KiB
Perl
Executable File

#!/usr/bin/perl -w
#
# Generate the OpenAFS man pages from POD source. Run merge-pod
# first to generate the POD source files.
#
package OpenAFS::Man;
use strict;
use vars qw(@ISA);
use Pod::Man;
@ISA = qw(Pod::Man);
# Subclass Pod::Man to support OpenAFS man page generation.
sub new {
my $class = shift;
my $self = Pod::Man->new('release' => 'OpenAFS', 'errors' => 'die');
bless ($self, 'OpenAFS::Man');
return $self;
}
# Set the current section number and heading text.
sub start_section {
my ($self, $section, $heading) = @_;
$self->{'section'} = $section;
$self->{'center'} = $heading;
}
# Set the man page title based on the file name and section number.
#
# Unless the current section number is 3, the title is taken from the
# name of the pod file being converted.
#
# Special handing is required for man pages in section 3 (libraries). The
# title of these pages are like "AFS::foo.3", but Windows does not support
# colon characters (:) in filenames, so we use dot '.' as a placeholder
# and convert the '.' found to '::' to create the title string set in
# the generated man page.
#
# In the future, the pod files may be organized in subdirectories, like
# pod3/lib/AFS/foo.pod (instead of pod3/AFS.foo.pod), which would be more
# conventional solution.
sub set_name {
my ($self, $pod) = @_;
my $name = $pod;
$name =~ s/\.pod$//;
if ($self->{'section'} == 3) {
$name =~ s/\./::/g;
}
$self->{'name'} = $name;
return $self->{'name'};
}
# Required for Pod::Simple::version_report()
sub VERSION () { '1.0' }
package main;
use strict;
use File::Spec;
my %HEADINGS = (
1 => 'AFS Command Reference',
3 => 'AFS Library Reference',
5 => 'AFS File Reference',
8 => 'AFS Command Reference'
);
# Create the parser object and generate the man pages for each pod file
# in each section.
#
# Remove partially generated files if an error is encountered.
sub generate_man_pages {
my $parser = OpenAFS::Man->new();
for my $section (sort(keys(%HEADINGS))) {
if (! -d "man${section}") {
mkdir("man${section}", 0755) or
die "Cannot create man${section} directory: $!\n";
}
$parser->start_section($section, $HEADINGS{$section});
opendir(D, "pod${section}") or die "Cannot open pod${section}: $!\n";
for my $file (readdir(D)) {
next unless $file =~ /\.pod$/; # Skip non-pod files.
my $name = $parser->set_name($file);
my $input = File::Spec->join("pod${section}", $file);
my $output = File::Spec->join("man${section}", "${name}.${section}");
eval {
$parser->parse_from_file($input, $output);
};
if ($@) {
if (-s $output) {
unlink($output); # Remove partially created file.
}
die "Unable to parse $input: $@";
}
}
}
}
generate_man_pages();