diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2012-07-16 19:41:39 +0100 |
---|---|---|
committer | Richard W.M. Jones <rjones@redhat.com> | 2012-08-05 22:48:50 +0100 |
commit | 3530e9d3dce5fd019646c46d14992c383e8e3f3a (patch) | |
tree | ab1dcc4c1644b4361303ba282865ee16d78e80da | |
parent | b5b5f1ad8bff7e59d7d7a54e2c90cb50283c1083 (diff) | |
download | libguestfs-3530e9d3dce5fd019646c46d14992c383e8e3f3a.tar.gz libguestfs-3530e9d3dce5fd019646c46d14992c383e8e3f3a.tar.xz libguestfs-3530e9d3dce5fd019646c46d14992c383e8e3f3a.zip |
Replace podwrapper shell script with custom Perl script.
This uses Pod::Simple so it properly parses the input POD and can
generate proper custom output as required specifically by libguestfs.
One immediate benefit is that links between and within manual pages
now work mostly correctly.
(cherry picked from commit 1e17a32060feb937b3972f61b37f9116ad7d8d9a)
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | README | 5 | ||||
-rw-r--r-- | configure.ac | 42 | ||||
-rwxr-xr-x | podwrapper.pl.in | 374 | ||||
-rwxr-xr-x | podwrapper.sh.in | 215 |
5 files changed, 390 insertions, 249 deletions
@@ -265,14 +265,13 @@ php/extension/php_guestfs_php.h php/extension/run-tests.php php/extension/tmp-php.ini po/boldquot.sed -pod2htm?.tmp po-docs/*/*.1 po-docs/*/*.3 po-docs/*/*.pl po-docs/po4a.conf po-docs/*/*.pod /po-docs/*/stamp-update-po -podwrapper.sh +podwrapper.pl po/en@boldquot.header po/en@quot.header po/*.gmo @@ -88,8 +88,9 @@ For basic functionality and the C tools: - systemtap/DTrace userspace probes (optional) http://sourceware.org/systemtap/wiki/AddingUserSpaceProbingToApps -- perldoc (pod2man, pod2text, pod2html) to generate the manual pages - and other documentation. +- perl Pod::Man and Pod::Simple are required. These are used to + generate man pages and other documentation. Every recent Perl + distribution ought to include both. - Readline to have nicer command-line editing in guestfish (optional) diff --git a/configure.ac b/configure.ac index 0d13e423..23885852 100644 --- a/configure.ac +++ b/configure.ac @@ -426,40 +426,22 @@ AC_CHECK_PROG([GPERF],[gperf],[gperf],[no]) test "x$GPERF" = "xno" && AC_MSG_ERROR([gperf must be installed]) -dnl Check for pod2man, pod2text, pod2html. -AC_CHECK_PROG([POD2MAN],[pod2man],[pod2man],[no]) -test "x$POD2MAN" = "xno" && - AC_MSG_ERROR([pod2man must be installed]) -AC_CHECK_PROG([POD2TEXT],[pod2text],[pod2text],[no]) -test "x$POD2TEXT" = "xno" && - AC_MSG_ERROR([pod2text must be installed]) -AC_CHECK_PROG([POD2HTML],[pod2html],[pod2html],[no]) -test "x$POD2HTML" = "xno" && - AC_MSG_ERROR([pod2html must be installed]) - -dnl Check if pod2man, pod2text take --stderr and -u options (not in RHEL 5). -AC_MSG_CHECKING([if pod2man takes --stderr option]) -if "$POD2MAN" --stderr >&AS_MESSAGE_LOG_FD 2>&1; then - AC_MSG_RESULT([yes]) - POD2_STDERR_OPTION="--stderr" +dnl Check for Pod::Man, Pod::Simple. +AC_MSG_CHECKING([for Pod::Man]) +if ! perl -MPod::Man -e1 >&AS_MESSAGE_LOG_FD 2>&1; then + AC_MSG_ERROR([perl Pod::Man must be installed]) else - AC_MSG_RESULT([no]) - POD2_STDERR_OPTION="" -fi -AC_SUBST([POD2_STDERR_OPTION]) - -AC_MSG_CHECKING([if pod2man takes -u option]) -if "$POD2MAN" -u >&AS_MESSAGE_LOG_FD 2>&1; then AC_MSG_RESULT([yes]) - POD2_UTF8_OPTION="-u" +fi +AC_MSG_CHECKING([for Pod::Simple]) +if ! perl -MPod::Simple -e1 >&AS_MESSAGE_LOG_FD 2>&1; then + AC_MSG_ERROR([perl Pod::Simple must be installed]) else - AC_MSG_RESULT([no]) - POD2_UTF8_OPTION="" + AC_MSG_RESULT([yes]) fi -AC_SUBST([POD2_UTF8_OPTION]) dnl Define the path to the podwrapper program. -PODWRAPPER="$(pwd)/podwrapper.sh" +PODWRAPPER="$(pwd)/podwrapper.pl" AC_SUBST([PODWRAPPER]) dnl Check for genisoimage/mkisofs @@ -1188,8 +1170,8 @@ AC_CONFIG_HEADERS([config.h]) dnl http://www.mail-archive.com/automake@gnu.org/msg10204.html AC_CONFIG_FILES([clone/virt-sysprep], [chmod +x,-w clone/virt-sysprep]) -AC_CONFIG_FILES([podwrapper.sh], - [chmod +x,-w podwrapper.sh]) +AC_CONFIG_FILES([podwrapper.pl], + [chmod +x,-w podwrapper.pl]) AC_CONFIG_FILES([run], [chmod +x,-w run]) AC_CONFIG_FILES([Makefile diff --git a/podwrapper.pl.in b/podwrapper.pl.in new file mode 100755 index 00000000..7ff13b36 --- /dev/null +++ b/podwrapper.pl.in @@ -0,0 +1,374 @@ +#!/usr/bin/perl -w +# podwrapper.pl +# Copyright (C) 2010-2012 Red Hat Inc. +# @configure_input@ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +use warnings; +use strict; + +use Pod::Usage; +use Getopt::Long; +use Pod::Man; +use Pod::Simple; +use Pod::Simple::Text; +use Pod::Simple::XHTML; +use File::Basename; + +=encoding utf8 + +=head1 NAME + +podwrapper.pl - Generate various output formats from POD input files + +=head1 SYNOPSIS + + virt-foo.1 $(top_builddir)/html/virt-foo.1.html: stamp-virt-foo.pod + stamp-virt-foo.pod: virt-foo.pod + $(PODWRAPPER) --man virt-foo.1 --html virt-foo.1.html $< + touch $@ + +=head1 DESCRIPTION + +podwrapper is a Perl script that generates various output formats +from POD input files that libguestfs uses for most documentation. + +You should specify an input file, and one or more output formats. +For example: + + podwrapper.pl virt-foo.pod --man virt-foo.1 + +will turn C<virt-foo.pod> into a man page C<virt-foo.1>. The output +options are I<--man>, I<--html> and I<--text> (see below). + +=head1 OPTIONS + +=over 4 + +=cut + +my $help; + +=item B<--help> + +Display brief help. + +=cut + +my $html; + +=item B<--html=output.html> + +Write a web page to C<output.html>. If this option is not +given, then no web page output is produced. + +=cut + +my @inserts; + +=item B<--insert=filename:@PATTERN@> + +In the input file, replace the literal text C<@PATTERN@> with the +replacement file C<filename>. You can give this option multiple +times. + +The contents of C<filename> are treated as POD. +Compare and contrast with I<--verbatim>. + +Although it is conventional to use C<@...@> for patterns, in fact +you can use any string as the pattern. + +=cut + +my $man; + +=item B<--man=output.n> + +Write a man page to C<output.n>. If this option is not +given, then no man page output is produced. + +=cut + +my $name; + +=item B<--name=name> + +Set the name of the man page. If not set, defaults to the basename +of the input file. + +=cut + +my $section; + +=item B<--section=N> + +Set the section of the man page (a number such as C<1> for +command line utilities or C<3> for C API documentation). If +not set, defaults to C<1>. + +=cut + +my $text; + +=item B<--text=output.txt> + +Write a text file to C<output.txt>. If this option is not +given, then no text output is produced. + +=cut + +my @verbatims; + +=item B<--verbatim=filename:@PATTERN@> + +In the input file, replace the literal text C<@PATTERN@> with the +replacement file C<filename>. You can give this option multiple +times. + +The contents of C<filename> are inserted as verbatim text, and +are I<not> interpreted as POD. +Compare and contrast with I<--insert>. + +Although it is conventional to use C<@...@> for patterns, in fact +you can use any string as the pattern. + +=cut + +=back + +=cut + +GetOptions ("help|?" => \$help, + "html=s" => \$html, + "insert=s" => \@inserts, + "man=s" => \$man, + "name=s" => \$name, + "section=s" => \$section, + "text=s" => \$text, + "verbatim=s" => \@verbatims + ) or pod2usage (2); +pod2usage (1) if $help; + +die "missing argument: podwrapper input.pod\n" unless @ARGV == 1; +my $input = $ARGV[0]; + +# There should be at least one output. +die "$0: no output format specified. Use --man and/or --html and/or --text.\n" + unless defined $man || defined $html || defined $text; + +# Default for $name and $section. +$name = basename ($input, ".pod") unless defined $name; +$section = 1 unless defined $section; + +# Note that these @...@ are substituted by ./configure. +my $abs_top_srcdir = "@abs_top_srcdir@"; +my $abs_top_builddir = "@abs_top_builddir@"; +my $package_name = "@PACKAGE_NAME@"; +my $package_version = "@PACKAGE_VERSION@"; + +die "$0: ./configure substitutions were not performed" + unless $abs_top_srcdir && $abs_top_builddir && + $package_name && $package_version; + +# Create a stable date (thanks Hilko Bengen). +my $date; +my $filename = "$abs_top_srcdir/ChangeLog"; +if (-r $filename) { + open FILE, $filename or die "$filename: $!"; + $_ = <FILE>; + close FILE; + $date = $1 if /^(\d+-\d+-\d+)\s/; +} +$filename = "$abs_top_srcdir/.git"; +if (!$date && -d $filename) { + $_ = `git show --git-dir=$filename -s --format=%ci`; + $date = $1 if /^(\d+-\d+-\d+)\s/; +} +if (!$date) { + my ($day, $month, $year) = (localtime)[3,4,5]; + $date = sprintf ("%04d-%02d-%02d", $year+1900, $month+1, $day); +} + +# Create a release string. +my $release = "$package_name-$package_version"; + +#print "input=$input\n"; +#print "name=$name\n"; +#print "section=$section\n"; +#print "date=$date\n"; + +# Read the input. +my $content = read_whole_file ($input); + +# Perform @inserts. +foreach (@inserts) { + my @a = split /:/, $_, 2; + die "$0: no colon in parameter of --insert\n" unless @a >= 2; + my $replacement = read_whole_file ($a[0]); + $content =~ s/$a[1]/$replacement/ge; +} + +# Perform @verbatims. +foreach (@verbatims) { + my @a = split /:/, $_, 2; + die "$0: no colon in parameter of --verbatim\n" unless @a >= 2; + my $replacement = read_verbatim_file ($a[0]); + $content =~ s/$a[1]/$replacement/ge; +} + +# Output man page. +if ($man) { + my $parser = Pod::Man->new (name => $name, + release => $release, section => $section, + center => "Virtualization Support", + date => $date); + my $output; + $parser->output_string (\$output); + $parser->parse_string_document ($content) + or die "$0: could not parse input document"; + open OUT, ">$man" or die "$man: $!"; + print OUT $output or die "$man: $!"; + close OUT or die "$man: $!"; + print "$0: wrote $man\n"; +} + +# Output HTML. +SUBCLASS: { + # Subclass Pod::Simple::XHTML. See the documentation. + package Podwrapper::XHTML; + + use vars qw(@ISA); + @ISA = qw(Pod::Simple::XHTML); + + # Pod::Simple::XHTML returns uppercase identifiers, whereas the + # old pod2html returns lowercase ones. + sub idify + { + my $self = shift; + my $id = $self->SUPER::idify (@_); + lc ($id); + } + + sub is_a_libguestfs_page + { + local $_ = shift; + + return 1 if /^Sys::Guestfs/; + return 1 if /^virt-/; + return 1 if /^libguestf/; + return 1 if /^guestf/; + return 1 if /^guestmount/; + return 1 if /^hivex/; + return 1 if /^febootstrap/; + return 0; + } + + sub resolve_pod_page_link + { + my $self = shift; + my $podname = $_[0]; # eg. "Sys::Guestfs", can be undef + my $anchor = $_[1]; # eg. "SYNOPSIS", can be undef + my $r = ""; + if (defined $podname) { + return $self->SUPER::resolve_pod_page_link (@_) + unless is_a_libguestfs_page ($podname); + $r .= "$podname.3.html" + } + $r .= "#" . $self->idify ($anchor, 1) if defined $anchor; + $r; + } + + sub resolve_man_page_link + { + my $self = shift; + my $name = $_[0]; # eg. "virt-make-fs(1)", can be undef + my $anchor = $_[1]; # eg. "SYNOPSIS", can be undef + my $r = ""; + if (defined $name) { + return $self->SUPER::resolve_man_page_link (@_) + unless is_a_libguestfs_page ($name); + $name =~ s/\((.*)\)$/.$1/; + $r .= "$name.html"; + } + $r .= "#" . $self->idify ($anchor, 1) if defined $anchor; + $r; + } +} + +if ($html) { + mkdir "$abs_top_builddir/html"; + + my $parser = Podwrapper::XHTML->new; + my $output; + $parser->output_string (\$output); + $parser->html_charset ("UTF-8"); + $parser->html_css ("pod.css"); + $parser->index (1); + $parser->parse_string_document ($content); + + # Hack for Perl 5.16. + $output =~ s{/>pod.css<}{/>\n<}; + + open OUT, ">$html" or die "$html: $!"; + print OUT $output or die "$html: $!"; + close OUT or die "$html: $!"; + print "$0: wrote $html\n"; +} + +# Output text. +if ($text) { + my $parser = Pod::Simple::Text->new; + my $output; + $parser->output_string (\$output); + $parser->parse_string_document ($content); + open OUT, ">$text" or die "$text: $!"; + print OUT $output or die "$text: $!"; + close OUT or die "$text: $!"; + print "$0: wrote $text\n"; +} + +sub read_whole_file +{ + my $input = shift; + local $/ = undef; + + open FILE, $input or die "$input: $!"; + $_ = <FILE>; + close FILE; + $_; +} + +sub read_verbatim_file +{ + my $input = shift; + my $r = ""; + + open FILE, $input or die "$input: $!"; + while (<FILE>) { + $r .= " $_"; + } + close FILE; + $r; +} + +=head1 AUTHOR + +Richard W.M. Jones. + +=head1 SEE ALSO + +libguestfs.git/README, +L<Pod::Simple> diff --git a/podwrapper.sh.in b/podwrapper.sh.in deleted file mode 100755 index c30df520..00000000 --- a/podwrapper.sh.in +++ /dev/null @@ -1,215 +0,0 @@ -#!/bin/bash - -# podwrapper.sh -# Copyright (C) 2010-2012 Red Hat Inc. -# @configure_input@ -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -# Wrapper script around POD utilities which can include files in the -# POD and controls HTML generation. - -unset CDPATH - -set -e -#set -x - -PACKAGE_NAME="@PACKAGE_NAME@" -PACKAGE_VERSION="@PACKAGE_VERSION@" -POD2MAN="@POD2MAN@" -POD2TEXT="@POD2TEXT@" -POD2HTML="@POD2HTML@" -POD2_STDERR_OPTION="@POD2_STDERR_OPTION@" -POD2_UTF8_OPTION="@POD2_UTF8_OPTION@" - -# This script could be run with any current directory, so if a source -# or build path is required it must be relative to the following -# absolute paths: -abs_top_srcdir="@abs_top_srcdir@" -abs_top_builddir="@abs_top_builddir@" - -if [ -z "$abs_top_srcdir" ]; then - echo "*** podwrapper.sh: error: abs_top_srcdir not defined" - echo "probably this is a very old version of autoconf and you need to" - echo "upgrade to a recent version" - exit 1 -fi - -if [ -z "$abs_top_builddir" ]; then - echo "*** podwrapper.sh: error: abs_top_builddir not defined" - echo "probably this is a very old version of autoconf and you need to" - echo "upgrade to a recent version" - exit 1 -fi - -if [ -e $abs_top_srcdir/ChangeLog ]; then - DATEPARAM=`awk '/^[0-9]+-[0-9]+-[0-9]+/ { print "--date=" $1; exit }' \ - $abs_top_srcdir/ChangeLog` -elif [ -d $abs_top_srcdir/.git ]; then - DATEPARAM=`git show -s --format=%ci | awk '{print "--date=" $1}'` -fi - -declare -a inserts -declare -a pattern -declare -a indent -nr_inserts=0 - -TEMP=`getopt \ - -o '' \ - --long section:,name:,man:,text:,html:,insert:,verbatim: \ - -n podwrapper.sh -- "$@"` -if [ $? != 0 ]; then - echo "podwrapper.sh: problem parsing the command line arguments" - exit 1 -fi -eval set -- "$TEMP" - -while true; do - case "$1" in - --section) - section="$2" - shift 2;; - --name) - name="$2" - shift 2;; - --man) - [ -z "$man_output" ] || { - echo "podwrapper.sh: --text option specified more than once" - exit 1 - } - man_output="$2" - shift 2;; - --text) - [ -z "$text_output" ] || { - echo "podwrapper.sh: --text option specified more than once" - exit 1 - } - text_output="$2" - shift 2;; - --html) - [ -z "$html_output" ] || { - echo "podwrapper.sh: --html option specified more than once" - exit 1 - } - html_output="$2" - shift 2;; - --insert) - inserts[$nr_inserts]=`echo "$2" | awk -F: '{print $1}'` - pattern[$nr_inserts]=`echo "$2" | awk -F: '{print $2}'` - indent[$nr_inserts]=no - ((++nr_inserts)) - shift 2;; - --verbatim) - inserts[$nr_inserts]=`echo "$2" | awk -F: '{print $1}'` - pattern[$nr_inserts]=`echo "$2" | awk -F: '{print $2}'` - indent[$nr_inserts]=yes - ((++nr_inserts)) - shift 2;; - --) - shift; break;; - *) - echo "podwrapper.sh: internal error in option parsing" - exit 1;; - esac -done - -# The remaining argument is the input POD file. -if [ $# -ne 1 ]; then - echo "podwrapper.sh [--options] input.pod" - exit 1 -fi -input="$1" - -#echo "input=$input" -#echo "man_output=$man_output" -#echo "text_output=$text_output" -#echo "html_output=$html_output" -#for i in `seq 0 $(($nr_inserts-1))`; do -# echo "insert $i: ${inserts[$i]} (pattern: ${pattern[$i]} indent: ${indent[$i]})" -#done - -# Should be at least one sort of output. -[ -z "$man_output" -a -z "$text_output" -a -z "$html_output" ] && { - echo "podwrapper.sh: no output specified" - exit 1 -} - -# If name and section are not set, make some sensible defaults. -[ -z "$section" ] && section=1 -[ -z "$name" ] && name=$(basename "$input" .pod) - -# Perform the insertions to produce a temporary POD file. -tmpdir="$(mktemp -d)" -trap "rm -rf $tmpdir; exit $?" EXIT - -if [ $nr_inserts -gt 0 ]; then - cmd="sed" - - for i in `seq 0 $(($nr_inserts-1))`; do - if [ "${indent[$i]}" = "yes" ]; then - sed 's/^/ /' < "${inserts[$i]}" > $tmpdir/$i - else - cp "${inserts[$i]}" $tmpdir/$i - fi - - cmd="$cmd -e /${pattern[$i]}/r$tmpdir/$i -e s/${pattern[$i]}//" - done - - $cmd < "$input" > $tmpdir/full.pod -else - cp "$input" $tmpdir/full.pod -fi - -# Now generate the final output format(s). -if [ -n "$man_output" ]; then - "$POD2MAN" "$POD2_STDERR_OPTION" "$POD2_UTF8_OPTION" \ - $DATEPARAM \ - --section "$section" -c "Virtualization Support" --name "$name" \ - --release "$PACKAGE_NAME-$PACKAGE_VERSION" \ - < $tmpdir/full.pod > "$man_output".tmp - mv "$man_output".tmp "$man_output" -fi - -if [ -n "$text_output" ]; then - "$POD2TEXT" "$POD2_STDERR_OPTION" "$POD2_UTF8_OPTION" \ - < $tmpdir/full.pod > "$text_output".tmp - mv "$text_output".tmp "$text_output" -fi - -if [ -n "$html_output" ]; then - mkdir -p "$abs_top_builddir/html" - "$POD2HTML" \ - --css "pod.css" --htmldir "$abs_top_builddir/html" \ - < $tmpdir/full.pod > "$html_output".tmp - mv "$html_output".tmp "$html_output" - - # Fix up some of the mess in the HTML output, mainly to make links - # between man pages work properly. - - # Rewrite <em>manpage(n)</em> to <a href=...>manpage(n)</a> if - # there is a linkable manual page. - sed_cmd="sed" - for f in $(cd "$abs_top_builddir/html" && ls -1 *.html); do - b=$(basename $f .html) - m=$(echo $b | sed 's/\(.*\)\.\([1-9]\)$/\1(\2)/') - sed_cmd="$sed_cmd -e 's,<em>$m</em>,<a href=$f>$m</a>,g'" - done - echo $sed_cmd - eval $sed_cmd < "$html_output" > "$html_output".tmp - mv "$html_output".tmp "$html_output" - - # Fix links like L<guestfs-foo(3)> - sed 's,<a href="#\([a-z]\+\)">guestfs-\1(\([1-9]\)),<a href="guestfs-\1.\2.html">guestfs-\1(\2),g' < "$html_output" > "$html_output".tmp - mv "$html_output".tmp "$html_output" -fi |