13 compare-megalogdirs.pl dir-or-logfile dir-or-logfile
14 compare-megalogdirs.pl glob
22 my @opt = <<'=back' =~ /B<--(\S+)>/g;
30 Only show OK => NOT OK
32 =item B<--debugcolorout!>
34 if colorout-to-dir prg is to be run, call it with -d
42 Skip things that have a line in annotated.txt
46 Compare runtimes, not status. Limit yourself to OK=>OK.
52 Reads two megalog directories and outputs modules with differing
53 status. Instead of directory names also the lognames may be given, in
54 this case the directories will be created if missing.
58 if the --times option is given, outputs times only on OK=>OK pairs.
68 use lib
"$FindBin::Bin/../lib";
73 use CPAN
::DistnameInfo
;
75 use File
::Basename
qw(basename dirname);
76 use File
::Path
qw(mkpath);
80 use Hash
::Util
qw(lock_keys);
81 use List
::MoreUtils
qw(uniq);
86 lock_keys
%Opt, map { /([^\=\!\|]+)/ } @opt;
94 $Opt{annofile
} ||= "/home/k/sources/CPAN/andk-cpan-tools/annotate.txt";
96 my(%anno, %olderanno);
98 my $annofile = $Opt{annofile
};
99 open my $fh, $annofile or die "could not open '$annofile': $!";
101 my($dist,$anno) = /^(\S+)\s+(.*)/;
102 $anno{$dist} = $anno;
104 $anno{$dist} = $anno; # prevent DCONWAY/List-Maker-0.003_000.tar.gz to appear
105 my $stem = $dist; # should we use Distnameinfo?
106 $stem =~ s/-\d[\d\._]*(-TRIAL)?//;
107 $olderanno{$stem} = $dist;
111 my($ldir,$rdir,@rest) = @ARGV;
112 my($lperlref,$rperlref)=(\
my $lperl,\
my $rperl);
114 die "Got more than two arguments: rejecting @rest";
116 if ($ldir && !$rdir && $ldir =~ /\{/) {
117 my($gldir,$grdir,@grest) = glob $ldir;
119 die "Your glob '$ldir' matches more than two: $gldir $grdir; rejecting: @grest";
122 die "Your glob '$ldir' did not match anything, giving up";
125 die "Your glob '$ldir' matched only one thing: $gldir, giving up";
130 unless (defined $rdir){
131 warn "Usage error: Missing second argument\n";
136 if (s/\.(?:log)?$/.d/) { # allow both xxx.log and xxx. instead of xxx.d
139 warn "directory '$dir' exists already, assuming I shall leave it as it is";
142 if ($Opt{debugcolorout
}) {
145 my($name,$path,$suffix) = File
::Basename
::fileparse
($0,".pl");
146 $path .= "colorout-to-dir-3.pl";
147 push @system, $path, "--html", $log;
148 warn "running system[@system]";
149 0==system @system or die "problem running '@system'";
158 for my $tuple (["left",$left,$ldir,$lperlref],
159 ["right",$right,$rdir,$rperlref],
161 my($side,$snap,$dir,$tperlref) = @
$tuple;
162 $superview->{"$side-dir"} = $dir;
163 opendir my $dh, $dir or die "Could not opendir '$dir': $!";
166 DIRENT
: for my $dirent (readdir $dh) {
167 next DIRENT
unless my($author,$distpath) = $dirent =~ /(.+?)!(.+)\.html$/;
169 $distpath =~ s
:!:/:g
;
170 my $dist = basename
($distpath);
171 if ($Opt{skipanno
} and $anno{$dist}) {
174 open my $fh, "$dir/$dirent" or die "could not open $dir/$dirent: $!";
178 LINE
: while (<$fh>) {
179 if (m
|<h2
>Status
:\s
+(.+)</h2
>$|){$status = $1;}
180 elsif (m
|<h2
>Distro
:\s
+(.+)</h2
>$|){$canon1 = $1;}
181 elsif (!$$tperlref and m
|<h2
>Perl
:\s
+.+?
/installed-perls/(.+)</h2
>$|){$$tperlref ||= $1;}
182 elsif (m
|=\s
+(\S
+)\s
+CPU\s
*\
)$|){$cputime = $1;}
184 # 1 wallclock secs ( 0.02 usr 0.00 sys + 0.22 cusr 0.00 csys = 0.24 CPU)
186 last LINE
if $cputime;
188 last LINE
if $status && $canon1;
192 $superview->{"$side-$status"}++;
193 next DIRENT
if $status eq "RESIDUUM";
194 if ($distpath =~ m
|[=']|) {
195 warn "Skipping suspicious file '$distpath' in '$dir'";
198 for ("$author/$distpath") {
200 $canon->{$_} = $canon1;
203 $snap->{$_} = "$status $cputime";
206 $snap->{$_} = $status;
210 $superview->{"$side-perl"} = $$tperlref;
212 die "Alert: NO html files found in '$dir'";
215 my(@miss_left,@miss_right,@diff,@bothok);
217 DISTRO: for my $m (uniq keys %$left, keys %$right) { # $m = "RWSTAUNER/File-Spec-Native-1.003"
218 $c1 = length $m if length $m > $c1;
220 next DISTRO unless $left->{$m} && $left->{$m} =~ /^OK/ && $right->{$m} && $right->{$m} =~ /^OK/;
221 push @bothok, [$m, $left->{$m}, $right->{$m}];
223 if (! exists $right->{$m}) {
224 push @miss_right, [$m, $left->{$m}];
226 } elsif (! exists $left->{$m}) {
227 push @miss_left, [$m, $right->{$m}];
230 next DISTRO if $left->{$m} eq $right->{$m};
231 push @diff, [$m, $left->{$m}, $right->{$m}];
235 # in miss_left and miss_right we now have common distributions that
236 # got upgraded. We postprocess them now because they should be
237 # presented differently.
239 for my $tutu ([left=>\@miss_left],[right=>\@miss_right]) {
240 my($leftright,$miss) = @$tutu;
241 for (my $i = $#$miss;$i>-1;$i--) {
242 my $tuple = $miss->[$i];
243 my $path = sprintf "authors/id/%s/%s/%s.tar.gz", substr($tuple->[0],0,1), substr($tuple->[0],0,2), $tuple->[0];
244 my $d = CPAN::DistnameInfo->new($path);
245 my $dcpanid = $d->cpanid or warn "missing id on path[$path]";
246 my $ddist = $d->dist or warn "missing dist on path[$path]";
247 my $dist = sprintf "%s/%s", $dcpanid, $ddist;
248 $dist{$dist}{$leftright}{arr} = splice @$miss, $i, 1;
249 $dist{$dist}{$leftright}{version} = $d->version;
250 $dist{$dist}{was}{$leftright}{distv} = sprintf("%s/%s", $dcpanid, $d->distvname);
253 for my $dist (keys %dist) {
254 no warnings 'uninitialized
';
255 push @diff, [exists $dist{$dist}{was}{left} ? $dist{$dist}{was}{left}{distv} : $dist,
256 # miss right = have left:
257 "$dist{$dist}{right}{version} $dist{$dist}{right}{arr}[1]",
258 "$dist{$dist}{left}{version} $dist{$dist}{left}{arr}[1]",
265 #warn "Missing right\n";
266 for my $tuple (sort {$a->[0] cmp $b->[0]} @miss_right) {
267 printf "%${c1}s %${c2}s =>\n", @$tuple;
269 #warn "Missing left\n";
270 for my $tuple (sort {$a->[0] cmp $b->[0]} @miss_left) {
271 #while (length $tuple->[0] > $c1) {
272 # (my $trim,$tuple->[0]) = unpack("a" . $c1 . "a*", $tuple->[0]);
275 printf "%${c1}s %${c2}s => %-${c2}s\n", $tuple->[0], "", $tuple->[1];
278 #warn "Diffing left right\n";
279 print YAML::Syck::Dump
287 for my $tuple (sort {lc($base->{$a->[0]}||"") cmp lc($base->{$b->[0]}||"")} @diff) {
290 my $distv = $base->{$tuple->[0]};
291 if ($tuple->[1] =~ /^(OK|.*[^T] OK)$/ and $tuple->[2] =~ /NOT OK$/) {
292 my $bang = $tuple->[0];
294 $matrx = sprintf "http://matrix.cpantesters.org/?dist=%s", $distv;
295 $lpath = sprintf "%s/%s.html", $rdir, $bang;
297 if ($Opt{bbc} && $matrx) {
298 my $path = sprintf "authors/id/%s/%s/%s.tar.gz", substr($tuple->[0],0,1), substr($tuple->[0],0,2), $tuple->[0];
299 my $d = CPAN::DistnameInfo->new($path);
303 $audis = sprintf "%s <= %s", $tuple->[0], $tuple->[3]{right}{arr}[0];
305 $audis = $tuple->[0];
309 canon => $canon->{$tuple->[0]},
315 if ($Opt{skipanno}) {
316 if (my $olderanno = $olderanno{$stem}) {
317 $dump->{olderanno} = $olderanno;
321 print YAML::Syck::Dump($dump);
322 } elsif (!$Opt{bbc}) {
323 printf "%${c1}s %${c2}s => %-${c2}s%s\n", @$tuple, $matrx;
327 print YAML::Syck::Dump({
329 stems=>join(",",map{$D->[$_]{stem}}0..$#$D),
332 for my $tuple (sort {lc($base->{$a->[0]}||"") cmp lc($base->{$b->[0]}||"")} @bothok) {
333 printf "BOTHOK: %${c1}s %${c2}s => %-${c2}s\n", @$tuple;
335 for my $some_ok ("OK", "NOT OK") {
336 for my $lr (qw(left right)) {
337 $superview->{"$lr-either-ok-or-not-ok"} += $superview->{"$lr-$some_ok"};
340 $superview->{summary
} = sprintf "l/r => %.4f, r/l => %.4f",
341 $superview->{"left-either-ok-or-not-ok"}/$superview->{"right-either-ok-or-not-ok"},
342 $superview->{"right-either-ok-or-not-ok"}/$superview->{"left-either-ok-or-not-ok"};
343 print YAML
::Syck
::Dump
($superview);
346 # cperl-indent-level: 4