#!/usr/bin/perl =head1 NAME pkg-time - Show how long time it took to emerge packages. =head1 DESCRIPTION This script shows how long time it took to emerge packages by parsing the log file (typically /var/log/emerge.log). You can sort result by package name, emerged date or time took to emerge. Type pkg-time -h for detail. =cut package Gentoo::Ebuild; use strict; use overload '""' => \&as_string, 'cmp' => \&compare ; #------------------------------------------------------------------------------# sub create{ my $class=shift; my $ebuild=shift; if($ebuild=~/ ^ (\w+-\w+) # group \/ ([\w+-]+) # package - ([\d\.]+(?:[a-zA-Z])?)? # version _? (?:(alpha|beta|pre|rc|p)(\d+)?)? # suffix (?:-r([\d\.]+))? # revision $ /x ){ return Gentoo::Ebuild->new( group => defined $1 ? $1 : '', package => defined $2 ? $2 : '', version => defined $3 ? $3 : '', suffix1 => defined $4 ? $4 : '', suffix2 => defined $5 ? $5 : '', revision => defined $6 ? $6 : '', ); } } #------------------------------------------------------------------------------# sub new{ my $class=shift; my $self=bless { group => undef, package => undef, version => undef, suffix1 => undef, suffix2 => undef, revision => undef, @_, },$class; return $self; } #------------------------------------------------------------------------------# sub as_string{ my $self=shift; return sprintf '%s/%s-%s%s%s%s', $self->{group}, $self->{package}, $self->{version}, $self->{suffix1} ? '_' . $self->{suffix1} : '', $self->{suffix2}, $self->{revision} ? '-r' . $self->{revision} : '', ; } #------------------------------------------------------------------------------# sub _split_version{ my $version=shift; if($version=~/^([\d\.]+)([a-zA-Z])?$/){ return [split(/\./,$1)], $2 || '' ; } } sub _compare_version{ my($a,$b)=@_; my($digits_a,$alphabet_a)=_split_version($a->{version}); my($digits_b,$alphabet_b)=_split_version($b->{version}); my $compare_length=( scalar(@{$digits_a}),scalar(@{$digits_b}) )[scalar(@{$digits_a})[$i]<=>$digits_b->[$i]; return $result if $result; } return $alphabet_a cmp $alphabet_b; } #------------------------------------------------------------------------------# my %SUFFIXES=( alpha => 0, beta => 1, pre => 2, rc => 3, '' => 4, p => 5, ); sub _compare_suffix{ my($a,$b)=@_; return $SUFFIXES{$a->{suffix1}} <=> $SUFFIXES{$b->{suffix1}} || ($a->{suffix2} || 0) <=> ($b->{suffix2} || 0) ; } sub compare{ my($a,$b)=@_; return $a->{group} cmp $b->{group} || $a->{package} cmp $b->{package} || _compare_version($a,$b) || _compare_suffix($a,$b) || ($a->{revision} || 0) <=> ($b->{revision} || 0) ; } #------------------------------------------------------------------------------# #------------------------------------------------------------------------------# package main; use strict; use Getopt::Std; my %opts; my $LOG_FILE='/var/log/emerge.log'; my $VERSION ='0.10'; #------------------------------------------------------------------------------# sub usage{ print <<_; Usage : pkg-time [-h] [-i LOG_FILE] [-l] [-o p|d|t] [PATTERN] -h Print this help. -i Use LOG_FILE instead of ${LOG_FILE} -l Last installed ebuild only. -o p Sort by package name(default). -o d Sort by emerged date. -o t Sort by time took emerging. PATTERN Show only ebuilds matched . _ exit; } sub time2hms{ my $time=shift; return ( $time/3600, $time/60%60, $time%60, ); } #------------------------------------------------------------------------------# $opts{o}='p'; getopts('o:i:hl',\%opts) || usage; $opts{h} && usage; exists $opts{o} && $opts{o}!~/^[pdt]$/ && usage; my $pattern=shift; #------------------------------------------------------------------------------# my @results; #------------------------------------------------------------------------------# my $current_ebuild; my $time_begins; my $time_ends; my $ebuild_length=0; my $max_time =0; open(LOG,'< ' . ($opts{i} || $LOG_FILE)) or die 'File not found.'; while(){ if(/(\d+):[\s>]+emerge \(\d+ of \d+\) (.+?) to \//){ $current_ebuild=$2; $time_begins =$1; if(defined $pattern && $current_ebuild!~/$pattern/o){ $current_ebuild=undef; next; } } if( defined $current_ebuild && /(\d+):[\s:]+completed emerge \(\d+ of \d+\) $current_ebuild to \// ){ $time_ends=$1; next if defined $pattern && $current_ebuild!~/$pattern/o; push @results, { ebuild => Gentoo::Ebuild->create($current_ebuild), time_took => $time_ends-$time_begins, emerged_time => $time_begins, }; $ebuild_length=( length($current_ebuild),$ebuild_length )[length($current_ebuild)<$ebuild_length]; $max_time=( $time_ends-$time_begins,$max_time )[$time_ends-$time_begins<$max_time]; } } close(LOG); #------------------------------------------------------------------------------# unless(@results){ print "No match!\n"; exit; } #------------------------------------------------------------------------------# if($opts{l}){ my %seen; @results=grep{!$seen{$_->{ebuild}}++}@results; } #------------------------------------------------------------------------------# my $sort_code; if($opts{o} eq 'd'){ $sort_code=sub{ $a->{emerged_time} <=> $b->{emerged_time} }; }elsif($opts{o} eq 't'){ $sort_code=sub{ $a->{time_took} <=> $b->{time_took} }; }else{ $sort_code=sub{ $a->{ebuild} cmp $b->{ebuild} || $a->{emerged_time} <=> $b->{emerged_time} }; } my $total_time=0; my $h_len =length(int((time2hms($max_time))[0])); foreach(sort $sort_code @results){ printf( "%-${ebuild_length}s : %${h_len}d:%02d:%02d(%s)\n", $_->{ebuild}, time2hms($_->{time_took}), scalar localtime $_->{emerged_time} ); $total_time+=$_->{time_took}; } #------------------------------------------------------------------------------# $h_len=length(int((time2hms($total_time))[0])); print "\n"; printf "Average time : %${h_len}d:%02d:%02d\n", time2hms($total_time/@results); printf "Total time : %${h_len}d:%02d:%02d\n", time2hms($total_time); #------------------------------------------------------------------------------# =head1 LICENSE GNU GPL v2 =head1 AUTHOR Yoshiaki Hagihara =cut