|
|
# Filename: sendbuildstats.pl # # Have any changes to this file reviewed by DavePr, BryanT, or WadeLa # before checking in. # Any changes need to verified in all standard build/rebuild scenarios. #
require $ENV{'sdxroot'} . '\TOOLS\sendmsg.pl';
# # Globals #
$BuildMachinesRelPathname = "TOOLS\\BuildMachines.txt"; $BuildMachinesFile = $ENV{ "RazzleToolPath" } . "\\BuildMachines.txt"; $SdDotMapPathname = "sd.map";
# # Usage variables # $PGM='SendBuildStats:';
$Usage = "\n" . 'Usage: SendBuildStats [-v] [-o | -t] -s | -w | -fb[:build.err] | -fpb[:pberr]' . " [-m msg]\n". "\n". " -? | -help help\n". " -v | -verbose verbose\n". " -o | -only send only to suspect list\n". " -t | -too put suspect list on To: line, DL on CC:\n". " -s | -success build success\n". " -w | -warn send out warning\n". " -fb[:fname] | -buildfailure build failed, fname is the build.err file\n". " -fpb[:fname] | -postbuildfailure post build failed\, fname is the postbuild.err file\n". " -f fname name of error file (i.e. build.err, postbuild.err)\n". " -m msg rest of line is a message to include in the mail\n";
# # debug routine for printing out variables # sub pvar { for (@_) { print "\$$_ = $$_\n"; } }
# # signal catcher (at least this would work on unix) # sub catch_ctrlc { printf $LogHandle "$PGM Aborted.\n" if $LogHandle; die "$PGM Aborted.\n"; }
$SIG{INT} = \&catch_ctrlc;
# # Get the current directory # open CWD, 'cd 2>&1|'; $CurrDir = <CWD>; close CWD; chomp $CurrDir;
$CurrDrive = substr($CurrDir, 0, 2);
# # Check variables expected to be set in the environment. # $sdxroot = $ENV{'SDXROOT'} or die $PGM, "SDXROOT not set in environment\n"; $MyComputername = $ENV{'COMPUTERNAME'} or die $PGM, "COMPUTERNAME not set in environment\n"; $MyBuildArch = $ENV{'_BuildArch'} or die $PGM, "_BuildArch not set in environment\n"; $MyBuildType = $ENV{'_BuildType'} or die $PGM, "_BuildType not set in environment\n"; $MyBranch = $ENV{'_BuildBranch'} or die $PGM, "_BuildBranch not set in environment\n"; $BuildDotChanges = $ENV{'sdxroot'} . '\build.changes'; $BuildDotChangedFiles = $ENV{'sdxroot'} . '\build.changedfiles'; $BuildDateFile = $ENV{'sdxroot'} . '\__blddate__'; $BuildMailMsg = $ENV{'BuildMailMsg'}; $BuildNumberFile = $ENV{'sdxroot'} . '\__bldnum__';
# # Initialize variables # $Success = 0; # only one of these gets set $Warn = 0; $BuildFailed = 0; $PostBuildFailed = 0;
$Fail = 0; # set if either BuildFailed or PostBuildFailed
$ErrorFile = 0; # will hold the name of the build.err file
$Fake = 0; # fake output flag $Verbose = 0; # verbose output flag
$SuspectsOnly = 0; # flag to send mail only to the suspect list. $SuspectsToo = 0; # flag to send mail to the suspect list and CC everyone else.
$BuildDate = ""; # set on first call to ReadBuildDate() $BuildNumber = ""; # set on first call to ReadBuildNumber()
# # Determine if this machine is an Official Build machine or not # $OfficialBuildMachine = $ENV{'OFFICIAL_BUILD_MACHINE'};
if (!$BuildMailMsg) { if ($OfficialBuildMachine) { $BuildMailMsg = "Official Build"; } else { $BuildMailMsg = "Private Build"; } }
$BuildCategory = "Unknown"; $BuildCategory = "Private" if $BuildMailMsg =~ /priv/i; $BuildCategory = "OFFICIAL" if $BuildMailMsg =~ /official/i; $BuildCategory = "MiniLoop" if $BuildMailMsg =~ /mini/i;
$SpecialMsg = 0;
# # Get Complete Build Number if possible # $CompleteBuildNumber = ReadBuildNumber() . "\.$MyBuildArch$MyBuildType\.$MyBranch\." . ReadBuildDate();
# # process arguments # for (@ARGV) { if ($SpecialMsg) { $SpecialMsg .= " $_"; next; }
if (/^-m$/i or /^-msg$/i or /^-message$/i) { $SpecialMsg = "***"; next; }
if ($GetFname) { $fname = $_; $GetFname = 0; next; }
if (/^-fake$/i) { $Fake++; next; }
if (/^-v$/i or /^-verbose$/i) { $Verbose++; next; }
if (/^-t$/i or /^-too$/) { $SuspectsToo++; next; }
if (/^-o$/i or /^-only$/) { $SuspectsOnly++; next; }
if (/^-s$/i or /^-success$/i or /^-successful$/i) { $Success++; next; }
if (/^-w$/i or /^-warn$/i) { $Warn++; next; }
if (/^-f$/i) { $GetFname = 1; next; }
if (/^-fb(:.*)?$/i or /^-buildfailure(:.*)?$/i) { $BuildFailed++; $Fail++; if ($1) { $ErrorFile = $1; $ErrorFile =~ s/://; $SetErrFile++; } else { $ErrorFile = $ENV{'sdxroot'} . '\build.err'; } next; }
if (/^-fpb(:.*)?$/i or /^-postbuildfailure(:.*)?$/i) { $PostBuildFailed++; $Fail++; if ($1) { $ErrorFile = $1; $ErrorFile =~ s/://; $SetErrFile++; } else { if ( -e $ENV{'_NTTREE'} . '\build_logs\postbuild.err') { $ErrorFile = $ENV{'_NTTREE'} . '\build_logs\postbuild.err'; } else { $ErrorFile = '\\\\' . $MyComputername . '\latest\build_logs\postbuild.err'; } } next; }
if (/^-?$/i or /^-help$/) { print $Usage; exit 0; }
die $Usage; }
$SpecialMsg .= " ***\n" if $SpecialMsg;
# # Sanity Check arguments # pvar Success, Warn, BuildFailed, ErrorFile, PostBuildFailed, fname, SetErrFile, SuspectsOnly if $Verbose;
die $Usage unless $Success + $Warn + $BuildFailed + $PostBuildFailed == 1; die $Usage unless $SuspectsOnly + $SuspectsToo <= 1; die $Usage if $fname and $SetErrFile;
$ErrorFile = $fname if $fname;
# # Compute MyDl, BuildChanges, Changers, and Suspects # Will use to decide the recipients to send Message To # SetMyDl(); GetChangersAndSuspects();
# # Generate the appropriate build message. # $BuildMail = FormatBuildMailStart(); $PrivateBuild = ($BuildCategory =~ /private/i);
if ($Success) {
# # Build was successful, so format a successful build message, and # send success build mail # #$BuildMailSubject = "Build Succeeded: $MyBuildArch$MyBuildType $CompleteBuildNumber"; $BuildMailSubject = "BUILD $MyComputername/$MyBranch: $BuildCategory $BuildDate $MyBuildArch$MyBuildType SUCCEEDED";
if ($PrivateBuild) { $BuildMail .= "Build is available on $ENV{'_NTTREE'}\n"; } else { $BuildMail .= "Build is available on \\\\$MyComputername\\latest\n" . "\nChanges for this build include\n\n\n" . $BuildChanges; }
} elsif ($Warn) { # # We are sending a warning message. # $BuildMailSubject = "BUILD $MyComputername/$MyBranch: $BuildCategory $BuildDate $MyBuildArch$MyBuildType warning";
} elsif ($BuildFailed) { # # Build failed, so format either a build.exe failure email and log data, # #$BuildMailSubject = "Build Failed: $MyBuildArch$MyBuildType $CompleteBuildNumber"; $BuildMailSubject = "BUILD $MyComputername/$MyBranch: $BuildCategory $BuildDate $MyBuildArch$MyBuildType FAILED";
$BuildMail .= "These failures occurred:\n\n\n" . $BuildErrs . "\n"; $BuildMail .= "\nChanges for this build include\n\n\n" . $BuildChanges unless $PrivateBuild;
} else { # $PostBuildFailed # # or a postbuild failure email and log data # #$BuildMailSubject = "Build Failed (PostBuild): $MyBuildArch$MyBuildType $CompleteBuildNumber"; $BuildMailSubject = "BUILD $MyComputername/$MyBranch: $BuildCategory $BuildDate $MyBuildArch$MyBuildType FAILED - POSTBUILD";
$BuildMail .= "PostBuild Failure:\n\n\n" . ReadPostBuildErrors();
$BuildMail .= $PostBuildErrorContents if $PostBuildErrorContents;
$BuildMail .= "\nChanges for this build include\n\n\n" . $BuildChanges unless $PrivateBuild; }
pvar BuildMailSubject,MyDl,MyComputername,MyBuildArch,MyBuildType if $Verbose; print $BuildMail if $Verbose;
if ($PrivateBuild) { @MailTargets = (split /;/, $MyDl);
} elsif ($SuspectsOnly and scalar @Suspects) { @MailTargets = @Suspects;
} elsif ($SuspectsToo and scalar @Suspects) { @MailTargets = ((map {"CC:$_"} split /;/, $MyDl), @Suspects);
} elsif (scalar @Changers) { @MailTargets = ((map {"CC:$_"} split /;/, $MyDl), @Changers);
} else { @MailTargets = (split /;/, $MyDl); }
($FromAddr) = split /;/, $MyDl;
if ($Fake) { print "sendmsg parameters:\n"; for ('-v', $FromAddr."DisableOof", $BuildMailSubject, $BuildMail, @MailTargets) { print "<<$_>>"; } print "\n";
} else { # # Really send the message # $rc = sendmsg ('-v', $FromAddr."DisableOof", $BuildMailSubject, $BuildMail, @MailTargets); print "WARNING: sendmsg failed!\n" if $rc; }
exit 0;
## ## Support Subroutine Section ##
# # Set MyDl. # For official build machines, extract this from BuildMachines.txt, # otherwise use _NT_BUILD_DL, USERNAME, or the script maintainer -- in that order. # sub SetMyDl {
if ($OfficialBuildMachine) {
$fname = $BuildMachinesFile; open BMFILE, $fname or die "Could not open: $fname\n"; for (<BMFILE>) { s/\s+//g; s/;.*$//; next if /^$/;
my($vblmach, $vblprime, $vblbranch, $vblarch, $vbldbgtype, $vbldl, $disttype ) = split /,/;
# # The BuildMachines.txt record is keyed by computername, architecture, type, and branch #
if ( ($vblmach =~ /\Q$MyComputername\E/io) && ($vblarch =~ /\Q$MyBuildArch\E/io) && ($vbldbgtype =~ /\Q$MyBuildType\E/io) && ($vblbranch =~ /\Q$MyBranch\E/io) ) {
close BMFILE;
$MyPrime = $vblprime; $MyDl = $vbldl; return; } } printf $PGM . "Problem Encounterd. $MyComputername was NOT found in buildmachines.txt. dl defaults to DavePr\n"; $MyDl = "DavePr"; close BMFILE;
} else { $MyDl = $ENV{'_NT_BUILD_DL'}; if (!$MyDl) { $MyDl = $ENV{'USERNAME'} or $MyDl = "DavePr"; } } }
# # Construct the base message used in the various cases. # sub FormatBuildMailStart { my($msg); my($BuildDate); my($MacroName);
if ($Success) { $msg = "Build Was Successful\n\n";
} elsif ($Warn) { $msg = "Build early-warning message\n\n";
} elsif ($BuildFailed) { $msg = "Build errors were found\n\n";
} else { # $PostBuildFailed $msg = "Postbuild errors were found\n\n"; }
if (scalar @Suspects) { $msg .= "SUSPECTS:"; for (@Suspects) { $msg .= " $_"; } $msg .= "\n\n"; }
$msg .= $BuildMailMsg . "\n" if $BuildMailMsg; $msg .= $SpecialMsg . "\n" if $SpecialMsg;
$msg .= "\nBuild Name : $CompleteBuildNumber\n"; $msg .= "\nBuild Date : " . ReadBuildDate() . "\n";
$msg .= "Build Machine: $MyComputername\n"; $msg .= "Architecture : $MyBuildArch\n"; $msg .= "DbgType : $MyBuildType\n"; $msg .= "Branch : $MyBranch\n"; $msg .= "SdxRoot : $sdxroot\n"; $msg .= "DL Notified : $MyDl\n"; $msg .= "\n\n";
return $msg; }
# # Canonicalize the prefix of a build path so we can make guesses about who # might have caused a build error based on who made changes to what. # sub CanonicalizeBuildPath { $_ = @_[0];
s/\\[^\\]+$//; # remove filename s/\\obj[^\\]*\\.*//i; # ignore OBJ directories
s/\\daytona\\.*//i; # ignore common sub-directories ( s/\\i386\\.*//i; s/\\amd64\\.*//i; s/\\ia64\\.*//i; s/\\daytona\\.*//i; s/\\i386\\.*//i; s/\\amd64\\.*//i; s/\\ia64\\.*//i;
s/^[a-z]:\\[^\\]+\\//i; # remove sdxroot
# remove last directory component -- if we have at least three s/\\[^\\]+$// if 3 <= split /\\/;
return $_; }
# # As build error file is read, we are called to record the canonicalized paths found. # sub CaptureBuildFailure { $_ = @_[0]; chomp;
$capture = "";
if (/NMAKE/) { if (/U1073/) { s/'$//; s/.*//; $capture = $_; } } else { s/[ (].*//; s/^[0-9]*>//; $capture = $_; }
if ($capture) { $capture = CanonicalizeBuildPath $capture; $BuildFailure{$capture}++; } }
# # Set $BuildChanges, $BuildErrs, @Changers, and @Suspects -- as appropriate. # sub GetChangersAndSuspects {
$BuildChanges = ""; $BuildErrs = ""; @Changers = (); @Suspects = ();
# # If this was a build failure, process ErrorFile # if ($BuildFailed) { my($rc) = open FD, $ErrorFile or warn $ErrorFile, ": ", $!, "\n"; if ($rc) { for (<FD>) { $BuildErrs .= $_; CaptureBuildFailure($_); } close FD; } else { $BuildErrs = "Sorry, unable to locate $ErrorFile\n"; } }
# # Get the Changers and record the BuildChanges for use in the BuildMail. # my($rcc) = open FD, $BuildDotChanges or warn $BuildDotChanges, ": ", $!, "\n"; if ($rcc) { %Checklist=();
for (<FD>) { $BuildChanges .= $_;
next unless /^Change /;
chop; s/'.*$//; s/.* by //; s/@.*//; s/.*\\//; tr/A-Z/a-z/;
$Checklist{$_}++; } close FD;
@Changers = sort keys %Checklist;
} else { $BuildChanges = "Sorry, unable to locate $BuildDotChanges\n"; }
# # Get the Suspects # if ($BuildFailed) { my($project, $change, $dev, $date, $time, $sdpath, $type); $rcc = open FD, $BuildDotChangedFiles or warn $BuildDotChangedFiles, ": ", $!, "\n"; if ($rcc) { %Checklist=(); for (<FD>) { my($project, $change, $dev, $date, $time, $sdpath, $type) = split; next unless $type; $_ = $sdpath; s|#.*||; # strip #change s|//depot/[^/]*/||i; # strip //depot/lab tr|/|\\|; # / -> \ $canonpath = CanonicalizeBuildPath $_; next unless $BuildFailure{$canonpath}; print "Suspect $dev because of change $change affecting $canonpath\n" if $Verbose and not $Pinged{$change}; $Pinged{$change}++; $Checklist{$dev}++; } close FD; @Suspects = sort keys %Checklist; } } }
# # Return the contents of the ErrorFile file. # sub ReadPostBuildErrors { my($pbcontents) = ""; my(@errfiles) = ();
$PostBuildErrorContents = ""; # global
$rc = open FD, $ErrorFile; return "Sorry, unable to locate $ErrorFile\n" unless $rc;
for (<FD>) { $pbcontents .= $_; if (/\ssee:?\s+(\S+)/i) { $foo = $1; $foo =~ s/\.$//; push @errfiles, $foo; } } close FD;
for (@errfiles) { $rc = open FD, $_; if (not $rc) { $PostBuildErrorContents .= "\nUnable to open $_: $!\n"; next; }
$PostBuildErrorContents .= "\nContents of $_\n"; for (<FD>) { $PostBuildErrorContents .= $_; } close FD; $PostBuildErrorContents .= "\n"; }
return $pbcontents; }
# # Set BuildDate from the contents of the BuildDate file and return it. # sub ReadBuildDate { my($rc, $mname, $bd);
return $BuildDate if $BuildDate;
$BuildDate = "UnknownBuildDate";
$rc = open FD, $BuildDateFile or warn $BuildDateFile, ": ", $!, "\n"; return $BuildDate unless $rc;
for (<FD>) { chomp; ($mname, $bd) = split /=/; $BuildDate = $bd if $mname =~ /BUILDDATE/i; } close FD;
return $BuildDate; }
# # Set BuildDate from the contents of the BuildDate file and return it. # sub ReadBuildNumber { my($rc, $mname, $bn);
return $BuildNumber if $BuildNumber;
$BuildNumber = "UnknownBuildNumber";
$rc = open FD, $BuildNumberFile or warn $BuildNumberFile, ": ", $!, "\n"; return $BuildNumber unless $rc;
for (<FD>) { chomp; ($mname, $bn) = split /=/; $BuildNumber = $bn if $mname =~ /BUILDNUMBER/i; } close FD;
return $BuildNumber; }
|