Lines 26-31
Link Here
|
26 |
use File::Basename qw(dirname); |
26 |
use File::Basename qw(dirname); |
27 |
use File::Find; |
27 |
use File::Find; |
28 |
use File::Spec::Functions qw(splitdir catfile); |
28 |
use File::Spec::Functions qw(splitdir catfile); |
|
|
29 |
use Gentoo::Ebuild; |
30 |
|
31 |
my $SORT = { |
32 |
NAME => 1, |
33 |
DATE => 1, |
34 |
TIME => 1, |
35 |
}; |
29 |
|
36 |
|
30 |
my $OPT = { |
37 |
my $OPT = { |
31 |
'verbose' => 0, |
38 |
'verbose' => 0, |
Lines 34-39
Link Here
|
34 |
'colored' => 0, |
41 |
'colored' => 0, |
35 |
'package' => undef, |
42 |
'package' => undef, |
36 |
'logfile' => undef, |
43 |
'logfile' => undef, |
|
|
44 |
'sort' => 'NAME', |
45 |
'sloppy' => 0, |
37 |
}; |
46 |
}; |
38 |
|
47 |
|
39 |
my %COLORS = ( |
48 |
my %COLORS = ( |
Lines 48-69
Link Here
|
48 |
# time format |
57 |
# time format |
49 |
my $TF = "%a %b %e %H:%M:%S %Y"; |
58 |
my $TF = "%a %b %e %H:%M:%S %Y"; |
50 |
|
59 |
|
51 |
# load installed packages |
|
|
52 |
my %INSTALLED = (); |
53 |
find({ 'wanted' => |
54 |
sub { |
55 |
return unless /\.ebuild$/; |
56 |
|
57 |
my $basedir = dirname($File::Find::name); |
58 |
$basedir =~ s/^\/var\/db\/pkg//; |
59 |
my $package = join('/',(splitdir($basedir))[1,2]); |
60 |
|
61 |
$INSTALLED{$package} = 1; |
62 |
|
63 |
}, 'no_chdir' => 1, }, |
64 |
'/var/db/pkg', |
65 |
); |
66 |
|
67 |
# Main Program |
60 |
# Main Program |
68 |
|
61 |
|
69 |
&parse_command_line(); |
62 |
&parse_command_line(); |
Lines 74-122
Link Here
|
74 |
# Colored output? I think not! |
67 |
# Colored output? I think not! |
75 |
$ENV{'ANSI_COLORS_DISABLED'} = 1 unless $OPT->{'colored'}; |
68 |
$ENV{'ANSI_COLORS_DISABLED'} = 1 unless $OPT->{'colored'}; |
76 |
|
69 |
|
77 |
my $rawlog = &fetch_portage_log($OPT->{'logfile'}); |
70 |
my $rawlog = &fetch_portage_log($OPT->{'logfile'}); |
78 |
my $parsed = &parse_portage_log($rawlog); |
71 |
my $parsed = &parse_portage_log($rawlog); |
79 |
my $emerge = &fetch_emerge_info($parsed,$OPT->{'package'}); |
72 |
my $emerge = &fetch_emerge_info($parsed,$OPT->{'package'}); |
80 |
|
73 |
my $result = []; |
81 |
my $summary = { |
74 |
my $longest = 0; |
82 |
'emerges' => 0, |
75 |
my $slowest = 0; |
83 |
'duration' => 0, |
76 |
my $sum_dur = 0; |
84 |
'first' => undef, |
77 |
foreach my $package (keys %{&fetch_emerge_info($parsed,$OPT->{'package'}) || {}}) |
85 |
'last' => undef, |
78 |
{ |
86 |
}; |
79 |
my @times = @{$emerge->{$package}}; |
|
|
80 |
while ( my ($start,$end) = splice(@times,0,2) ) |
81 |
{ |
82 |
push @$result, { |
83 |
ebuild => Gentoo::Ebuild->create($package), |
84 |
start => $start, |
85 |
end => $end, |
86 |
}; |
87 |
|
88 |
$longest = ( |
89 |
$longest, length($package) |
90 |
)[$longest < length($package)]; |
91 |
|
92 |
$slowest = ( |
93 |
$slowest, length( int( ( $end - $start ) / 3600 ) ) |
94 |
)[$slowest < length( int( ( $end - $start ) / 3600 ) )]; |
95 |
|
96 |
$sum_dur += ( $end - $start ); |
97 |
} |
98 |
} |
99 |
undef $emerge; |
100 |
|
87 |
|
101 |
|
88 |
my $count = keys %$emerge; |
102 |
my $count = @$result; |
89 |
if( $count == 0 ) |
103 |
if( $count == 0 ) |
90 |
{ |
104 |
{ |
91 |
die "!!! Package not found '$OPT->{'package'}'\n"; |
105 |
die "!!! Package not found '$OPT->{'package'}'\n"; |
92 |
} |
106 |
} |
93 |
|
107 |
|
|
|
108 |
|
109 |
# determin sort method |
110 |
my $sort_code=sub{ 1 }; |
111 |
unless( $OPT->{summary} ) |
112 |
{ |
113 |
if( $OPT->{sort} eq 'NAME' ) |
114 |
{ |
115 |
$sort_code = sub{ |
116 |
$a->{ebuild} cmp $b->{ebuild} || |
117 |
$a->{start} <=> $b->{start} |
118 |
}; |
119 |
} |
120 |
elsif( $OPT->{sort} eq 'DATE' ) |
121 |
{ |
122 |
$sort_code = sub{ |
123 |
$a->{start} <=> $b->{start} |
124 |
}; |
125 |
} |
126 |
else |
127 |
{ |
128 |
$sort_code = sub{ |
129 |
$a->{end}-$a->{start} <=> $b->{end}-$b->{start} || |
130 |
$a->{ebuild} cmp $b->{ebuild} || |
131 |
$a->{start} <=> $b->{start} |
132 |
}; |
133 |
} |
134 |
} |
135 |
|
136 |
|
94 |
# foreach package that was matched |
137 |
# foreach package that was matched |
95 |
foreach my $package (sort keys %$emerge) |
138 |
my $prev_package = Gentoo::Ebuild->new; |
|
|
139 |
foreach my $info (sort $sort_code @$result) |
96 |
{ |
140 |
{ |
|
|
141 |
my ($package,$start,$end) = @{$info}{qw(ebuild start end)}; |
142 |
|
97 |
# print out the package name |
143 |
# print out the package name |
98 |
unless( $OPT->{'summary'} ) |
144 |
if( !$OPT->{'summary'} ) |
99 |
{ |
145 |
{ |
100 |
print colored( " * $package\n", &pkgcolor($package) ); |
146 |
if( $OPT->{sloppy} ) |
101 |
print "\n"; |
147 |
{ |
|
|
148 |
print colored( |
149 |
sprintf( "%-${longest}s", $package ), |
150 |
&pkgcolor($package) |
151 |
); |
152 |
print " "; |
153 |
} |
154 |
else |
155 |
{ |
156 |
if( $package ne $prev_package ) |
157 |
{ |
158 |
print colored( " * $package\n", &pkgcolor($package) ); |
159 |
print "\n"; |
160 |
} |
161 |
} |
102 |
} |
162 |
} |
103 |
|
163 |
|
104 |
# print out the build information for each one |
164 |
# print out the build information for each one |
105 |
my @times = @{$emerge->{$package}}; |
165 |
my $duration = ($end-$start); |
106 |
while ( my ($start,$end) = splice(@times,0,2) ) |
|
|
107 |
{ |
108 |
my $duration = ($end-$start); |
109 |
|
166 |
|
110 |
if( $duration < 0 ) |
167 |
if( $duration < 0 ) |
|
|
168 |
{ |
169 |
$duration = 0; |
170 |
if( $OPT->{'verbose'} ) |
111 |
{ |
171 |
{ |
112 |
$duration = 0; |
172 |
warn "*** Invalid timestamp for $package\n"; |
113 |
if( $OPT->{'verbose'} ) |
|
|
114 |
{ |
115 |
warn "*** Invalid timestamp for $package\n"; |
116 |
} |
117 |
} |
173 |
} |
|
|
174 |
} |
118 |
|
175 |
|
119 |
unless( $OPT->{'summary'} ) |
176 |
unless( $OPT->{'summary'} ) |
|
|
177 |
{ |
178 |
if( $OPT->{sloppy} ) |
179 |
{ |
180 |
print colored( |
181 |
sprintf( |
182 |
"%${slowest}d:%02d:%02d(%s)\n", |
183 |
$duration / 3600, |
184 |
$duration / 60 % 60, |
185 |
$duration % 60, |
186 |
scalar localtime $start, |
187 |
), |
188 |
$duration>($sum_dur/@$result)*4 |
189 |
? 'red' |
190 |
: $duration<($sum_dur/@$result)/4 |
191 |
? 'green' |
192 |
: 'yellow' |
193 |
); |
194 |
} |
195 |
else |
120 |
{ |
196 |
{ |
121 |
# standard output |
197 |
# standard output |
122 |
print "\tEmerged at: ", |
198 |
print "\tEmerged at: ", |
Lines 129-170
Link Here
|
129 |
$COLORS{'duration'} ), |
205 |
$COLORS{'duration'} ), |
130 |
"\n"; |
206 |
"\n"; |
131 |
} |
207 |
} |
132 |
|
|
|
133 |
# summary information |
134 |
$summary->{'emerges'}++; |
135 |
$summary->{'duration'} += $duration; |
136 |
|
137 |
if( !defined($summary->{'first'}) || |
138 |
$start < $summary->{'first'}->{'start'} ) |
139 |
{ |
140 |
$summary->{'first'} = { |
141 |
'name' => $package, |
142 |
'start' => $start, |
143 |
'end' => $end, |
144 |
}; |
145 |
} |
146 |
|
147 |
if( !defined($summary->{'last'}) || |
148 |
$end > $summary->{'last'}->{'end'} ) |
149 |
{ |
150 |
$summary->{'last'} = { |
151 |
'name' => $package, |
152 |
'start' => $start, |
153 |
'end' => $end, |
154 |
}; |
155 |
} |
156 |
# end summary info |
157 |
|
158 |
unless( $OPT->{'summary'} ) |
159 |
{ |
160 |
print "\n" if @times; |
161 |
} |
162 |
} |
208 |
} |
163 |
|
209 |
|
164 |
unless( $OPT->{'summary'} ) |
210 |
if( !$OPT->{'summary'} && !$OPT->{'sloppy'} ) |
165 |
{ |
211 |
{ |
166 |
print "\n"; |
212 |
print "\n"; |
167 |
} |
213 |
} |
|
|
214 |
|
215 |
$prev_package = $package; |
168 |
} |
216 |
} |
169 |
|
217 |
|
170 |
# output the summary |
218 |
# output the summary |
Lines 174-181
Link Here
|
174 |
print "\n"; |
222 |
print "\n"; |
175 |
my $of = "\t%-14s %s\n"; |
223 |
my $of = "\t%-14s %s\n"; |
176 |
|
224 |
|
177 |
my $emerges = $summary->{'emerges'}; |
225 |
my $emerges = @$result; |
178 |
my $duration = $summary->{'duration'}; |
226 |
my $duration = $sum_dur; |
179 |
my $average = int($duration/$emerges); |
227 |
my $average = int($duration/$emerges); |
180 |
|
228 |
|
181 |
printf( $of, "Total Builds:", |
229 |
printf( $of, "Total Builds:", |
Lines 192-200
Link Here
|
192 |
|
240 |
|
193 |
print "\n"; |
241 |
print "\n"; |
194 |
|
242 |
|
195 |
my $first = $summary->{'first'}; |
243 |
my ($first,$last) = (sort { $a->{start} <=> $b->{start} } @$result)[0,-1]; |
|
|
244 |
|
196 |
printf( $of, "First Build:", |
245 |
printf( $of, "First Build:", |
197 |
colored( $first->{'name'}, &pkgcolor($first->{'name'}) ) |
246 |
colored( "$first->{'ebuild'}", &pkgcolor($first->{'ebuild'}) ) |
198 |
); |
247 |
); |
199 |
printf( $of, "", "(" . |
248 |
printf( $of, "", "(" . |
200 |
colored( strftime($TF,localtime($first->{'start'})), |
249 |
colored( strftime($TF,localtime($first->{'start'})), |
Lines 203-213
Link Here
|
203 |
|
252 |
|
204 |
print "\n"; |
253 |
print "\n"; |
205 |
|
254 |
|
206 |
if( $summary->{'emerges'} > 1 ) |
255 |
if( $emerges > 1 ) |
207 |
{ |
256 |
{ |
208 |
my $last = $summary->{'last'}; |
|
|
209 |
printf( $of, "Last Build:", |
257 |
printf( $of, "Last Build:", |
210 |
colored( $last->{'name'}, &pkgcolor($last->{'name'}) ) |
258 |
colored( "$last->{'ebuild'}", &pkgcolor($last->{'ebuild'}) ) |
211 |
); |
259 |
); |
212 |
printf( $of, "", "(" . |
260 |
printf( $of, "", "(" . |
213 |
colored( strftime($TF,localtime($last->{'end'})), |
261 |
colored( strftime($TF,localtime($last->{'end'})), |
Lines 226-232
Link Here
|
226 |
{ |
274 |
{ |
227 |
my $package = shift; |
275 |
my $package = shift; |
228 |
|
276 |
|
229 |
return exists $INSTALLED{$package} |
277 |
return $package->installed |
230 |
? $COLORS{'pkg_install'} |
278 |
? $COLORS{'pkg_install'} |
231 |
: $COLORS{'pkg_normal'}; |
279 |
: $COLORS{'pkg_normal'}; |
232 |
} |
280 |
} |
Lines 247-256
Link Here
|
247 |
'help|h|?' => \$OPT->{'gethelp'}, |
295 |
'help|h|?' => \$OPT->{'gethelp'}, |
248 |
'package|p=s'=> \$OPT->{'package'}, |
296 |
'package|p=s'=> \$OPT->{'package'}, |
249 |
'logfile|l=s'=> \$OPT->{'logfile'}, |
297 |
'logfile|l=s'=> \$OPT->{'logfile'}, |
|
|
298 |
'sort|o=s' => \$OPT->{'sort'}, |
299 |
'sloppy!' => \$OPT->{'sloppy'}, |
300 |
'y!' => \$OPT->{'sloppy'}, |
250 |
) or pod2usage(2); |
301 |
) or pod2usage(2); |
251 |
|
302 |
|
252 |
pod2usage(1) if $OPT->{'gethelp'}; |
303 |
pod2usage(1) if $OPT->{'gethelp'}; |
253 |
|
304 |
|
|
|
305 |
pod2usage(1) unless exists $SORT->{$OPT->{'sort'}}; |
306 |
|
254 |
if( !defined($OPT->{'package'}) && !defined($ARGV[0]) ) |
307 |
if( !defined($OPT->{'package'}) && !defined($ARGV[0]) ) |
255 |
{ |
308 |
{ |
256 |
pod2usage(1); |
309 |
pod2usage(1); |
Lines 482-493
Link Here
|
482 |
splat [options] [--package] package |
535 |
splat [options] [--package] package |
483 |
|
536 |
|
484 |
Options: |
537 |
Options: |
485 |
--help -? -h brief help message |
538 |
--help -? -h brief help message |
486 |
--verbose -v print extra warnings during parsing |
539 |
--verbose -v print extra warnings during parsing |
487 |
--summary -s print a summary line instead of full info |
540 |
--sloppy -y display in sloppy mode(one package in a line) |
488 |
--logfile -l use specified logfile as emerge log |
541 |
--summary -s print a summary line instead of full info |
489 |
--colored -c output with colors |
542 |
--logfile -l use specified logfile as emerge log |
490 |
--package -p a package name to match. can be a partial package |
543 |
--colored -c output with colors |
|
|
544 |
--sort -o sort output |
545 |
--sort=NAME sort by package name(default) |
546 |
--sort=DATE sort by date emerged at |
547 |
--sort=TIME sort by build time |
548 |
--package -p a package name to match. can be a partial package |
491 |
name (ie 'evo'), in which case it will match any |
549 |
name (ie 'evo'), in which case it will match any |
492 |
package that starts with 'evo'. you can also |
550 |
package that starts with 'evo'. you can also |
493 |
include the category (ie 'net-www/evo') |
551 |
include the category (ie 'net-www/evo') |