windows-nt/Source/XPSP1/NT/sdktools/debuggers/scripts/symsrvtools/whatsnew.pl
2020-09-26 16:20:57 +08:00

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;