13 bin/snapshotflattener.pl ~sand/megalog/megalog-9999-99-99T99:99:99.log
15 bin/snapshotflattener.pl ~sand/megalog/megalog-9999-99-99T99:99:99.
23 my @opt = <<'=back' =~ /B<--(\S+)>/g;
29 =item B<--showfirstrequirer|sfr!>
31 Spits out a YAML structure showing in which file we have a requirer,
32 the name of that one, and the names of the dependencies that are not
33 already listed in from of him. Implies --dry-run and an unlimited
42 Defaults to 0. If given, we limit the number of candidates to process by
43 randomly kicking out candidates.
47 Defaults to 12, so we get the top 12 reported. If the value is 0, we
48 just get the old output which showed us whenever we had a new
49 highscore (something quite useless which we considered good enough for
56 We rank all modules that trigger a "requires" line, that is all
57 modules that are not yet installed when they are suddenly needed as a
58 dependency. This ranking is called RANKIN. We rank these modules again
59 according to the relative lines they occupy in the Bundle/Snapshot
60 files. We call this ranking RANKOUT. For the record: we rank them by
61 module name, not by line number. (???)
63 Finally we calculate the maximum diff between RANKIN and RANKOUT. If
64 the diff is e.g. 700, we can say: we should move this module past 700
65 *ranked* modules. In reality this may mean a movement of thousands of
70 Iff all modules were in perfect linear order to satisfy all
71 dependencies, we could easily read the time it takes to build one
72 module. *And* we could easily rebalance the 5 snapshotfiles when one
73 of them goes over the well established max of 10 hours.
75 I came to this when trying to run C<megalog-overview.pl --debug=reps>
76 which turned out to be buggy.
82 use lib
"$FindBin::Bin/../lib";
88 use File
::Basename
qw(dirname);
89 use File
::Path
qw(mkpath);
94 use Hash
::Util
qw(lock_keys);
97 lock_keys
%Opt, map { /([^=|!]+)/ } @opt;
106 if ($Opt{showfirstrequirer
}) {
107 $Opt{top
} = 999999999;
112 my $megalog = shift or pod2usage
(1);
113 $megalog =~ s/\.$/.log/;
114 my @snaps = glob("lib/Bundle/Snapshot_2011_10_21_0?.pm");
129 $INSTATE{contents
}=0;
130 open my $fh, $megalog or die;
132 if (/\s(\S+)\s+\[(\S*requires)\]/) {
134 unless (exists $RANKIN{$1}) {
135 $RANKIN{$1} = 1 + scalar keys %RANKIN;
137 $FIRSTREQUIRER{$1} ||= $REQUIRER;
138 $IN_FILE{$1} ||= $FILE;
140 } elsif (/Running install for module\s+'([A-Za-z0-9\:]+)'/) {
142 } elsif (/^path\|-> Bundle::\S+([0-9][0-9])\s*$/) {
147 while (keys %CANDIDATES > $Opt{maxcand
}){
148 my @c = keys %CANDIDATES;
149 my $r = $c[rand $#c];
150 delete $CANDIDATES{$r};
155 for my $snap (@snaps) {
157 my $out_file = substr($snap,-5,2);
158 if ($Opt{"dry-run"}) {
159 open $fh, $snap or die "Could not open $snap: $!";
161 rename $snap, "$snap~" or die "Could not rename $snap: $!";
162 open $fh, "$snap~" or die "Could not open $snap~: $!";
163 open $fh2, ">", $snap or die "Could not open >$snap: $!";
170 if (/^=head1 CONTENTS/){
171 $INSTATE{contents
}=1;
172 unless ($Opt{"dry-run"}) {
177 $INSTATE{contents
}=0;
178 if (/^=head1 CONFIGU/){
179 unless ($Opt{"dry-run"}) {
180 print ((shift @SHIFTLINES)->[0]) while @SHIFTLINES;
185 if ($INSTATE{contents
}){
186 if (/^([A-Za-z]\S*)/){
188 $BUNDLELINE{$1} ||= $bundleline;
189 if ($CANDIDATES{$1}){
190 $RANKOUT{$1} = 1 + scalar keys %RANKOUT;
191 $OUT_FILE{$1} = $out_file;
192 unshift @SHIFTLINES, [$_, $1];
194 push @SHIFTLINES, [$_, $1];
196 if (@SHIFTLINES > 1){
197 my $line = (shift @SHIFTLINES)->[0];
199 unless ($Opt{"dry-run"}) {
205 $SHIFTLINES[-1][0] .= "\n" unless $SHIFTLINES[-1][0] =~ /\n/;
207 push @SHIFTLINES, [""];
211 unless ($Opt{"dry-run"}) {
217 my $max = { diff
=> -99999 };
220 for my $k (sort keys %CANDIDATES) {
221 unless ($RANKOUT{$k}){
222 $RANKOUT{$k} = 1 + scalar keys %RANKOUT;
224 my $diff = $RANKOUT{$k} - $RANKIN{$k};
226 push @all, { diff
=>$RANKOUT{$k}-$RANKIN{$k}, in=>$RANKIN{$k}, out
=>$RANKOUT{$k}, name
=>$k, reqdby
=>$FIRSTREQUIRER{$k}, infile
=>$IN_FILE{$k}, outfile
=>$OUT_FILE{$k}||"--", reqtype
=>$REQTYPE{$k}, bundleline
=>$BUNDLELINE{$k}||=0 };
228 if ($diff > $max->{diff
}) {
229 $max->{diff
} = $diff;
230 $max->{in} = $RANKIN{$k};
231 $max->{out
} = $RANKOUT{$k};
233 next if $max->{diff
} < 0;
234 warn "Note: so far largest distance with $max->{k}: $max->{out} - $max->{in} = $max->{diff}\n";
241 $rec->{bundleline_reqdby
} = $BUNDLELINE{$rec->{reqdby
}};
242 $rec->{reqtype_short
} = substr($rec->{reqtype
},0,1);
244 my $showfirstrequirer = {};
245 for my $rec (sort { $a->{bundleline_reqdby
} <=> $b->{bundleline_reqdby
}
246 || $a->{bundleline
} <=> $b->{bundleline
}
248 next if $BUNDLELINE{$rec->{name
}} < $BUNDLELINE{$rec->{reqdby
}};
249 if ($Opt{showfirstrequirer
}) {
250 $showfirstrequirer->{bfile
} ||= $rec->{infile
};
251 $showfirstrequirer->{name
} ||= $rec->{reqdby
};
252 if ($rec->{reqdby
} ne $showfirstrequirer->{name
}) {
253 print YAML
::Dump
($showfirstrequirer);
256 $showfirstrequirer->{line
} = $rec->{bundleline_reqdby
};
257 my $a = $showfirstrequirer->{deps
} ||= [];
258 push @
$a, $rec->{name
};
261 printf "%5d %-58s %s %5d %5d %s %s %s\n", @
{$rec}{qw
/diff name reqtype_short bundleline bundleline_reqdby outfile infile reqdby/};
262 push @reported, $rec->{name
};
263 last if @reported >= $Opt{top
};
266 my $show_maybe_try = 0;
267 if ($show_maybe_try) {
268 warn sprintf "Maybe try:
269 egrep -n '^(%s)(\$| )' lib/Bundle/Snapshot_2011_10_21_0*.pm
270 ", join("|", @reported);
271 warn sprintf "And/Or:
272 egrep -an ' (%s) *\\[.*requi|^perl\\|' %s
273 ", join("|", @reported), $megalog;
274 warn sprintf "And/Or:
275 egrep -an ' \\S+ *\\[.*requi|^perl\\||Running install for module' %s|egrep -B2 ' (%s) '
276 ", $megalog, join("|", @reported), ;
281 # cperl-indent-level: 4