417 lines
11 KiB
Perl
417 lines
11 KiB
Perl
|
package WhatsNew;
|
||
|
|
||
|
use Getp;
|
||
|
|
||
|
($Alias, $BinRoot, $BinPattern, $SymPattern, $PriSymPattern, $CommentPattern, $AliasList, $BinList, $HELP, $Powerless, $FullAlias) = ();
|
||
|
|
||
|
my $AliasFileFormat =
|
||
|
"<Alias>,\\s+<BinRoot>,\\s+<BinPattern>,\\s+<SymPattern>,\\s+<PriSymPattern>,\\s+<CommentPattern>";
|
||
|
|
||
|
my $BinFileFormat =
|
||
|
"<Bin>,\\s+<Symbols>,\\s+<PriSymbols>,\\s+<FileCounter>,\\s+<LatestTime>,\\s+<TotalTime>,\\s+<Revision>,\\s+<BinRoot>,\\s+<Comment>";
|
||
|
|
||
|
my (@Aliases, @AliasItems, @BinItems) = ();
|
||
|
my (%ArgHash, %AliasHash, %BinHash) = ();
|
||
|
my (@Pieces, @NameSpace, %NameValue) = ();
|
||
|
my ($tBinRoot, $tBinPattern, $tSymPattern, $tPriSymPattern, $tComment);
|
||
|
(@AliasItemNames) = $AliasFileFormat =~ /\<(\w+)\>/g;
|
||
|
|
||
|
sub Main {
|
||
|
|
||
|
my (@Bins, $comment);
|
||
|
|
||
|
open(LOG, ">test.log");
|
||
|
&LoadAliasHash($AliasList);
|
||
|
&LoadBinHash($BinList);
|
||
|
|
||
|
@Aliases = &StoreAlias($Alias);
|
||
|
|
||
|
for $Alias (@Aliases) {
|
||
|
@Bins = &FindBins($Alias);
|
||
|
|
||
|
for $tBin (@Bins) {
|
||
|
$_ = &QuickCheck($tBin);
|
||
|
if (/NETWORK/ || /SKIP/) {
|
||
|
next;
|
||
|
}
|
||
|
if (/DELETE/) {
|
||
|
# system("symstore del /i id /s $tBin");
|
||
|
}
|
||
|
if (/CHECK/) {
|
||
|
$comment = ("$BinHash{$tBin}->{Comment}" ne "")?"/c $BinHash{$tBin}->{Comment}":"";
|
||
|
$IndexFile = $tBin;
|
||
|
$IndexFile =~ s/\_/\___/g; # _=>___
|
||
|
$IndexFile =~ s/\\/\_/g;
|
||
|
|
||
|
print $_ . "\n";
|
||
|
print "Check Bin - $tBin\n";
|
||
|
next if (defined $Powerless);
|
||
|
|
||
|
$BinHash{$tBin}->{Revision}++;
|
||
|
print("Symstore add /a /p /r /f $tBin /g $BinHash{$tBin}->{BinRoot} /x index\\${IndexFile}.${BinHash{$tBin}->{Revision}}.bin $comment");
|
||
|
system("symstore add /a /p /r /f $tBin /g $BinHash{$tBin}->{BinRoot} /x index\\${IndexFile}.${BinHash{$tBin}->{Revision}}.bin $comment");
|
||
|
system("symstore add /a /p /r /f $BinHash{$tBin}->{Symbols} /g $BinHash{$tBin}->{BinRoot} /x index\\${IndexFile}.${BinHash{$tBin}->{Revision}}.sym $comment") if (defined $BinHash{$tBin}->{Symbols});
|
||
|
system("symstore add /a /p /r /f $BinHash{$tBin}->{PriSymbols} /g $BinHash{$tBin}->{BinRoot} /x index\\${IndexFile}.${BinHash{$tBin}->{Revision}}.pri $comment") if (defined $BinHash{$tBin}->{PriSymbols});
|
||
|
}
|
||
|
&UpdateTotal($tBin);
|
||
|
}
|
||
|
|
||
|
&SaveBinHash($BinList) if (defined $Powerless);
|
||
|
&SaveAliasHash($AliasList) if (defined $Powerless);
|
||
|
}
|
||
|
close(LOG);
|
||
|
}
|
||
|
|
||
|
sub FindBins {
|
||
|
($tAlias) = @_;
|
||
|
|
||
|
my (@Bins, $tBin);
|
||
|
my ($BinRoot, $BinPattern, $SymPattern, $PriSymPattern, $CommentPattern) =
|
||
|
map({$AliasHash{$tAlias}->{$_}} @AliasItemNames[1..$#AliasItemNames]);
|
||
|
|
||
|
$BinPattern = $BinRoot . "\\" . $BinPattern;
|
||
|
$SymPattern = $BinRoot . "\\" . $SymPattern if (defined $SymPattern);
|
||
|
$PriSymPattern = $BinRoot . "\\" . $PriSymPattern if (defined $PriSymPattern);
|
||
|
|
||
|
@Bins = &FindPattern($BinRoot, $BinPattern, $SymPattern, $PriSymPattern, $CommentPattern);
|
||
|
|
||
|
return @Bins;
|
||
|
}
|
||
|
|
||
|
sub FindPattern {
|
||
|
($tBinRoot, $tBinPattern, $tSymPattern, $tPriSymPattern, $tComment) = @_;
|
||
|
|
||
|
my (@Names, $namepattern);
|
||
|
|
||
|
my (%Checked, @RetResult)=();
|
||
|
|
||
|
my ($i, $path)=(0);
|
||
|
|
||
|
# @NameSpace = [$Name, $pattern];
|
||
|
|
||
|
(@Names) = $tBinPattern=~/\#([^\#]+)\#/g;
|
||
|
|
||
|
for $namepattern (@Names) {
|
||
|
$namepattern =~ /([^\:]+)(?:\:(.+))?/;
|
||
|
my ($name, $pattern) = ($1, $2);
|
||
|
$pattern = ".+" if (!defined $pattern);
|
||
|
$NameSpace[$i]=[$name, $pattern];
|
||
|
$NameValue{$name}="";
|
||
|
$i++;
|
||
|
}
|
||
|
|
||
|
@Pieces = split(/\#[^\#]+\#/, $tBinPattern); # No support for recursive parenthesis
|
||
|
|
||
|
return &RecDir(1, $Pieces[0]);
|
||
|
}
|
||
|
|
||
|
sub RecDir {
|
||
|
my ($i, $path) = @_;
|
||
|
|
||
|
my (@ret, $mypath, @paths);
|
||
|
|
||
|
if ($i == (scalar @Pieces)) {
|
||
|
if (-d $path) {
|
||
|
$BinHash{$path}->{Symbols} = &Evaluate($tSymPattern, \%NameValue);
|
||
|
$BinHash{$path}->{PriSymbols} = &Evaluate($tPriSymPattern, \%NameValue);
|
||
|
$BinHash{$path}->{FileCounter} = 0 if (!defined $BinHash{$path}->{FileCounter});
|
||
|
$BinHash{$path}->{LatestTime} = 0 if (!defined $BinHash{$path}->{LatestTime});
|
||
|
$BinHash{$path}->{TotalTime} = 0 if (!defined $BinHash{$path}->{TotalTime});
|
||
|
$BinHash{$path}->{Revision} = 0 if (!defined $BinHash{$path}->{Revision});
|
||
|
$BinHash{$path}->{BinRoot} = $tBinRoot;
|
||
|
$BinHash{$path}->{Comment} = &Evaluate($tComment, \%NameValue);
|
||
|
|
||
|
return $path;
|
||
|
} else {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
opendir(DIR, $path);
|
||
|
@paths = map({/\w+/?$path . $_:()} readdir(DIR));
|
||
|
closedir(DIR);
|
||
|
for $mypath (@paths) {
|
||
|
if ((-d $mypath) &&
|
||
|
(substr($mypath,length($path)) =~ /^$NameSpace[$i-1][1]$/i)) {
|
||
|
|
||
|
$NameValue{$NameSpace[$i-1][0]} = substr($mypath, length($path));
|
||
|
|
||
|
push @ret, &RecDir($i + 1, $mypath . $Pieces[$i]);
|
||
|
}
|
||
|
}
|
||
|
return @ret;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub Evaluate {
|
||
|
my ($path, $hNameValue) = @_;
|
||
|
$path=~s/\#([^\#]+)(?:\:[^\#]+)?\#/$hNameValue->{$1}/ge;
|
||
|
return $path;
|
||
|
}
|
||
|
|
||
|
sub QuickCheck {
|
||
|
my ($Bin) = @_;
|
||
|
|
||
|
my $hInfo = $BinHash{$Bin};
|
||
|
|
||
|
my ($myTotalTime, $myFCtr, $myfile, $myTime)=(0,0,"");
|
||
|
|
||
|
my ($yy, $mm, $dd, $hh, $mn, $ss);
|
||
|
|
||
|
open(F, "dir /s /b /a-d /o-d $Bin|") or return "NETWORK";
|
||
|
|
||
|
$myfile = <F>;
|
||
|
chomp $myfile;
|
||
|
$myTotalTime = (lstat($myfile))[9];
|
||
|
$myFCtr=1;
|
||
|
|
||
|
($yy, $mm, $dd, $hh, $mn, $ss) = (localtime($mytotalTime))[5,4,3,2,1,0];
|
||
|
printf LOG ("C: %s, %04d/%02d/%02d %02d:%02d:%02d\n", $myfile, $yy+1900, $mm+1, $dd, $hh, $mn, $ss);
|
||
|
|
||
|
return "DELETE" if ($myfile !~ /\S/);
|
||
|
return "CHECK 1 - $myTotalTime $hInfo->{LatestTime}" if ($myTotalTime != $hInfo->{LatestTime});
|
||
|
|
||
|
while (<F>) {
|
||
|
chomp;
|
||
|
$myFCtr++;
|
||
|
$myTotalTime += $myTime = (lstat($_))[9];
|
||
|
($yy, $mm, $dd, $hh, $mn, $ss) = (localtime($myTime))[5,4,3,2,1,0];
|
||
|
printf LOG ("C: %s, %04d/%02d/%02d %02d:%02d:%02d\n", $_, $yy+1900, $mm+1, $dd, $hh, $mn, $ss);
|
||
|
if ($myTotalTime > $hInfo->{TotalTime}) {
|
||
|
return "CHECK 2 - $myTotalTime, $hInfo->{TotalTime}";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
close(F);
|
||
|
|
||
|
(($hInfo->{TotalTime}==$myTotalTime) && ($hInfo->{FileCounter}==$myFCtr))?"SKIP":"CHECK 3 - $hInfo->{TotalTime}, $myTotalTime, $hInfo->{FileCounter}, $myFCtr";
|
||
|
}
|
||
|
|
||
|
sub StoreAlias {
|
||
|
my ($tAlias)=@_;
|
||
|
|
||
|
return keys %AliasHash if (defined $FullAlias);
|
||
|
|
||
|
if ($tAlias=~/\,/) {
|
||
|
# Store the new alias into %TargetAlias
|
||
|
$AliasHash{$tAlias} = {
|
||
|
BinRoot => $BinRoot,
|
||
|
BinPattern => $BinPattern,
|
||
|
SymPattern => $SymPattern,
|
||
|
PriSymPattern => $PriSymPattern,
|
||
|
CommentPattern => $CommentPattern
|
||
|
} if (defined $BinRoot);
|
||
|
return $tAlias;
|
||
|
} else {
|
||
|
return split(/\,/, $tAlias);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub UpdateTotal {
|
||
|
my ($tBin)=@_;
|
||
|
|
||
|
my ($tFileCounter, $tLatestTime, $tTotalTime) = (0, 0, 0);
|
||
|
my ($myfile, $myTime);
|
||
|
my ($yy, $mm, $dd, $hh, $mn, $ss);
|
||
|
|
||
|
open(F, "dir /s /b /a-d /o-d $tBin|") or return "NETWORK";
|
||
|
|
||
|
$myfile = <F>;
|
||
|
chomp $myfile;
|
||
|
$tTotalTime = $tLatestTime = (lstat($myfile))[9];
|
||
|
$tFileCounter++;
|
||
|
|
||
|
($yy, $mm, $dd, $hh, $mn, $ss) = (localtime($tTotalTime))[5,4,3,2,1,0];
|
||
|
printf LOG ("U: %s, %04d/%02d/%02d %02d:%02d:%02d\n", $myfile, $yy+1900, $mm+1, $dd, $hh, $mn, $ss);
|
||
|
|
||
|
while(<F>) {
|
||
|
chomp;
|
||
|
$tTotalTime += $myTime = (lstat($_))[9];
|
||
|
$tFileCounter++;
|
||
|
($yy, $mm, $dd, $hh, $mn, $ss) = (localtime($myTime))[5,4,3,2,1,0];
|
||
|
printf LOG ("U: %s, %04d/%02d/%02d %02d:%02d:%02d\n", $_, $yy+1900, $mm+1, $dd, $hh, $mn, $ss);
|
||
|
}
|
||
|
|
||
|
$BinHash{$tBin}->{FileCounter} = $tFileCounter;
|
||
|
$BinHash{$tBin}->{LatestTime} = $tLatestTime;
|
||
|
$BinHash{$tBin}->{TotalTime} = $tTotalTime;
|
||
|
close(F);
|
||
|
}
|
||
|
|
||
|
sub LoadBinHash {
|
||
|
my ($FileName) = @_;
|
||
|
|
||
|
&LoadFileToHash($FileName, \%BinHash, $BinFileFormat);
|
||
|
}
|
||
|
|
||
|
sub SaveBinHash {
|
||
|
my ($FileName) = @_;
|
||
|
|
||
|
&SaveHashToFile($FileName, \%BinHash, $BinFileFormat);
|
||
|
}
|
||
|
|
||
|
sub LoadAliasHash {
|
||
|
my ($FileName) = @_;
|
||
|
|
||
|
&LoadFileToHash($FileName, \%AliasHash, $AliasFileFormat);
|
||
|
|
||
|
}
|
||
|
|
||
|
sub SaveAliasHash {
|
||
|
my ($FileName) = @_;
|
||
|
|
||
|
&SaveHashToFile($FileName, \%AliasHash, $AliasFileFormat);
|
||
|
|
||
|
}
|
||
|
|
||
|
sub LoadFileToHash {
|
||
|
my ($FileName, $refHash, $HashFormat) = @_;
|
||
|
local $_;
|
||
|
|
||
|
my ($Key1, $Pattern, @Keys2, @Values2)=();
|
||
|
|
||
|
$KeyNames = $HashFormat;
|
||
|
(@Keys2) = $HashFormat =~ /\<(\w+)\>/g;
|
||
|
|
||
|
shift @Keys2; # Remove the first level hash key name
|
||
|
|
||
|
$Pattern = $HashFormat;
|
||
|
$Pattern =~ s/\<\w+\>/\(\\S+\)/g;
|
||
|
|
||
|
open(F, $FileName);
|
||
|
while(<F>) {
|
||
|
chomp;
|
||
|
(@Values)=/$Pattern/;
|
||
|
$Key1 = shift @Values;
|
||
|
map({ my ($key2, $value) = ($_, shift @Values);
|
||
|
$refHash->{$Key1}->{$key2} = ($value eq "-")?undef:$value;
|
||
|
} @Keys2);
|
||
|
}
|
||
|
close(F);
|
||
|
|
||
|
}
|
||
|
|
||
|
sub SaveHashToFile {
|
||
|
my ($FileName, $refHash, $HashFormat) = @_;
|
||
|
local $_;
|
||
|
|
||
|
my (%formlength, $myFormat, $ctr, $ctr_old);
|
||
|
my ($Key1, $Pattern, @Keys2, @Values2)=();
|
||
|
|
||
|
$KeyNames = $HashFormat;
|
||
|
(@Keys2) = $HashFormat =~ /\<(\w+)\>/g;
|
||
|
|
||
|
map({$formlength{$_}=length($_)} @Keys2);
|
||
|
|
||
|
for $Key1 (keys %$refHash) {
|
||
|
next if($Key1 eq '');
|
||
|
$formlength{$Keys2[0]} = length($Key1)
|
||
|
if($formlength{$Keys2[0]} < length($Key1));
|
||
|
for $Key2 (keys %{$refHash->{$Key1}}) {
|
||
|
$formlength{$Key2} = length($refHash->{$Key1}->{$Key2})
|
||
|
if($formlength{$Key2} < length($refHash->{$Key1}->{$Key2}));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$Format = $HashFormat;
|
||
|
$Format =~ s/\<(\w+)\>/\%s/g;
|
||
|
|
||
|
open(F, ">" . $FileName);
|
||
|
for $Key1 (sort keys %$refHash) {
|
||
|
$refHash->{$Key1}->{$Keys2[0]}=$Key1;
|
||
|
@Values2 = map({(defined $refHash->{$Key1}->{$_})?$refHash->{$Key1}->{$_}:"-"} @Keys2);
|
||
|
$myFormat = $Format;
|
||
|
$ctr_old = $spaces = 0;
|
||
|
while ($myFormat=~/\\s\+/) {
|
||
|
my($pre, $match, $post) = ($`, $&, $');
|
||
|
$ctr = 0;
|
||
|
map({$ctr++;} ($pre=~/\%/g));
|
||
|
splice(@Values2, $ctr, 0, " ");
|
||
|
$myFormat = $pre .
|
||
|
"\%" .
|
||
|
sprintf("%d", &AdjustSpace( \%formlength, $refHash, $Key1, \@Keys2, $ctr_old, $ctr - $spaces)+1 ) .
|
||
|
"s" .
|
||
|
$post;
|
||
|
$ctr_old=$ctr - $spaces;
|
||
|
$spaces++;
|
||
|
}
|
||
|
printf F ($myFormat, @Values2);
|
||
|
print F "\n";
|
||
|
}
|
||
|
close(F);
|
||
|
|
||
|
}
|
||
|
|
||
|
sub AdjustSpace {
|
||
|
my ($formlengthptr, $refHash, $Key1, $refKeys2, $i, $j) = @_;
|
||
|
my $sum=0;
|
||
|
map({
|
||
|
if (defined $refHash->{$Key1}->{$_}) {
|
||
|
$sum+=$formlengthptr->{$_} - length($refHash->{$Key1}->{$_});
|
||
|
} else {
|
||
|
$sum+=$formlengthptr->{$_} - 1;
|
||
|
}
|
||
|
} @$refKeys2[$i..$j-1]);
|
||
|
return $sum;
|
||
|
}
|
||
|
|
||
|
sub ParseArgument {
|
||
|
|
||
|
my @unsolve = Getp::GetParams(
|
||
|
-o => "a: f r: b: s: p: c: l: i: z " .
|
||
|
"alias>a root>r bin>b sym>s pri>p cmt>c alist>l blist>b",
|
||
|
-h => \%ArgHash,
|
||
|
-p => "Alias FullAlias BinRoot BinPattern SymPattern PriSymPattern CommentPattern AliasList BinList Powerless",
|
||
|
@ARGV
|
||
|
);
|
||
|
print "Error: Unsolve argument: $Getp::_UNSOLVE\n" if defined ($Getp::_UNSOLVE);
|
||
|
if ($Getp::HELP eq 1) {
|
||
|
&Usage;
|
||
|
exit(1);
|
||
|
}
|
||
|
if (!defined $AliasList) {
|
||
|
$AliasList = "AliasList.txt";
|
||
|
}
|
||
|
if (!defined $BinList) {
|
||
|
$BinList = "BinList.txt";
|
||
|
}
|
||
|
if ((!defined $Alias) && (!defined $FullAlias)) {
|
||
|
&Usage;
|
||
|
print "Please defined either -a:<alias> or -f\n";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub Usage {
|
||
|
print <<USAGE;
|
||
|
$0 - Find What is new in the tree
|
||
|
------------------------------------------------------
|
||
|
Syntax:
|
||
|
$0 -a[lias]:<alias>
|
||
|
[-r[oot]:<root> -b[in]:<bin> -s[ym]:<sym> -p[ri]:<pri> -c[mt]:<cmt>]
|
||
|
[-<l|alist>:<alist>] [-<i|blist>:<blist>] [-z]
|
||
|
|
||
|
|
||
|
Parameters:
|
||
|
alias - The project name or any alias. Such as SP2
|
||
|
root - The root path. Such as \\\\winseqfe\\release\\w2k\\sp2
|
||
|
bin - The binary path.
|
||
|
Such as \#buildnum:[\\d\^|\\.]+\#\\\#lang\#\\x86\\\#frechk:fre\^|chk\#\\stf\\binaries
|
||
|
sym - The symbols path. Such as \#buildnum\#\\\#lang\#\\x86\\\#frechk\#\\sym
|
||
|
pri - The private symbols. Such as \#buildnum\#\\\#lang\#\\x86\\\#frechk\#\\sym
|
||
|
cmt - The comment. Such as, Windows SP2 build \#buildnum\#
|
||
|
alist - The filename of the AliasList. Such as aliaslist.txt (default)
|
||
|
blist - The filename of the BinList. Such as binlist.txt. (default)
|
||
|
|
||
|
Options:
|
||
|
-z - powerless
|
||
|
|
||
|
USAGE
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (eval("\$0=~/" . __PACKAGE__ . "\\.pl\$/i")) {
|
||
|
&ParseArgument;
|
||
|
&Main;
|
||
|
}
|
||
|
|
||
|
1;
|