use strict;
use Digest::MD5 'md5';
+use File::Find;
# make it clearer when we haven't run to completion, as we can be quite
# noisy when things are working ok
close $fh or die "Can't close $filename: $!";
}
+sub pods_to_install {
+ # manpages not to be installed
+ my %do_not_install = map { ($_ => 1) }
+ qw(Pod::Functions XS::APItest XS::Typemap);
+
+ my (%done, %found);
+
+ File::Find::find({no_chdir=>1,
+ wanted => sub {
+ if (m!/t\z!) {
+ ++$File::Find::prune;
+ return;
+ }
+
+ # $_ is $File::Find::name when using no_chdir
+ return unless m!\.p(?:m|od)\z! && -f $_;
+ return if m!lib/Net/FTP/.+\.pm\z!; # Hi, Graham! :-)
+ # Skip .pm files that have corresponding .pod files
+ return if s!\.pm\z!.pod! && -e $_;
+ s!\.pod\z!!;
+ s!\Alib/!!;
+ s!/!::!g;
+
+ my_die("Duplicate files for $_, '$done{$_}' and '$File::Find::name'")
+ if exists $done{$_};
+ $done{$_} = $File::Find::name;
+
+ return if $do_not_install{$_};
+ return if is_duplicate_pod($File::Find::name);
+ $found{/\A[a-z]/ ? 'PRAGMA' : 'MODULE'}{$_}
+ = $File::Find::name;
+ }}, 'lib');
+ return \%found;
+}
my %state = (
# Don't copy these top level READMEs
sub is_duplicate_pod {
my $file = shift;
+ local $_;
# Initialise the list of possible source files on the first call.
unless (%Lengths) {
__prime_state() unless $state{master};
foreach (@{$state{master}}) {
- next if !$_ || @$_ < 4 || $_->[1] eq $_->[4];
+ next unless $_->[2]{dual};
# This is a dual-life perl*.pod file, which will have be copied
# to lib/ by the build process, and hence also found there.
# These are the only pod files that might become duplicated.
- ++$Lengths{-s $_->[2]};
- ++$MD5s{md5(slurp_or_die($_->[2]))};
+ ++$Lengths{-s $_->[1]};
+ ++$MD5s{md5(slurp_or_die($_->[1]))};
}
}
my @want =
$contents =~ /perldelta - what is new for perl v(5)\.(\d+)\.(\d+)\n/;
die "Can't extract version from $filename" unless @want;
- $state{delta_target} = join '', 'perl', @want, 'delta.pod';
+ my $delta_leaf = join '', 'perl', @want, 'delta';
+ $state{delta_target} = "$delta_leaf.pod";
$state{delta_version} = \@want;
# This way round so that keys can act as a MANIFEST skip list
# with sources being in the same directory.
$state{copies}{$state{delta_target}} = $source;
+ # The default flags if none explicitly set for the current file.
+ my $current_flags = '';
+ my (%flag_set, @paths);
+
+ my $master = open_or_die('pod/perl.pod');
- # process pod.lst
- my $master = open_or_die('pod.lst');
+ while (<$master>) {
+ last if /^=begin buildtoc$/;
+ }
+ die "Can't find '=begin buildtoc':" if eof $master;
+
+ while (<$master>) {
+ next if /^$/ or /^#/;
+ last if /^=end buildtoc/;
+ my ($command, @args) = split ' ';
+ if ($command eq 'flag') {
+ # For the named pods, use these flags, instead of $current_flags
+ my $flags = shift @args;
+ my_die("Malformed flag $flags")
+ unless $flags =~ /\A=([a-z]*)\z/;
+ $flag_set{$_} = $1 foreach @args;
+ } elsif ($command eq 'path') {
+ # If the pod's name matches the regex, prepend the given path.
+ my_die("Malformed path for /$args[0]/")
+ unless @args == 2;
+ push @paths, [qr/\A$args[0]\z/, $args[1]];
+ } elsif ($command eq 'aux') {
+ # The contents of perltoc.pod's "AUXILIARY DOCUMENTATION" section
+ $state{aux} = [sort @args];
+ } else {
+ my_die("Unknown buildtoc command '$command'");
+ }
+ }
foreach (<$master>) {
- next if /^\#/;
-
- # At least one upper case letter somewhere in the first group
- if (/^(\S+)\s(.*)/ && $1 =~ tr/h//) {
- # it's a heading
- my $flags = $1;
- $flags =~ tr/h//d;
- my %flags = (header => 1);
- $flags{toc_omit} = 1 if $flags =~ tr/o//d;
- $flags{aux} = 1 if $flags =~ tr/a//d;
- my_die "Unknown flag found in heading line: $_" if length $flags;
-
- push @{$state{master}}, [\%flags, $2];
- } elsif (/^(\S*)\s+(\S+)\s+(.*)/) {
- # it's a section
- my ($flags, $podname, $desc) = ($1, $2, $3);
- my $filename = "${podname}.pod";
- $filename = "pod/${filename}" if $filename !~ m{/};
-
- my %flags = (indent => 0);
- $flags{indent} = $1 if $flags =~ s/(\d+)//;
+ next if /^$/ or /^#/;
+ next if /^=head2/;
+ last if /^=for buildtoc __END__$/;
+
+ if (my ($action, $flags) = /^=for buildtoc flag ([-+])([a-z]+)/) {
+ if ($action eq '+') {
+ $current_flags .= $flags;
+ } else {
+ my_die("Attempt to unset [$flags] failed - flags are '$current_flags")
+ unless $current_flags =~ s/[\Q$flags\E]//g;
+ }
+ } elsif (my ($leafname, $desc) = /^\s+(\S+)\s+(.*)/) {
+ my $podname = $leafname;
+ my $filename = "pod/$podname.pod";
+ foreach (@paths) {
+ my ($re, $path) = @$_;
+ if ($leafname =~ $re) {
+ $podname = $path . $leafname;
+ $filename = "$podname.pod";
+ last;
+ }
+ }
+
+ # Keep this compatible with pre-5.10
+ my $flags = delete $flag_set{$leafname};
+ $flags = $current_flags unless defined $flags;
+
+ my %flags;
$flags{toc_omit} = 1 if $flags =~ tr/o//d;
- $flags{aux} = 1 if $flags =~ tr/a//d;
- $flags{perlpod_omit} = "$podname.pod" eq $state{delta_target};
+ $flags{dual} = $podname ne $leafname;
$state{generated}{"$podname.pod"}++ if $flags =~ tr/g//d;
$readme =~ s/^perl//;
$state{readmes}{$readme} = $desc;
$flags{readme} = 1;
- } elsif ($flags{aux}) {
- $state{aux}{$podname} = $desc;
} else {
$state{pods}{$podname} = $desc;
}
my_die "Unknown flag found in section line: $_" if length $flags;
- my ($leafname) = $podname =~ m!([^/]+)$!;
push @{$state{master}},
- [\%flags, $podname, $filename, $desc, $leafname];
- } elsif (/^$/) {
- push @{$state{master}}, undef;
+ [$leafname, $filename, \%flags];
+
+ if ($podname eq 'perldelta') {
+ local $" = '.';
+ push @{$state{master}},
+ [$delta_leaf, "pod/$state{delta_target}"];
+ $state{pods}{$delta_leaf} = "Perl changes in version @want";
+ }
+
} else {
- my_die "Malformed line: $_" if $1 =~ tr/A-Z//;
+ my_die("Malformed line: $_");
}
}
- close $master or my_die "close pod.lst: $!";
+ close $master or my_die("close pod/perl.pod: $!");
+ # This has to be special-cased somewhere. Turns out this is cleanest:
+ push @{$state{master}}, ['a2p', 'x2p/a2p.pod', {toc_omit => 1}];
+
+ my_die("perl.pod sets flags for unknown pods: "
+ . join ' ', sort keys %flag_set)
+ if keys %flag_set;
}
sub get_pod_metadata {
my $permit_missing_generated = shift;
# Do they want a consistency report?
my $callback = shift;
+ local $_;
__prime_state() unless $state{master};
return \%state unless $callback;
# Sanity cross check
- my (%disk_pods, %manipods, %manireadmes, %perlpods);
+ my (%disk_pods, %manipods, %manireadmes);
my (%cpanpods, %cpanpods_leaf);
my (%our_pods);
- # These are stub files for deleted documents. We don't want them to show up
- # in perl.pod, they just exist so that if someone types "perldoc perltoot"
- # they get some sort of pointer to the new docs.
- my %ignoredpods
- = map { ( "$_.pod" => 1 ) } qw( perlboot perlbot perltooc perltoot );
+ # There are files that we don't want to list in perl.pod.
+ # Maybe the various stub manpages should be listed there.
+ my %ignoredpods = map { ( "$_.pod" => 1 ) } qw( );
# Convert these to a list of filenames.
++$our_pods{"$_.pod"} foreach keys %{$state{pods}};
foreach (@{$state{master}}) {
- ++$our_pods{"$_->[1].pod"}
- if defined $_ && @$_ == 5 && $_->[0]{readme};
+ ++$our_pods{"$_->[0].pod"}
+ if $_->[2]{readme};
}
opendir my $dh, 'pod';
}
close $mani or my_die "close MANIFEST: $!\n";
- my $perlpod = open_or_die('pod/perl.pod');
- while (<$perlpod>) {
- if (/^For ease of access, /../^\(If you're intending /) {
- if (/^\s+(perl\S*)\s+\w/) {
- ++$perlpods{"$1.pod"};
- }
- }
- }
- close $perlpod or my_die "close perlpod: $!\n";
- my_die "could not find the pod listing of perl.pod\n"
- unless %perlpods;
-
# Are we running before known generated files have been generated?
# (eg in a clean checkout)
my %not_yet_there;
my @inconsistent;
foreach my $i (sort keys %disk_pods) {
push @inconsistent, "$0: $i exists but is unknown by buildtoc\n"
- unless $our_pods{$i};
+ unless $our_pods{$i} || $ignoredpods{$i};
push @inconsistent, "$0: $i exists but is unknown by MANIFEST\n"
if !$BuildFiles{'MANIFEST'} # Ignore if we're rebuilding MANIFEST
&& !$manipods{$i} && !$manireadmes{$i} && !$state{copies}{$i}
&& !$state{generated}{$i} && !$cpanpods{$i};
- push @inconsistent, "$0: $i exists but is unknown by perl.pod\n"
- if !$BuildFiles{'perl.pod'} # Ignore if we're rebuilding perl.pod
- && !$perlpods{$i} && !exists $state{copies}{$i}
- && !$cpanpods{$i} && !$ignoredpods{$i};
}
foreach my $i (sort keys %our_pods) {
push @inconsistent, "$0: $i is known by buildtoc but does not exist\n"
if $state{generated}{$i};
}
}
- unless ($BuildFiles{'perl.pod'}) {
- # Again, ignore these if we're about to rebuild perl.pod
- foreach my $i (sort keys %perlpods) {
- push @inconsistent, "$0: $i is known by perl.pod but does not exist\n"
- unless $disk_pods{$i} or $BuildFiles{$i} or $cpanpods_leaf{$i}
- or $not_yet_there{$i};
- }
- }
&$callback(@inconsistent);
return \%state;
}