Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

607 lines
15 KiB

  1. require $ENV{'sdxroot'} . '\TOOLS\sendmsg.pl';
  2. #
  3. # Globals
  4. #
  5. $BuildMachinesRelPathname = "TOOLS\\BuildMachines.txt";
  6. $BuildMachinesFile = $ENV{ "RazzleToolPath" } . "\\BuildMachines.txt";
  7. $SdDotMapPathname = "sd.map";
  8. #
  9. # Usage variables
  10. #
  11. $PGM='SendBuildStats:';
  12. $Usage = "\n" . 'Usage: SendBuildStats [-v] [-o | -t] -s | -w | -fb[:build.err] | -fpb' . "[-m msg]\n".
  13. "\n".
  14. " -? help\n".
  15. " -v verbose\n".
  16. " -o send only to suspect list\n".
  17. " -t put suspect list on To: line, DL on CC:\n".
  18. " -s build success\n".
  19. " -w send out warning\n".
  20. " -fb[:fname] build failed, fname is the build.err file\n".
  21. " -fpb[:fname] post build faild\, fname is the postbuild.err file\n".
  22. " -m msg rest of line is a message to include in the mail\n";
  23. #
  24. # debug routine for printing out variables
  25. #
  26. sub pvar {
  27. for (@_) {
  28. print "\$$_ = $$_\n";
  29. }
  30. }
  31. #
  32. # signal catcher (at least this would work on unix)
  33. #
  34. sub catch_ctrlc {
  35. printf $LogHandle "$PGM Aborted.\n" if $LogHandle;
  36. die "$PGM Aborted.\n";
  37. }
  38. $SIG{INT} = \&catch_ctrlc;
  39. #
  40. # Get the current directory
  41. #
  42. open CWD, 'cd 2>&1|';
  43. $CurrDir = <CWD>;
  44. close CWD;
  45. chomp $CurrDir;
  46. $CurrDrive = substr($CurrDir, 0, 2);
  47. #
  48. # Check variables expected to be set in the environment.
  49. #
  50. $sdxroot = $ENV{'SDXROOT'} or die $PGM, "SDXROOT not set in environment\n";
  51. $MyComputername = $ENV{'COMPUTERNAME'} or die $PGM, "COMPUTERNAME not set in environment\n";
  52. $MyBuildArch = $ENV{'_BuildArch'} or die $PGM, "_BuildArch not set in environment\n";
  53. $MyBuildType = $ENV{'_BuildType'} or die $PGM, "_BuildType not set in environment\n";
  54. $MyBranch = $ENV{'_BuildBranch'} or die $PGM, "_BuildBranch not set in environment\n";
  55. $BuildDotChanges = $ENV{'sdxroot'} . '\build.changes';
  56. $BuildDotChangedFiles = $ENV{'sdxroot'} . '\build.changedfiles';
  57. $BuildDateFile = $ENV{'sdxroot'} . '\__blddate__';
  58. $BuildMailMsg = $ENV{'BuildMailMsg'};
  59. $BuildNumberFile = $ENV{'sdxroot'} . '\__bldnum__';
  60. #
  61. # Initialize variables
  62. #
  63. $Success = 0; # only one of these gets set
  64. $Warn = 0;
  65. $BuildFailed = 0;
  66. $PostBuildFailed = 0;
  67. $Fail = 0; # set if either BuildFailed or PostBuildFailed
  68. $BuildDotErr = 0; # will hold the name of the build.err file
  69. $Fake = 0; # fake output flag
  70. $Verbose = 0; # verbose output flag
  71. $SuspectsOnly = 0; # flag to send mail only to the suspect list.
  72. $SuspectsToo = 0; # flag to send mail to the suspect list and CC everyone else.
  73. $BuildDate = ""; # set on first call to ReadBuildDate()
  74. $BuildNumber = ""; # set on first call to ReadBuildNumber()
  75. #
  76. # Determine if this machine is an Official Build machine or not
  77. #
  78. $OfficialBuildMachine = $ENV{'OFFICIAL_BUILD_MACHINE'};
  79. if (!$BuildMailMsg) {
  80. if ($OfficialBuildMachine) {
  81. $BuildMailMsg = "Official Build";
  82. } else {
  83. $BuildMailMsg = "Private Build";
  84. }
  85. }
  86. $BuildCategory = "Unknown";
  87. $BuildCategory = "Private" if $BuildMailMsg =~ /priv/i;
  88. $BuildCategory = "OFFICIAL" if $BuildMailMsg =~ /official/i;
  89. $BuildCategory = "MiniLoop" if $BuildMailMsg =~ /mini/i;
  90. $SpecialMsg = 0;
  91. #
  92. # Get Complete Build Number if possible
  93. #
  94. $CompleteBuildNumber = ReadBuildNumber() . "\.$MyBuildArch$MyBuildType\.$MyBranch\." . ReadBuildDate();
  95. #
  96. # process arguments
  97. #
  98. for (@ARGV) {
  99. if ($SpecialMsg) {
  100. $SpecialMsg .= " $_";
  101. next;
  102. }
  103. if (/^-m$/i or /^-msg$/i or /^-message$/i) {
  104. $SpecialMsg = "***";
  105. next;
  106. }
  107. if (/^-fake$/i) {
  108. $Fake++;
  109. next;
  110. }
  111. if (/^-v$/i or /^-verbose$/i) {
  112. $Verbose++;
  113. next;
  114. }
  115. if (/^-t$/i or /^-too$/) {
  116. $SuspectsToo++;
  117. next;
  118. }
  119. if (/^-o$/i or /^-only$/) {
  120. $SuspectsOnly++;
  121. next;
  122. }
  123. if (/^-s$/i or /^-success$/i or /^-successful$/i) {
  124. $Success++;
  125. next;
  126. }
  127. if (/^-w$/i or /^-warn$/i) {
  128. $Warn++;
  129. next;
  130. }
  131. if (/^-fb(:.*)?$/i or /^-buildfailure(:.*)?$/i) {
  132. $BuildFailed++;
  133. $Fail++;
  134. if ($1) {
  135. $BuildDotErr = $1;
  136. $BuildDotErr =~ s/://;
  137. } else {
  138. $BuildDotErr = $ENV{'sdxroot'} . '\build.err';
  139. }
  140. next;
  141. }
  142. if (/^-fpb(:.*)?$/i or /^-postbuildfailure(:.*)?$/i) {
  143. $PostBuildFailed++;
  144. $Fail++;
  145. if ($1) {
  146. $PostBuildDotErr = $1;
  147. $PostBuildDotErr =~ s/://;
  148. } else {
  149. if ( -e '\\\\' . $MyComputername . '\latest\build_logs\postbuild.err') {
  150. $PostBuildDotErr = '\\\\' . $MyComputername . '\latest\build_logs\postbuild.err';
  151. } else {
  152. $PostBuildDotErr = $ENV{'_NTTREE'} . '\build_logs\postbuild.err';
  153. }
  154. }
  155. next;
  156. }
  157. if (/^-?$/i or /^-help$/) {
  158. print $Usage;
  159. exit 0;
  160. }
  161. die $Usage;
  162. }
  163. $SpecialMsg .= " ***\n" if $SpecialMsg;
  164. #
  165. # Sanity Check arguments
  166. #
  167. pvar Success, Warn, BuildFailed, BuildDotErr, PostBuildFailed, SuspectsOnly if $Verbose;
  168. die $Usage unless $Success + $Warn + $BuildFailed + $PostBuildFailed == 1;
  169. die $Usage unless $SuspectsOnly + $SuspectsToo <= 1;
  170. #
  171. # Compute MyDl, BuildChanges, Changers, and Suspects
  172. # Will use to decide the recipients to send Message To
  173. #
  174. SetMyDl();
  175. GetChangersAndSuspects();
  176. #
  177. # Generate the appropriate build message.
  178. #
  179. $BuildMail = FormatBuildMailStart();
  180. $PrivateBuild = ($BuildCategory =~ /private/i);
  181. if ($Success) {
  182. #
  183. # Build was successful, so format a successful build message, and
  184. # send success build mail
  185. #
  186. #$BuildMailSubject = "Build Succeeded: $MyBuildArch$MyBuildType $CompleteBuildNumber";
  187. $BuildMailSubject = "BUILD $MyComputername/$MyBranch: $BuildCategory $BuildDate $MyBuildArch$MyBuildType SUCCEEDED";
  188. if ($PrivateBuild) {
  189. $BuildMail .= "Build is available on $ENV{'_NTTREE'}\n";
  190. } else {
  191. $BuildMail .= "Build is available on \\\\$MyComputername\\latest\n" . "\nChanges for this build include\n\n\n" . $BuildChanges;
  192. }
  193. } elsif ($Warn) {
  194. #
  195. # We are sending a warning message.
  196. #
  197. $BuildMailSubject = "BUILD $MyComputername/$MyBranch: $BuildCategory $BuildDate $MyBuildArch$MyBuildType warning";
  198. } elsif ($BuildFailed) {
  199. #
  200. # Build failed, so format either a build.exe failure email and log data,
  201. #
  202. #$BuildMailSubject = "Build Failed: $MyBuildArch$MyBuildType $CompleteBuildNumber";
  203. $BuildMailSubject = "BUILD $MyComputername/$MyBranch: $BuildCategory $BuildDate $MyBuildArch$MyBuildType FAILED";
  204. $BuildMail .= "These failures occurred:\n\n\n" . $BuildErrs . "\n";
  205. $BuildMail .= "\nChanges for this build include\n\n\n" . $BuildChanges unless $PrivateBuild;
  206. } else { # $PostBuildFailed
  207. #
  208. # or a postbuild failure email and log data
  209. #
  210. #$BuildMailSubject = "Build Failed (PostBuild): $MyBuildArch$MyBuildType $CompleteBuildNumber";
  211. $BuildMailSubject = "BUILD $MyComputername/$MyBranch: $BuildCategory $BuildDate $MyBuildArch$MyBuildType FAILED - POSTBUILD";
  212. $BuildMail .= "PostBuild Failure:\n\n\n" . ReadPostBuildDotErr();
  213. $BuildMail .= "\nChanges for this build include\n\n\n" . $BuildChanges unless $PrivateBuild;
  214. }
  215. pvar BuildMailSubject,MyDl,MyComputername,MyBuildArch,MyBuildType if $Verbose;
  216. print $BuildMail if $Verbose;
  217. @Changers = (); # Lab 7 doesn't want to send mail other than to $MyDl
  218. if ($PrivateBuild) {
  219. @MailTargets = ($MyDl);
  220. } elsif ($SuspectsOnly and scalar @Suspects) {
  221. @MailTargets = @Suspects;
  222. } elsif ($SuspectsToo and scalar @Suspects) {
  223. @MailTargets = ("CC:$MyDl", @Suspects);
  224. } elsif (scalar @Changers) {
  225. @MailTargets = ("CC:$MyDl", @Changers);
  226. } else {
  227. @MailTargets = ("$MyDl");
  228. }
  229. if ($Fake) {
  230. print "sendmsg parameters:\n";
  231. for ('-v', $MyDl."DisableOof", $BuildMailSubject, $BuildMail, @MailTargets) {
  232. print "<<$_>>";
  233. }
  234. print "\n";
  235. } else {
  236. #
  237. # Really send the message
  238. #
  239. $rc = sendmsg ('-v', $MyDl."DisableOof", $BuildMailSubject, $BuildMail, @MailTargets);
  240. print "WARNING: sendmsg failed!\n" if $rc;
  241. }
  242. exit 0;
  243. ##
  244. ## Support Subroutine Section
  245. ##
  246. #
  247. # Set MyDl.
  248. # For official build machines, extract this from BuildMachines.txt,
  249. # otherwise use _NT_BUILD_DL, USERNAME, or the script maintainer -- in that order.
  250. #
  251. sub SetMyDl {
  252. if ($OfficialBuildMachine) {
  253. $fname = $BuildMachinesFile;
  254. open BMFILE, $fname or die "Could not open: $fname\n";
  255. for (<BMFILE>) {
  256. s/\s+//g;
  257. s/;.*$//;
  258. next if /^$/;
  259. my($vblmach, $vblprime, $vblbranch, $vblarch, $vbldbgtype, $vbldl, $disttype ) = split /,/;
  260. #
  261. # The BuildMachines.txt record is keyed by computername, architecture, type, and branch
  262. #
  263. if ( ($vblmach =~ /\Q$MyComputername\E/io) &&
  264. ($vblarch =~ /\Q$MyBuildArch\E/io) &&
  265. ($vbldbgtype =~ /\Q$MyBuildType\E/io) &&
  266. ($vblbranch =~ /\Q$MyBranch\E/io) ) {
  267. close BMFILE;
  268. $MyPrime = $vblprime;
  269. $MyDl = $vbldl;
  270. return;
  271. }
  272. }
  273. printf $PGM . "Problem Encounterd. $MyComputername was NOT found in buildmachines.txt. dl defaults to DavePr\n";
  274. $MyDl = "DavePr";
  275. close BMFILE;
  276. } else {
  277. $MyDl = $ENV{'_NT_BUILD_DL'};
  278. if (!$MyDl) {
  279. $MyDl = $ENV{'USERNAME'} or $MyDl = "DavePr";
  280. }
  281. }
  282. }
  283. #
  284. # Construct the base message used in the various cases.
  285. #
  286. sub FormatBuildMailStart {
  287. my($msg);
  288. my($BuildDate);
  289. my($MacroName);
  290. if ($Success) {
  291. $msg = "Build Was Successful\n\n";
  292. } elsif ($Warn) {
  293. $msg = "Build early-warning message\n\n";
  294. } elsif ($BuildFailed) {
  295. $msg = "Build errors were found\n\n";
  296. } else { # $PostBuildFailed
  297. $msg = "Postbuild errors were found\n\n";
  298. }
  299. if (scalar @Suspects) {
  300. $msg .= "Suspects:";
  301. for (@Suspects) {
  302. $msg .= " $_";
  303. }
  304. $msg .= "\n";
  305. }
  306. $msg .= $BuildMailMsg . "\n" if $BuildMailMsg;
  307. $msg .= $SpecialMsg . "\n" if $SpecialMsg;
  308. $msg .= "\nBuild Name : $CompleteBuildNumber\n";
  309. $msg .= "\nBuild Date : " . ReadBuildDate() . "\n";
  310. $msg .= "Build Machine: $MyComputername\n";
  311. $msg .= "Architecture : $MyBuildArch\n";
  312. $msg .= "DbgType : $MyBuildType\n";
  313. $msg .= "Branch : $MyBranch\n";
  314. $msg .= "SdxRoot : $sdxroot\n";
  315. $msg .= "DL Notified : $MyDl\n";
  316. $msg .= "\n\n";
  317. return $msg;
  318. }
  319. #
  320. # Canonicalize the prefix of a build path so we can make guesses about who
  321. # might have caused a build error based on who made changes to what.
  322. #
  323. sub CanonicalizeBuildPath {
  324. $_ = @_[0];
  325. s/\\[^\\]+$//; # remove filename
  326. s/\\obj[^\\]*\\.*//i; # ignore OBJ directories
  327. s/\\daytona\\.*//i; # ignore common sub-directories (
  328. s/\\i386\\.*//i;
  329. s/\\amd64\\.*//i;
  330. s/\\ia64\\.*//i;
  331. s/\\daytona\\.*//i;
  332. s/\\i386\\.*//i;
  333. s/\\amd64\\.*//i;
  334. s/\\ia64\\.*//i;
  335. s/^[a-z]:\\[^\\]+\\//i; # remove sdxroot
  336. # remove last directory component -- if we have at least three
  337. s/\\[^\\]+$// if 3 <= split /\\/;
  338. return $_;
  339. }
  340. #
  341. # As BuildDotErr is read, we are called to record the canonicalized paths found.
  342. #
  343. sub CaptureBuildFailure {
  344. $_ = @_[0];
  345. chomp;
  346. $capture = "";
  347. if (/NMAKE/) {
  348. if (/U1073/) {
  349. s/'$//;
  350. s/.*//;
  351. $capture = $_;
  352. }
  353. } else {
  354. s/[ (].*//;
  355. s/^[0-9]*>//;
  356. $capture = $_;
  357. }
  358. if ($capture) {
  359. $capture = CanonicalizeBuildPath $capture;
  360. $BuildFailure{$capture}++;
  361. }
  362. }
  363. #
  364. # Set $BuildChanges, $BuildErrs, @Changers, and @Suspects -- as appropriate.
  365. #
  366. sub GetChangersAndSuspects {
  367. $BuildChanges = "";
  368. $BuildErrs = "";
  369. @Changers = ();
  370. @Suspects = ();
  371. #
  372. # If this was a build failure, process BuildDotErr
  373. #
  374. if ($BuildFailed) {
  375. my($rc) = open FD, $BuildDotErr or warn $BuildDotErr, ": ", $!, "\n";
  376. if ($rc) {
  377. for (<FD>) {
  378. $BuildErrs .= $_;
  379. CaptureBuildFailure($_);
  380. }
  381. close FD;
  382. } else {
  383. $BuildErrs = "Sorry, unable to locate $BuildDotErr\n";
  384. }
  385. }
  386. #
  387. # Get the Changers and record the BuildChanges for use in the BuildMail.
  388. #
  389. my($rcc) = open FD, $BuildDotChanges or warn $BuildDotChanges, ": ", $!, "\n";
  390. if ($rcc) {
  391. %Checklist=();
  392. for (<FD>) {
  393. $BuildChanges .= $_;
  394. next unless /^Change /;
  395. chop;
  396. s/'.*$//;
  397. s/.* by //;
  398. s/@.*//;
  399. s/.*\\//;
  400. tr/A-Z/a-z/;
  401. $Checklist{$_}++;
  402. }
  403. close FD;
  404. @Changers = sort keys %Checklist;
  405. } else {
  406. $BuildChanges = "Sorry, unable to locate $BuildDotChanges\n";
  407. }
  408. #
  409. # Get the Suspects
  410. #
  411. if ($BuildFailed) {
  412. my($project, $change, $dev, $date, $time, $sdpath, $type);
  413. $rcc = open FD, $BuildDotChangedFiles or warn $BuildDotChangedFiles, ": ", $!, "\n";
  414. if ($rcc) {
  415. %Checklist=();
  416. for (<FD>) {
  417. my($project, $change, $dev, $date, $time, $sdpath, $type) = split;
  418. next unless $type;
  419. $_ = $sdpath;
  420. s|#.*||; # strip #change
  421. s|//depot/[^/]*/||i; # strip //depot/lab
  422. tr|/|\\|; # / -> \
  423. $canonpath = CanonicalizeBuildPath $_;
  424. next unless $BuildFailure{$canonpath};
  425. print "Suspect $dev because of change $change affecting $canonpath\n" if $Verbose and not $Pinged{$change};
  426. $Pinged{$change}++;
  427. $Checklist{$dev}++;
  428. }
  429. close FD;
  430. @Suspects = sort keys %Checklist;
  431. }
  432. }
  433. }
  434. #
  435. # Return the contents of the PostBuildDotErr file.
  436. #
  437. sub ReadPostBuildDotErr {
  438. my($pbcontents) = "";
  439. $rc = open FD, $PostBuildDotErr;
  440. return "Sorry, unable to locate $PostBuildDotErr\n" unless $rc;
  441. for (<FD>) {
  442. $pbcontents .= $_;
  443. }
  444. close FD;
  445. return $pbcontents;
  446. }
  447. #
  448. # Set BuildDate from the contents of the BuildDate file and return it.
  449. #
  450. sub ReadBuildDate {
  451. my($rc, $mname, $bd);
  452. return $BuildDate if $BuildDate;
  453. $BuildDate = "UnknownBuildDate";
  454. $rc = open FD, $BuildDateFile or warn $BuildDateFile, ": ", $!, "\n";
  455. return $BuildDate unless $rc;
  456. for (<FD>) {
  457. chomp;
  458. ($mname, $bd) = split /=/;
  459. $BuildDate = $bd if $mname =~ /BUILDDATE/i;
  460. }
  461. close FD;
  462. return $BuildDate;
  463. }
  464. #
  465. # Set BuildDate from the contents of the BuildDate file and return it.
  466. #
  467. sub ReadBuildNumber {
  468. my($rc, $mname, $bn);
  469. return $BuildNumber if $BuildNumber;
  470. $BuildNumber = "UnknownBuildNumber";
  471. $rc = open FD, $BuildNumberFile or warn $BuildNumberFile, ": ", $!, "\n";
  472. return $BuildNumber unless $rc;
  473. for (<FD>) {
  474. chomp;
  475. ($mname, $bn) = split /=/;
  476. $BuildNumber = $bn if $mname =~ /BUILDNUMBER/i;
  477. }
  478. close FD;
  479. return $BuildNumber;
  480. }