diff options
Diffstat (limited to 'dh_installman')
-rwxr-xr-x | dh_installman | 320 |
1 files changed, 203 insertions, 117 deletions
diff --git a/dh_installman b/dh_installman index af2d136d..c1583a76 100755 --- a/dh_installman +++ b/dh_installman @@ -11,21 +11,38 @@ use warnings; use File::Find; use Debian::Debhelper::Dh_Lib; +our $VERSION = DH_BUILTIN_VERSION; + =head1 SYNOPSIS B<dh_installman> [S<I<debhelper options>>] [S<I<manpage> ...>] =head1 DESCRIPTION -B<dh_installman> is a debhelper program that handles installing -man pages into the correct locations in package build directories. You tell -it what man pages go in your packages, and it figures out where to install -them based on the section field in their B<.TH> or B<.Dt> line. If you have -a properly formatted B<.TH> or B<.Dt> line, your man page will be installed -into the right directory, with the right name (this includes proper handling -of pages with a subsection, like B<3perl>, which are placed in F<man3>, and -given an extension of F<.3perl>). If your B<.TH> or B<.Dt> line is incorrect -or missing, the program may guess wrong based on the file extension. +B<dh_installman> is a debhelper program that handles installing man +pages into the correct locations in package build directories. + +In compat 10 and earlier, this program was primarily for when +upstream's build system does not properly install them as a part of +its install step (or it does not have an install step). In compat 11 +and later, it supports the same features of L<dh_install(1)> and +has the advantage that it respects the B<nodoc> build profile (unlike +L<dh_install(1)>). + +Even if you prefer to use L<dh_install(1)> for installing the manpages, +B<dh_installman> can still be useful for converting the manpage encoding +to UTF-8 and for converting F<.so> links (as described below). However, +that part happens automatically without any explicit configuration. + + +You tell B<dh_installman> what man pages go in your packages, and it figures out +where to install them based on the section field in their B<.TH> or +B<.Dt> line. If you have a properly formatted B<.TH> or B<.Dt> line, +your man page will be installed into the right directory, with the +right name (this includes proper handling of pages with a subsection, +like B<3perl>, which are placed in F<man3>, and given an extension of +F<.3perl>). If your B<.TH> or B<.Dt> line is incorrect or missing, the +program may guess wrong based on the file extension. It also supports translated man pages, by looking for extensions like F<.ll.8> and F<.ll_LL.8>, or by use of the B<--language> switch. @@ -73,6 +90,16 @@ acted on. Use this to specify that the man pages being acted on are written in the specified language. +=item B<--sourcedir=>I<dir> + +Look in the specified directory for files to be installed. This option +requires compat 11 or later (it is silently ignored in compat 10 or earlier). + +Note that this is not the same as the B<--sourcedirectory> option used +by the B<dh_auto_>I<*> commands. You rarely need to use this option, since +B<dh_installman> automatically looks for files in F<debian/tmp> in debhelper +compatibility level 11 and above. + =item I<manpage> ... Install these man pages into the first package acted on. (Or in all @@ -80,6 +107,20 @@ packages if B<-A> is specified). =back +=head1 EXAMPLES + +An example F<debian/manpages> file could look like this: + + doc/man/foo.1 + # Translations + doc/man/foo.da.1 + doc/man/foo.de.1 + doc/man/foo.fr.1 + # NB: The following line is considered a polish translation + # of "foo.1" (and not a manpage written in perl called "foo.pl") + doc/man/foo.pl.1 + # ... + =head1 NOTES An older version of this program, L<dh_installmanpages(1)>, is still used @@ -91,139 +132,190 @@ interface. Use this program instead. init(options => { "language=s" => \$dh{LANGUAGE}, + "sourcedir=s" => \$dh{SOURCEDIR}, }); -my @sofiles; -my @sodests; -# PROMISE: DH NOOP WITHOUT manpages tmp(usr/share/man) +# PROMISE: DH NOOP WITHOUT pkgfile-logged(manpages) tmp(usr/share/man) -foreach my $package (@{$dh{DOPACKAGES}}) { - next if is_udeb($package); +my (@sofiles, @sodests); +my @all_packages = getpackages(); - my $tmp=tmpdir($package); - my $file=pkgfile($package,"manpages"); - my @manpages; +my $default_error_handler = compat(10) ? \&glob_expand_error_handler_warn_and_discard : \&glob_expand_error_handler_reject; +my $nodocs = is_build_profile_active('nodoc') || get_buildoption('nodoc') ? 1 : 0; +# We cannot assume documentation is built under nodoc, but if it is we must flag it as handled +# or dh_missing might make noise. +$default_error_handler = \&glob_expand_error_handler_silently_ignore if $nodocs; - @manpages=filearray($file, ".") if $file; +on_items_in_parallel(\@all_packages, sub { - if (($package eq $dh{FIRSTPACKAGE} || $dh{PARAMS_ALL}) && @ARGV) { - push @manpages, @ARGV; - } + foreach my $package (@_) { + next if is_udeb($package); - foreach my $page (@manpages) { - my $basename=basename($page); + my $tmp = tmpdir($package); + my $file = pkgfile($package, "manpages"); + my @manpages; + my @search_dirs = ('.'); + my $skip_install = process_pkg($package) ? 0 : 1; + my $error_handler = $skip_install ? \&glob_expand_error_handler_silently_ignore : $default_error_handler; + @search_dirs = ($dh{SOURCEDIR} // '.', default_sourcedir($package)) if not compat(10); - # Support compressed pages. - my $gz=''; - if ($basename=~m/(.*)(\.gz)/) { - $basename=$1; - $gz=$2; - } + @manpages = filearray($file, \@search_dirs, $error_handler) if $file; - my ($fd, $section); - # See if there is a .TH or .Dt entry in the man page. If so, - # we'll pull the section field from that. - if ($gz) { - $fd = open_gz($page) or die "$page: $!"; - } - else { - open($fd, '<', $page) or die "$page: $!"; + if (($package eq $dh{FIRSTPACKAGE} || $dh{PARAMS_ALL}) && @ARGV) { + push @manpages, @ARGV; } - while (<$fd>) { - if (/^\.TH\s+\S+\s+"?(\d+[^"\s]*)"?/ || - /^\.Dt\s+\S+\s+(\d+[^\s]*)/) { - $section=$1; - last; + + log_installed_files($package, @manpages); + + next if $skip_install or $nodocs; + + foreach my $page (@manpages) { + my $basename = basename($page); + + # Support compressed pages. + my $gz = ''; + if ($basename =~ m/(.*)(\.gz)/) { + $basename = $1; + $gz = $2; } - } - close($fd); - # Failing that, we can try to get it from the filename. - if (! $section) { - ($section)=$basename=~m/\.([1-9]\S*)/; - } - # Now get the numeric component of the section. - my ($realsection)=$section=~m/^(\d)/ if defined $section; - if (! $realsection) { - error("Could not determine section for $page"); - } - - # Get the man page's name -- everything up to the last dot. - my ($instname)=$basename=~m/^(.*)\./; - - my $destdir="$tmp/usr/share/man/man$realsection/"; - my $langcode; - if (! defined $dh{LANGUAGE} || ! exists $dh{LANGUAGE}) { - # Translated man pages are typically specified by adding the - # language code to the filename, so detect that and - # redirect to appropriate directory, stripping the code. - ($langcode)=$basename=~m/\.([a-z][a-z](?:_[A-Z][A-Z])?)\.(?:[1-9]|man)/; - } - elsif ($dh{LANGUAGE} ne 'C') { - $langcode=$dh{LANGUAGE}; - } - - if (defined $langcode && $langcode ne '') { - # Strip the language code from the instname. - $instname=~s/\.$langcode$//; - } - - if (defined $langcode && $langcode ne '') { - $destdir="$tmp/usr/share/man/$langcode/man$realsection/"; - } - $destdir=~tr:/:/:s; # just for looks - my $instpage="$destdir$instname.$section"; + my ($fd, $section); + # See if there is a .TH or .Dt entry in the man page. If so, + # we'll pull the section field from that. + if ($gz) { + $fd = open_gz($page) or die "$page: $!"; + } + else { + open($fd, '<', $page) or die "$page: $!"; + } + while (<$fd>) { + if (/^\.TH\s+\S+\s+"?(\d+[^"\s]*)"?/ || + /^\.Dt\s+\S+\s+(\d+[^\s]*)/) { + $section = $1; + last; + } + } + close($fd); + # Failing that, we can try to get it from the filename. + if (!$section) { + ($section) = $basename =~ m/\.([1-9]\S*)/; + } + + # Now get the numeric component of the section. + my ($realsection) = $section =~ m/^(\d)/ if defined $section; + if (!$realsection) { + error("Could not determine section for $page"); + } + + # Get the man page's name -- everything up to the last dot. + my ($instname) = $basename =~ m/^(.*)\./; + + my $destdir = "$tmp/usr/share/man/man$realsection/"; + my $langcode; + if (!defined $dh{LANGUAGE} || !exists $dh{LANGUAGE}) { + if (not compat(10) and $page =~ m{/man/(?:([a-z][a-z](?:_[A-Z][A-Z])?)(?:\.[^/]+)?)?/man[1-9]/}) { + # If it looks like it was installed in a proper man dir, assume the language + # from that is correct. + $langcode = $1; + } else { + # Translated man pages are typically specified by adding the + # language code to the filename, so detect that and + # redirect to appropriate directory, stripping the code. + ($langcode) = $basename =~ m/\.([a-z][a-z](?:_[A-Z][A-Z])?)\.(?:[1-9]|man)/; + } + } elsif ($dh{LANGUAGE} ne 'C') { + $langcode = $dh{LANGUAGE}; + } + + if (defined $langcode && $langcode ne '') { + # Strip the language code from the instname. + $instname =~ s/\.$langcode$//; + } + + if (defined $langcode && $langcode ne '') { + $destdir = "$tmp/usr/share/man/$langcode/man$realsection/"; + } + $destdir =~ tr:/:/:s; # just for looks + my $instpage = "$destdir$instname.$section"; - next if -l $instpage; - next if compat(5) && -e $instpage; + next if -l $instpage; + next if -e _ && compat(5); - if (! -d $destdir) { install_dir($destdir); + if ($gz) { + doit({ stdout => $instpage }, 'zcat', $page); + } + else { + install_file($page, $instpage); + } } - if ($gz) { - complex_doit "zcat \Q$page\E > \Q$instpage\E"; + + # Now the .so conversion. + @sofiles = @sodests = (); + foreach my $dir (qw{usr/share/man}) { + if (-e "$tmp/$dir") { + find(\&find_so_man, "$tmp/$dir"); + } } - else { - install_file($page, $instpage); + foreach my $sofile (@sofiles) { + my $sodest = shift(@sodests); + rm_files($sofile); + make_symlink_raw_target($sodest, $sofile); } } - # Now the .so conversion. - @sofiles=@sodests=(); - foreach my $dir (qw{usr/share/man}) { - if (-e "$tmp/$dir") { - find(\&find_so_man, "$tmp/$dir"); - } - } - foreach my $sofile (@sofiles) { - my $sodest=shift(@sodests); - doit "rm","-f",$sofile; - doit "ln","-sf",$sodest,$sofile; - } +}); - # Now utf-8 conversion. - if (defined `man --version`) { +# Now utf-8 conversion. +if (defined `man --version`) { + my (@manpages_to_reencode, @issues); + for my $package (@{$dh{DOPACKAGES}}) { + next if is_udeb($package); + my $tmp = tmpdir($package); foreach my $dir (qw{usr/share/man}) { next unless -e "$tmp/$dir"; find(sub { - return if ! -f $_ || -l $_; - my ($tmp, $orig)=($_.".new", $_); - complex_doit "man --recode UTF-8 ./\Q$orig\E > \Q$tmp\E"; - # recode uncompresses compressed pages - doit "rm", "-f", $orig if s/\.(gz|Z)$//; - doit "chmod", 644, $tmp; - doit "mv", "-f", $tmp, $_; - }, "$tmp/$dir"); + return if -l $_ || !-f _; + if ($_ =~ m/\.dh-new$/) { + push(@issues, "${File::Find::dir}/${_}"); + return; + } + push(@manpages_to_reencode, "${File::Find::dir}/${_}"); + }, "$tmp/$dir"); + } + if (@issues) { + warning("Removing temporary manpages from another dh_installman instance"); + rm_files(@issues); + warning("Possibly race-condition detected or left-overs from an interrupted dh_installman (e.g. with ^C)"); + error("Please ensure there are no parallel dh_installman's running (for this pkg) and then re-run dh_installman"); } } + if (@manpages_to_reencode) { + on_items_in_parallel(\@manpages_to_reencode, sub { + for my $manpage (@_) { + my $manpage_tmp = "${manpage}.dh-new"; + my $manpage_cmd = ($manpage =~ m{^/}) ? $manpage : "./${manpage}"; + doit({ stdout => $manpage_tmp }, 'man', '-l', '--recode', 'UTF-8', $manpage_cmd); + # recode uncompresses compressed pages + my $orig = $manpage; + rm_files($orig) if $manpage =~ s/\.(gz|Z)$//; + rename_path($manpage_tmp, $manpage); + } + # Bulk reset permissions of all re-encoded files + xargs(\@_, 'chmod', '0644', '--'); + }); + } +} else { + # Should only occur during debhelper building itself (to avoid a B-D on man-db). + warning("man is not available. Skipping re-encode of UTF-8 manpages") } # Check if a file is a .so man page, for use by File::Find. sub find_so_man { # The -s test is because a .so file tends to be small. We don't want # to open every man page. 1024 is arbitrary. - if (! -f $_ || -s $_ > 1024 || -s == 0) { + if (! -f $_ || -s _ > 1024 || -s _ == 0) { return; } @@ -241,7 +333,7 @@ sub find_so_man { if (! defined $l) { error("failed to read $_"); } - + if ($l=~m/\.so\s+(.*)\s*/) { my $solink=$1; # This test is here to prevent links like ... man8/../man8/foo.8 @@ -255,7 +347,7 @@ sub find_so_man { elsif ($solink =~ m!/!) { $solink="../$solink"; } - + if (-e $solink || -e "$solink.gz") { push @sofiles,"$File::Find::dir/$_"; push @sodests,$solink; @@ -274,9 +366,3 @@ This program is a part of debhelper. Joey Hess <joeyh@debian.org> =cut - -# Local Variables: -# indent-tabs-mode: t -# tab-width: 4 -# cperl-indent-level: 4 -# End: |