7 # make it clearer when we haven't run to completion, as we can be quite
8 # noisy when things are working ok
11 print STDERR "$0: ", @_;
12 print STDERR "\n" unless $_[-1] =~ /\n\z/;
13 print STDERR "ABORTED\n";
19 open my $fh, '<', $filename or my_die "Can't open $filename: $!";
25 my $fh = open_or_die($filename);
29 die "Can't read $filename: $!" unless defined $contents and close $fh;
34 my ($filename, $contents) = @_;
35 open my $fh, '>', $filename or die "Can't open $filename for writing: $!";
37 print $fh $contents or die "Can't write to $filename: $!";
38 close $fh or die "Can't close $filename: $!";
42 # manpages not to be installed
43 my %do_not_install = map { ($_ => 1) }
44 qw(Pod::Functions XS::APItest XS::Typemap);
48 File::Find::find({no_chdir=>1,
50 # $_ is $File::Find::name when using no_chdir
51 return unless m!\.p(?:m|od)\z! && -f $_;
52 return if m!(?:^|/)t/!;
53 return if m!lib/Net/FTP/.+\.pm\z!; # Hi, Graham! :-)
54 # Skip .pm files that have corresponding .pod files
55 return if s!\.pm\z!.pod! && -e $_;
60 my_die("Duplicate files for $_, '$done{$_}' and '$File::Find::name'")
62 $done{$_} = $File::Find::name;
64 return if $do_not_install{$_};
65 return if is_duplicate_pod($File::Find::name);
66 $found{/\A[a-z]/ ? 'PRAGMA' : 'MODULE'}{$_}
73 # Don't copy these top level READMEs
83 sub is_duplicate_pod {
86 # Initialise the list of possible source files on the first call.
88 __prime_state() unless $state{master};
89 foreach (@{$state{master}}) {
90 next unless $_->[2]{dual};
91 # This is a dual-life perl*.pod file, which will have be copied
92 # to lib/ by the build process, and hence also found there.
93 # These are the only pod files that might become duplicated.
94 ++$Lengths{-s $_->[1]};
95 ++$MD5s{md5(slurp_or_die($_->[1]))};
99 # We are a file in lib. Are we a duplicate?
100 # Don't bother calculating the MD5 if there's no interesting file of
102 return $Lengths{-s $file} && $MD5s{md5(slurp_or_die($file))};
107 my $source = 'perldelta.pod';
108 my $filename = "pod/$source";
109 my $contents = slurp_or_die($filename);
111 $contents =~ /perldelta - what is new for perl v(5)\.(\d+)\.(\d+)\n/;
112 die "Can't extract version from $filename" unless @want;
113 my $delta_leaf = join '', 'perl', @want, 'delta';
114 $state{delta_target} = "$delta_leaf.pod";
115 $state{delta_version} = \@want;
117 # This way round so that keys can act as a MANIFEST skip list
118 # Targets will always be in the pod directory. Currently we can only cope
119 # with sources being in the same directory.
120 $state{copies}{$state{delta_target}} = $source;
122 # The default flags if none explicitly set for the current file.
123 my $current_flags = '';
124 my (%flag_set, @paths);
126 my $master = open_or_die('pod/perl.pod');
129 last if /^=begin buildtoc$/;
131 die "Can't find '=begin buildtoc':" if eof $master;
134 next if /^$/ or /^#/;
135 last if /^=end buildtoc/;
136 my ($command, @args) = split ' ';
137 if ($command eq 'flag') {
138 # For the named pods, use these flags, instead of $current_flags
139 my $flags = shift @args;
140 my_die("Malformed flag $flags")
141 unless $flags =~ /\A=([a-z]*)\z/;
142 $flag_set{$_} = $1 foreach @args;
143 } elsif ($command eq 'path') {
144 # If the pod's name matches the regex, prepend the given path.
145 my_die("Malformed path for /$args[0]/")
147 push @paths, [qr/\A$args[0]\z/, $args[1]];
148 } elsif ($command eq 'aux') {
149 # The contents of perltoc.pod's "AUXILIARY DOCUMENTATION" section
150 $state{aux} = [sort @args];
152 my_die("Unknown buildtoc command '$command'");
156 foreach (<$master>) {
157 next if /^$/ or /^#/;
159 last if /^=for buildtoc __END__$/;
161 if (my ($action, $flags) = /^=for buildtoc flag ([-+])([a-z]+)/) {
162 if ($action eq '+') {
163 $current_flags .= $flags;
165 my_die("Attempt to unset [$flags] failed - flags are '$current_flags")
166 unless $current_flags =~ s/[\Q$flags\E]//g;
168 } elsif (my ($leafname, $desc) = /^\s+(\S+)\s+(.*)/) {
169 my $podname = $leafname;
170 my $filename = "pod/$podname.pod";
172 my ($re, $path) = @$_;
173 if ($leafname =~ $re) {
174 $podname = $path . $leafname;
175 $filename = "$podname.pod";
180 # Keep this compatible with pre-5.10
181 my $flags = delete $flag_set{$leafname};
182 $flags = $current_flags unless defined $flags;
185 $flags{toc_omit} = 1 if $flags =~ tr/o//d;
186 $flags{dual} = $podname ne $leafname;
188 $state{generated}{"$podname.pod"}++ if $flags =~ tr/g//d;
190 if ($flags =~ tr/r//d) {
191 my $readme = $podname;
192 $readme =~ s/^perl//;
193 $state{readmes}{$readme} = $desc;
196 $state{pods}{$podname} = $desc;
198 my_die "Unknown flag found in section line: $_" if length $flags;
200 push @{$state{master}},
201 [$leafname, $filename, \%flags];
203 if ($podname eq 'perldelta') {
205 push @{$state{master}},
206 [$delta_leaf, "pod/$state{delta_target}"];
207 $state{pods}{$delta_leaf} = "Perl changes in version @want";
211 my_die("Malformed line: $_");
214 close $master or my_die("close pod/perl.pod: $!");
216 my_die("perl.pod sets flags for unknown pods: "
217 . join ' ', sort keys %flag_set)
221 sub get_pod_metadata {
222 # Do we expect to find generated pods on disk?
223 my $permit_missing_generated = shift;
224 # Do they want a consistency report?
225 my $callback = shift;
227 __prime_state() unless $state{master};
228 return \%state unless $callback;
232 foreach my $path (@_) {
233 $path =~ m!([^/]+)$!;
239 my (%disk_pods, %manipods, %manireadmes);
240 my (%cpanpods, %cpanpods_leaf);
243 # These are stub files for deleted documents. We don't want them to show up
244 # in perl.pod, they just exist so that if someone types "perldoc perltoot"
245 # they get some sort of pointer to the new docs.
247 = map { ( "$_.pod" => 1 ) } qw( perlboot perlbot perltooc perltoot );
249 # Convert these to a list of filenames.
250 ++$our_pods{"$_.pod"} foreach keys %{$state{pods}};
251 foreach (@{$state{master}}) {
252 ++$our_pods{"$_->[0].pod"}
256 opendir my $dh, 'pod';
257 while (defined ($_ = readdir $dh)) {
258 next unless /\.pod\z/;
262 # Things we copy from won't be in perl.pod
263 # Things we copy to won't be in MANIFEST
265 my $mani = open_or_die('MANIFEST');
269 if (m!^pod/([^.]+\.pod)!i) {
271 } elsif (m!^README\.(\S+)!i) {
272 next if $state{ignore}{$1};
273 ++$manireadmes{"perl$1.pod"};
274 } elsif (exists $our_pods{$_}) {
277 ++$cpanpods_leaf{$1};
282 close $mani or my_die "close MANIFEST: $!\n";
284 # Are we running before known generated files have been generated?
285 # (eg in a clean checkout)
287 if ($permit_missing_generated) {
288 # If so, don't complain if these files aren't yet in place
289 %not_yet_there = (%manireadmes, %{$state{generated}}, %{$state{copies}})
293 foreach my $i (sort keys %disk_pods) {
294 push @inconsistent, "$0: $i exists but is unknown by buildtoc\n"
295 unless $our_pods{$i};
296 push @inconsistent, "$0: $i exists but is unknown by MANIFEST\n"
297 if !$BuildFiles{'MANIFEST'} # Ignore if we're rebuilding MANIFEST
298 && !$manipods{$i} && !$manireadmes{$i} && !$state{copies}{$i}
299 && !$state{generated}{$i} && !$cpanpods{$i};
301 foreach my $i (sort keys %our_pods) {
302 push @inconsistent, "$0: $i is known by buildtoc but does not exist\n"
303 unless $disk_pods{$i} or $BuildFiles{$i} or $not_yet_there{$i};
305 unless ($BuildFiles{'MANIFEST'}) {
306 # Again, ignore these if we're about to rebuild MANIFEST
307 foreach my $i (sort keys %manipods) {
308 push @inconsistent, "$0: $i is known by MANIFEST but does not exist\n"
309 unless $disk_pods{$i};
310 push @inconsistent, "$0: $i is known by MANIFEST but is marked as generated\n"
311 if $state{generated}{$i};
314 &$callback(@inconsistent);
321 # cperl-indent-level: 4
322 # indent-tabs-mode: nil
325 # ex: set ts=8 sts=4 sw=4 et: