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.

843 lines
25 KiB

  1. # FileName: timebuild.pl
  2. #
  3. # Have any changes to this file reviewed by DavePr, BryanT, or WadeLa
  4. # before checking in.
  5. # Any changes need to verified in all standard build/rebuild scenarios.
  6. #
  7. # Reads in the commands from commandfile, and executes them with system() -- recording
  8. # the elapsed times on the standard output.
  9. # Echo and timing can be supressed by prepending '@'.
  10. # The magic 'CHECKFATAL' command can be used to end a script if the previous command failed.
  11. # If commandfile is not specified, uses a canned list of commands.
  12. #
  13. # Note: ':' can be used instead of '=' in command line arguments, since '=' is a separator to cmd.exe
  14. #
  15. # WARNING:
  16. # WARNING: make sure pathname comparisons are case insensitive. Either convert the case or do the
  17. # WARNING: comparisons like this:
  18. # WARNING: if ($foo =~ /^\Q$bar\E$/i) {}
  19. # WARNING: or if ($foo !~ /^\Q$bar\E$/i) {}
  20. # WARNING:
  21. # use appropriate pm files
  22. use lib $ENV{ "RazzleToolPath" } . "\\PostBuildScripts";
  23. use cookie;
  24. #
  25. # Default cmdlist
  26. # Enclose in single quotes, unless getting tricky with parameters
  27. #
  28. # Note that RESUME and STOPAFTERBUILD are referenced in the code.
  29. #
  30. @ValidFlagList = ("NOSYNC", "NOPOSTBUILD", "STOPAFTERBUILD", "QFE", "RELEASE", "NOSCORCH", "NOCLEANBUILD", "CHECKSYNC");
  31. $Usage = $PGM . "Usage: timebuild.pl\n"
  32. . " [-]\n"
  33. . " [-START=[[YY]MMDD-]HH[:]MM[(a|p)] - specify a time to start the commands (start => revision time to use)\n"
  34. . " [-START=+[HH[:]MM]] - specify a delay before starting commands\n"
  35. . " [-RESUME] - start-up again after the build step\n"
  36. . " [-QFE=NNNNNN] - package a QFE instead of a service pack\n"
  37. . " [-STOPAFTERBUILD] - stop commands right after the build step\n"
  38. . " [-NOSYNC] - do not sync/resolve\n"
  39. . " [-NOSCORCH] - do not run scorch\n"
  40. . " [-NOCLEANBUILD] - don't use -c with build\n"
  41. . " [-NOPOSTBUILD] - skip the postbuild step\n"
  42. . " [-NOCOOKIE] - ignore synchronization against concurrent timebuilds\n"
  43. . " [-PRS] - PRS sign the result during packaging\n"
  44. . " [-COVERBUILD] - produce one build with coverage-enabled files\n"
  45. . " [-RELEASE] - release the build (automatic on build machines)\n"
  46. . " [-REVISION=<sdrevision>] - SD file revision to use (\@yyyy/mm/dd:hh:ss or \#rev -- see sd help revisions)\n"
  47. . " [commandfile | - ] - instead of built-in commands use file or stdin\n\n";
  48. #
  49. # Conditional execution based on either ValidFlagList (specified on command line) or environment variables.
  50. #
  51. @cmdlist = (
  52. ' @echo Running <<timebuild>>',
  53. '=%OFFICIAL_BUILD_MACHINE ECHO This is an OFFICIAL BUILD MACHINE!',
  54. '=%OFFICIAL_BUILD_MACHINE=PRIMARY ECHO Publics will be published if timebuild succeeds.',
  55. ' @if EXIST <<fixederr>> del <<fixederr>>',
  56. '=NOSYNC @echo SKIPPING sync/resolve',
  57. '=NOSYNC SUCCESS', # set current result code to 0
  58. '!NOSYNC revert_public.cmd',
  59. '=CHECKSYNC CHECKWARN perl %sdxroot%\Tools\sendbuildstats.pl -warn -m revert_public failed',
  60. '=NOSCORCH @echo SKIPPING scorch',
  61. '!NOSCORCH nmake -lf makefil0 scorch_source',
  62. '!NOSCORCH CHECKWARN perl %sdxroot%\Tools\sendbuildstats.pl -warn -m scorch failed see %sdxroot%\build.scorch',
  63. '!NOSYNC sdx sync ...<<timestamp>> -q -h > build.changes 2>&1',
  64. '=CHECKSYNC CHECKWARN perl %sdxroot%\Tools\sendbuildstats.pl -warn -m sdx sync failed',
  65. '!NOSYNC sdx resolve -af',
  66. '=CHECKSYNC CHECKWARN perl %sdxroot%\Tools\sendbuildstats.pl -warn -m sdx resolve failed',
  67. '!NOSYNC perl %sdxroot%\Tools\ChangesToFiles.pl build.changes > build.changedfiles 2>&1',
  68. '!NOSYNC @echo BUILDDATE=<<BUILDDATE_timestamp>> > __blddate__',
  69. # ' sdx delta > build.baseline',
  70. '!NOCLEANBUILD build -cZP',
  71. '=NOCLEANBUILD @echo NOT BUILDING CLEAN',
  72. '=NOCLEANBUILD build -ZP',
  73. ' CHECKBUILDERRORS',
  74. ' CHECKFATAL perl %sdxroot%\Tools\sendbuildstats.pl -too -buildfailure',
  75. 'RESUME',
  76. '=RESUME ECHO Resuming timebuild after build step.',
  77. '=RESUME ECHO Resuming timebuild after build step. >> build.changes',
  78. ' %sdxroot%\Tools\ChangesToBuild.cmd',
  79. # '=RESUME ECHO The following changes have been made since the build was started. >> build.changes',
  80. # '=RESUME perl %sdxroot%\Tools\DetermineChanges.pl build.baseline >> build.changes',
  81. # '=RESUME perl %sdxroot%\Tools\ChangesToFiles.pl build.changes > build.changedfiles 2>&1',
  82. '=STOPAFTERBUILD QUIT TIMEBUILD stopping after build, use /RESUME to continue.',
  83. '=%OFFICIAL_BUILD_MACHINE %sdxroot%\Tools\sp\submit_public.cmd',
  84. 'RESUME QFE',
  85. '=QFE ECHO Packaging a QFE. Build not run.',
  86. ' %sdxroot%\Tools\sp\bbt\bbt.cmd -incbbt',
  87. ' perl %sdxroot%\Tools\sp\planpackage.pl <<QFE>> <<PRS>>',
  88. ' CHECKFATAL',
  89. ' %sdxroot%\Tools\sp\scp_wpafilessp1.cmd <<QFE>> -root:%_nttree%',
  90. ' %sdxroot%\Tools\sp\filter.cmd <<QFE>>',
  91. ' CHECKFILTERERRORS',
  92. ' CHECKFATAL',
  93. '!NOPOSTBUILD LANG %sdxroot%\Tools\sp\package.cmd <<QFE>> <<PRS>>',
  94. '!NOPOSTBUILD CHECKFATAL',
  95. # '!NOPOSTBUILD perl %sdxroot%\tools\sendbuildstats.pl -successful',
  96. '=NOPOSTBUILD ECHO SKIPPING postbuild',
  97. 'ECHO Finished Timing Build'
  98. );
  99. if ($ENV{'BUILD_OFFLINE'} eq "1") { @cmdlist = (
  100. ' @echo Running <<timebuild>>',
  101. ' @if EXIST <<fixederr>> del <<fixederr>>',
  102. '=NOSYNC @echo SKIPPING sync/resolve',
  103. '=NOSYNC SUCCESS', # set current result code to 0
  104. '=NOSCORCH @echo SKIPPING scorch',
  105. '!NOSCORCH nmake -lf makefil0 scorch_source',
  106. '=CHECKSYNC CHECKWARN perl %sdxroot%\Tools\sendbuildstats.pl -warn -m sdx sync failed',
  107. '=CHECKSYNC CHECKWARN perl %sdxroot%\Tools\sendbuildstats.pl -warn -m sdx resolve failed',
  108. '!NOSYNC perl %sdxroot%\Tools\ChangesToFiles.pl build.changes > build.changedfiles 2>&1',
  109. '!NOSYNC @echo BUILDDATE=<<BUILDDATE_timestamp>> > __blddate__',
  110. '!NOCLEANBUILD build -cZP',
  111. '=NOCLEANBUILD @echo NOT BUILDING CLEAN',
  112. '=NOCLEANBUILD build -ZP',
  113. ' CHECKBUILDERRORS',
  114. # ' CHECKFATAL perl %sdxroot%\Tools\sendbuildstats.pl -too -buildfailure',
  115. 'RESUME',
  116. '=RESUME ECHO Resuming timebuild after build step.',
  117. '=RESUME ECHO Resuming timebuild after build step. >> build.changes',
  118. # ' %sdxroot%\Tools\ChangesToBuild.cmd',
  119. # '=RESUME ECHO The following changes have been made since the build was started. >> build.changes',
  120. # '=RESUME perl %sdxroot%\Tools\DetermineChanges.pl build.baseline >> build.changes',
  121. # '=RESUME perl %sdxroot%\Tools\ChangesToFiles.pl build.changes > build.changedfiles 2>&1',
  122. '=STOPAFTERBUILD QUIT TIMEBUILD stopping after build, use /RESUME to continue.',
  123. 'RESUME QFE',
  124. '=QFE ECHO Packaging a QFE. Build not run.',
  125. # ' %sdxroot%\Tools\sp\bbt\bbt.cmd -incbbt',
  126. ' perl %sdxroot%\Tools\sp\planpackage.pl <<QFE>> <<PRS>>',
  127. ' CHECKFATAL',
  128. # ' %sdxroot%\Tools\sp\scp_wpafilessp1.cmd <<QFE>> -root:%_nttree%',
  129. ' %sdxroot%\Tools\sp\filter.cmd <<QFE>>',
  130. ' CHECKFILTERERRORS',
  131. ' CHECKFATAL',
  132. '!NOPOSTBUILD LANG %sdxroot%\Tools\sp\package.cmd <<QFE>> <<PRS>>',
  133. '!NOPOSTBUILD CHECKFATAL',
  134. # '!NOPOSTBUILD perl %sdxroot%\tools\sendbuildstats.pl -successful',
  135. '=NOPOSTBUILD ECHO SKIPPING postbuild',
  136. 'ECHO Finished Timing Build'
  137. );
  138. }
  139. for (@ValidFlagList) {
  140. $ValidFlag{lc $_} = 1;
  141. }
  142. $TimeLogFileName = "build.time";
  143. $ChangeLogFileName = "build.changes";
  144. $TimeHistFileName = "build.timehistory";
  145. $BuildErrorFileName = "build.err";
  146. $BuildCheckFileName = "build.fixed-err";
  147. $FilterErrFile = "$ENV{_NTFILTER}\\build_logs\\filter.err";
  148. $LangListFile = "$ENV{_NTPOSTBLD}\\build_logs\\langlist.txt";
  149. $CookieSleepDuration = 60;
  150. $cmdvar{fixederr} = $BuildCheckFileName;
  151. #
  152. # Debug routines for printing out variables
  153. #
  154. sub gvar {
  155. for (@_) {
  156. print "\$$_ = $$_\n";
  157. }
  158. }
  159. #
  160. # print on the various files
  161. #
  162. sub printall {
  163. print TIMELOGFILE @_;
  164. print TIMEHISTFILE @_;
  165. print $PGM unless @_ == 1 and $_[0] eq "\n";
  166. print @_;
  167. }
  168. sub printfall {
  169. printf TIMELOGFILE @_;
  170. printf TIMEHISTFILE @_;
  171. print $PGM unless @_ == 1 and $_[0] eq "\n";
  172. printf @_;
  173. }
  174. #
  175. # Sub hms
  176. # Takes Argument time in seconds and returns as list of (hrs, mins, secs)
  177. #
  178. sub hms {
  179. $s = shift @_;
  180. $h = int ($s / 3600);
  181. $s -= 3600*$h;
  182. $m = int ($s / 60);
  183. $s -= 60*$m;
  184. return ($h, $m, $s);
  185. }
  186. #
  187. # Sub toseconds
  188. # Takes Argument time string and returns how many seconds from now.
  189. # Balks at negative time, or time greater than a week.
  190. # Returns 0 on error. Any valid time returns at least 1 second.
  191. # Flavors of time specs:
  192. # +MM
  193. # +HH:MM
  194. # HH:MM
  195. # HH:MMa
  196. #
  197. sub toseconds {
  198. my($y, $M, $d, $h, $m, $s, $mday, $wday, $yday, $isdst);
  199. my($delta, $now, $then, $th, $tm, $ampm);
  200. my($arg) = $_[0];
  201. ($s, $m, $h, $mday, $M, $y, $wday, $yday, $isdst) = localtime;
  202. $y += 1900;
  203. $M += 1;
  204. $mday += 1;
  205. if ($arg =~ /^\+(\d+)$/i) {
  206. $delta = $1;
  207. } elsif ($arg =~ /^\+(\d+)\:(\d{1,2})$/i) {
  208. $delta = $1 * 60 + $2;
  209. } elsif ($arg =~ /^(\d{1,2})\:(\d{1,2})([ap]m{0,1}){0,1}$/i
  210. or $arg =~ /^(\d\d)(\d\d)([ap]m{0,1}){0,1}$/i) {
  211. $th = $1;
  212. $tm = $2;
  213. $ampm = $3;
  214. return -1 if $ampm and ($th == 0 or $th > 12);
  215. if ($ampm =~ /^pm{0,1}$/i) {
  216. $th += 12 if $th < 12;
  217. } else {
  218. $th = 0 if $th == 12;
  219. }
  220. $now = $h *60 + $m;
  221. $then = $th *60 + $tm;
  222. $then += (24 *60) if ($now > $then);
  223. $delta = $then - $now;
  224. } else {
  225. $delta = -1;
  226. }
  227. return $delta * 60 if $delta > 0; # convert to seconds
  228. return 1 if $delta == 0; # minimum valid wait
  229. return 0 if $delta < 0; # error
  230. }
  231. #
  232. # Initialization
  233. #
  234. $PGM='TIMEBUILD: ';
  235. $cmdvar{timebuild} = "TIMEBUILD";
  236. $TimeLogFileSpec = ">" . $TimeLogFileName;
  237. $TimeHistFileSpec = ">>" . $TimeHistFileName;
  238. open TIMELOGFILE, $TimeLogFileSpec or die $PGM, "Could not open: ", $TimeLogFileName, "\n";
  239. open TIMEHISTFILE, $TimeHistFileSpec or die $PGM, "Could not open: ", $TimeHistFileName, "\n";
  240. ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime;
  241. $foo = sprintf "Timed Build script started at %04d/%02d/%02d-%02d:%02d:%02d.\n",
  242. 1900+$year, 1+$mon, $mday, $hour, $min, $sec;
  243. printall "\n";
  244. printall $foo;
  245. $begintime = time();
  246. #
  247. # Assume we're setting the build date.
  248. #
  249. $ENV{"BUILD_DATE_SET"} = 1;
  250. #
  251. # Make sure NT_SIGNCODE is off as it disables most of the postbuild changes.
  252. #
  253. $ENV{"NT_SIGNCODE"} = "";
  254. #
  255. # Process and validate arguments
  256. #
  257. $CommandFile = 0;
  258. $DoResume = 0;
  259. $ResumeTag = "";
  260. $Verbose = 0;
  261. $Fake = 0;
  262. $WaitSeconds = 0;
  263. $NoCookie = 0;
  264. $Prs = 0;
  265. $Revision = "";
  266. @Langs = ();
  267. for (@ARGV) {
  268. if (/^[\-\/]{0,1}\?$/i) { die $Usage; }
  269. if (/^[\-\/]help$/i) { die $Usage; }
  270. if (/^[\-\/]lang[:=](.+)$/i) { @Langs = split /;/, $1; next; }
  271. if (/^[\-\/]resume$/i) { $DoResume++; $ResumeTag = ""; next; }
  272. if (/^[\-\/]resume[:=](.+)$/i) { $DoResume++; $ResumeTag = $1; next; }
  273. if (/^[\-\/]revision[:=]([@#].+)$/i) { $Revision = $1; next; }
  274. if (/^[\-\/]prs$/i) { $Prs++; next; }
  275. if (/^[\-\/]verbose$/i) { $Verbose++; next; }
  276. if (/^[\-\/]fake$/i) { $Fake++; next; }
  277. if (/^[\-\/]nocookie$/i) { $NoCookie++; next; }
  278. if (/^[\-\/]start[:=](.+)$/i) { $WaitSeconds = toseconds $1;
  279. die $PGM, "Invalid start time: ", $1, "\n" unless $WaitSeconds;
  280. next;
  281. }
  282. #
  283. # Set the environment variables we need for producing a coverage build
  284. #
  285. if (/^[\-\/]coverbuild/i) {
  286. $ENV{"_COVERAGE_BUILD"} = 1;
  287. }
  288. #
  289. # We don't set the build date if this is a nosync build.
  290. #
  291. if (/^[\-\/]nosync/i) {
  292. $ENV{"BUILD_DATE_SET"} = "";
  293. }
  294. #
  295. # Flags can be used for things like -STOPAFTERBUILD
  296. #
  297. if (/^[\-\/](\S+)[:=](\S+)$/i) {
  298. $argkey = lc $1;
  299. $argval = lc $2;
  300. die $PGM, "Invalid option: ", $argkey, "\n", $Usage unless $ValidFlag{$argkey};
  301. $Flags{$argkey} = $argval;
  302. next;
  303. }
  304. if (/^[\-\/](\S+)$/i) {
  305. $argkey = lc $1;
  306. die $PGM, "Invalid option: ", $argkey, "\n", $Usage unless $ValidFlag{$argkey};
  307. $Flags{$argkey}++;
  308. next;
  309. }
  310. #
  311. # All that should be left is the commandfile (we only allow one).
  312. #
  313. die $Usage if $CommandFile;
  314. $CommandFile = $_;
  315. }
  316. if (!@Langs) {
  317. if ($ENV{OFFICIAL_BUILD_MACHINE} and lc $ENV{_BUILDTYPE} eq 'fre') {
  318. if (lc $ENV{_BUILDARCH} ne "x86") {
  319. @Langs = ('usa', 'ger', 'jpn', 'fr');
  320. } else {
  321. if (!$Flags{"qfe"}) {
  322. @Langs = ('usa', 'ger', 'jpn', 'fr', 'kor');
  323. } else {
  324. @Langs = ('usa', 'ara', 'br', 'chh', 'chs', 'cht', 'cs', 'da', 'el', 'es', 'fi', 'fr',
  325. 'ger', 'heb', 'hu', 'it', 'jpn', 'kor', 'nl', 'no', 'pl', 'pt', 'ru', 'sv', 'tr');
  326. }
  327. }
  328. } else {
  329. @Langs = ('usa');
  330. }
  331. }
  332. print $PGM, "Only Faking.\n" if $Fake;
  333. if ($Flags{"qfe"}) {
  334. $DoResume++;
  335. $ResumeTag="QFE";
  336. }
  337. die $Usage if $DoResume > 1;
  338. if ($CommandFile) {
  339. @cmdlist = ();
  340. open CMD, $CommandFile or die $PGM, "Could not open command file: ", $CommandFile, "\n";
  341. for (<CMD>) {
  342. push @cmdlist, $_;
  343. }
  344. close CMD;
  345. print $PGM, 'Running commands from: ', $CommandFile, "\n";
  346. } else {
  347. print $PGM, "Running default build commands.\n";
  348. }
  349. #
  350. # Set up some global variables: nttree
  351. #
  352. # Check the environmental assumptions.
  353. #
  354. # _nttree has to point at a directory containing build_logs
  355. # no_binaries results in a warning
  356. # VBL release has to be detectable
  357. # VBL has to have binlist and binplace files.
  358. #
  359. # Get the current directory
  360. #
  361. open CWD, 'cd 2>&1|';
  362. $CurrDir = <CWD>;
  363. close CWD;
  364. chomp $CurrDir;
  365. $s = $ENV{'sdxroot'};
  366. if (not $s) {
  367. printall "sdxroot not defined\n";
  368. exit 1;
  369. }
  370. if ($s !~ /^\Q$CurrDir\E$/i) {
  371. printall "ERROR: CD ($CurrDir) mismatch with sdxroot ($s)\n";
  372. exit 1;
  373. }
  374. $nttree = $ENV{'_NTTREE'};
  375. if (not $nttree) {
  376. printall "_NTTREE not defined - Adding STOPAFTERBUILD to arg list\n";
  377. $Flags{"STOPAFTERBUILD"} = 1;
  378. }
  379. if (not $ENV{'USERNAME'} and not $ENV {'_NT_BUILD_DL'} and not $ENV {'OFFICIAL_BUILD_MACHINE'}) {
  380. printall "ERROR: Must be an official build machine, or set USERNAME or _NT_BUILD_DL in the environment\n";
  381. exit 1;
  382. }
  383. # THIS IS STILL TODO
  384. use File::Compare;
  385. #
  386. # Process the commands
  387. #
  388. #
  389. # Calculate the build date value to write to __blddate__
  390. #
  391. $BuildDate = "";
  392. if ($Revision) {
  393. # For now, if they specified a revision, just use the current time/date for the build date
  394. ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time() + $WaitSeconds);
  395. $BuildDate = sprintf "%02d%02d%02d-%02d%02d", (1900+$year)%100, 1+$mon, $mday, $hour, $min;
  396. }
  397. #
  398. # sleep if we were told /START=...
  399. #
  400. if ($WaitSeconds) {
  401. ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time() + $WaitSeconds);
  402. if ($sec < $WaitSeconds) {
  403. $WaitSeconds -= $sec;
  404. $sec = 0;
  405. }
  406. $foo = sprintf "Waiting to run commands until %04d/%02d/%02d-%02d:%02d:%02d.\n",
  407. 1900+$year, 1+$mon, $mday, $hour, $min, $sec;
  408. printall $foo;
  409. sleep $WaitSeconds;
  410. #
  411. # yyyy/mm/dd:hh:mm:ss
  412. #
  413. if (not $Revision) {
  414. $Revision = sprintf "@%04d/%02d/%02d:%02d:%02d", 1900+$year, 1+$mon, $mday, $hour, $min;
  415. $BuildDate = sprintf "%02d%02d%02d-%02d%02d", (1900+$year)%100, 1+$mon, $mday, $hour, $min;
  416. }
  417. #
  418. # reset the beginning time if we slept
  419. #
  420. $begintime = time();
  421. }
  422. if (not $Revision) {
  423. ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time());
  424. $Revision = sprintf "@%04d/%02d/%02d:%02d:%02d", 1900+$year, 1+$mon, $mday, $hour, $min;
  425. $BuildDate = sprintf "%02d%02d%02d-%02d%02d", (1900+$year)%100, 1+$mon, $mday, $hour, $min;
  426. }
  427. $cmdvar{timestamp} = "$Revision";
  428. $cmdvar{BUILDDATE_timestamp} = "$BuildDate";
  429. $cmdvar{QFE} = $Flags{"qfe"} ? ("-qfe ".$Flags{"qfe"}):"";
  430. $cmdvar{PRS} = $Prs ? "-prs":"";
  431. printall "sdx sync revision: $Revision\n";
  432. #
  433. # do the cookie check, unless -nocookie
  434. #
  435. if ( $NoCookie == 0 ) {
  436. printall "Checking for other instances of timebuild ...\n";
  437. $CookieName = "timebuild." . $ENV{ "SDXROOT" };
  438. $CookieName =~ s/[\:\\]/\./g;
  439. $CheckCookie = "TRUE"; # loop variable to see if we've acquired the cookie
  440. while ( $CheckCookie eq "TRUE" ) {
  441. # attempt to acquire the cookie
  442. $CookieRC = &cookie::CreateCookieQuiet( $CookieName );
  443. if ( $CookieRC ) {
  444. # we successfully created the cookie, we're the only instance of timebuild
  445. printall "No other timebuilds running, continuing ...\n";
  446. $CheckCookie = "FALSE";
  447. } else {
  448. # someone else has the cookie, there is another instance of timebuild running.
  449. printall "Other timebuilds are running, sleeping $CookieSleepDuration seconds ...\n";
  450. sleep( $CookieSleepDuration );
  451. }
  452. }
  453. }
  454. $rc = 0;
  455. for (@cmdlist) {
  456. chomp;
  457. s/\#.*$//;
  458. s/^\s+//;
  459. s/\s+$//;
  460. $skipchar = s/^\@//;
  461. #
  462. # replace any cmd variables
  463. #
  464. while (s/<<([^<]+)>>/$cmdvar{$1}/) {}
  465. #
  466. # Skip through the specified RESUME line
  467. #
  468. if (/^RESUME\s*/i) {
  469. if ($DoResume) {
  470. $DoResume = 0 if /^RESUME\s*(\Q$ResumeTag\E)$/i;
  471. $Flags{'resume'} = 1;
  472. }
  473. next;
  474. }
  475. next if $DoResume;
  476. #
  477. # Handle conditional execution of commands (before CHECKFATAL)
  478. #
  479. if (/^([!=])(\%{0,1})(\w+)%{0,1}\s*=(\S*)\s+(.*)$/i) {
  480. $argkey = lc $3;
  481. $argval = lc $4;
  482. $keyval = ($2 eq '%')? $ENV{$argkey} : $Flags{$argkey};
  483. $keyval = lc $keyval;
  484. printall ("Info: Picking up %$argkey%=$ENV{$argkey} from environment.\n") if $Verbose and !$Flags{$argkey} and $ENV{$argkey};
  485. next if $1 eq '=' and $keyval ne $argval;
  486. next if $1 eq '!' and $keyval eq $argval;
  487. $_ = $5;
  488. }
  489. elsif (/^([!=])(\%{0,1})(\w+)%{0,1}\s+(.*)$/i) {
  490. $argkey = lc $3;
  491. $keyval = ($2 eq '%')? $ENV{$argkey} : $Flags{$argkey};
  492. $keyval = lc $keyval;
  493. printall ("Info: Picking up %$argkey%=$ENV{$argkey} from environment.\n") if $Verbose and !$Flags{$argkey} and $ENV{$argkey};
  494. next if $1 eq '!' and $keyval;
  495. next if $1 eq '=' and not $keyval;
  496. $_ = $4;
  497. }
  498. #
  499. # SUCCESS - reset the current result code to 0
  500. #
  501. if (/^SUCCESS\s*$/i) {
  502. $rc = 0;
  503. next;
  504. }
  505. #
  506. # Handle CHECKBUILDERRORs
  507. # $rc is set to 0, and cmdlist parsing continues, if the
  508. # errors in the check build.err file matches those in build.err
  509. #
  510. if (/^CHECKBUILDERRORS\s*(.*)$/i) {
  511. next unless $rc;
  512. next unless -r $BuildCheckFileName;
  513. $foo = "Checking $BuildErrorFileName "
  514. . "against $BuildCheckFileName...\n";
  515. printall $foo;
  516. $r = compare ($BuildErrorFileName, $BuildCheckFileName);
  517. if ($r) {
  518. $foo = "Comparison failed. Build error will be fatal.\n";
  519. printall $foo;
  520. } else {
  521. #
  522. # No new build errors have occurred so reset $rc.
  523. #
  524. $foo = "Error file hasn't changed. Build errors ignored.\n";
  525. printall $foo;
  526. $rc = 0;
  527. }
  528. next;
  529. }
  530. #
  531. # Handle CHECKFILTERERRORs
  532. # $rc is set to 0, and cmdlist parsing continues, if there is
  533. # no filter.err file
  534. #
  535. if (/^CHECKFILTERERRORS\s*(.*)$/i) {
  536. if (-e $FilterErrFile) {
  537. printall "Filter failure detected see $FilterErrFile\n";
  538. $rc = 1;
  539. }
  540. next;
  541. }
  542. #
  543. # Handle CHECKFATALs
  544. #
  545. if (/^CHECKFATAL\s*(.*)$/i) {
  546. $checkcommand = $1;
  547. if ($rc) {
  548. $foo = "Failure of last command is fatal. Script aborted.\n";
  549. printall $foo;
  550. system "$checkcommand" if $checkcommand;
  551. last;
  552. }
  553. next;
  554. }
  555. #
  556. # Handle CHECKWARNs (like CHECKFATALs, but not fatal).
  557. #
  558. if (/^CHECKWARN\s*(.*)$/i) {
  559. $checkcommand = $1;
  560. if ($rc) {
  561. $foo = "WARNING: Last command failed.\n";
  562. printall $foo;
  563. system "$checkcommand" if $checkcommand;
  564. }
  565. next;
  566. }
  567. #
  568. # The built-in ECHO command
  569. #
  570. if (/^ECHO\s*(.*)$/i) {
  571. printall $1, "\n";
  572. next;
  573. }
  574. #
  575. # The built-in TESTFATAL command
  576. #
  577. if (/^TESTFATAL\s*(.*)$/i) {
  578. $rc = 1;
  579. printall $1, "\n";
  580. next;
  581. }
  582. #
  583. # The built-in QUIT command
  584. #
  585. if (/^QUIT\s*(.*)$/i) {
  586. printall "QUITTING: $1.\n";
  587. $rc = 0;
  588. last;
  589. }
  590. #
  591. # The loop over languages command
  592. #
  593. if (/^LANG\s*(.*)$/i) {
  594. @loop_langs = @Langs;
  595. $_ = $1;
  596. }
  597. if (@loop_langs) {
  598. my @procs;
  599. use Win32::Process;
  600. use Win32::IPC qw(wait_all wait_any);
  601. $then = time();
  602. # List the languages so that the called script can tell who else is running.
  603. (my $dir = $LangListFile) =~ s/\\[^\\]*$//;
  604. if ($dir !~ /^\s*$/ and !-d $dir) {
  605. if (system "mkdir $dir") {
  606. printall "ERROR: Unable to create dir $dir.\n";
  607. last;
  608. }
  609. }
  610. if (!open LLIST, ">$LangListFile") {
  611. printall "ERROR: Unable to write out language list.\n";
  612. last;
  613. }
  614. for my $lang (@loop_langs) { print LLIST "$lang\n"; }
  615. close LLIST;
  616. for my $lang (@loop_langs) {
  617. printall "Running for $lang: $_ -l:$lang\n" unless $skipchar;
  618. if (!$Fake) {
  619. my $proc;
  620. Win32::Process::Create($proc,
  621. $ENV{COMSPEC},
  622. "cmd /c " . "$_ -l:$lang",
  623. 1, # inherit handles, incl. STDIN, STDOUT
  624. CREATE_NEW_CONSOLE,
  625. ".");
  626. push @procs, $proc;
  627. }
  628. }
  629. if (!$Fake) {
  630. wait_all(@procs);
  631. }
  632. unlink $LangListFile or printall "WARNING: Unable to delete language list file.\n";
  633. if (not $skipchar and not $Fake) {
  634. $now = time();
  635. $t = $now - $then;
  636. ($h, $m, $s) = hms $t;
  637. printfall "Elapsed time: %5d seconds (%d:%02d:%02d) <%s>\n", $t, $h, $m, $s, "$_ for requested langs";
  638. }
  639. } else {
  640. #
  641. # Run the command
  642. #
  643. printall "Running: $_\n" unless $skipchar;
  644. $rc = 0;
  645. $then = time();
  646. $rc = system $_ unless $Fake;
  647. $now = time();
  648. if ($rc) {
  649. $foo = sprintf "FAILURE. Returned 0x%x: %s\n", $rc, $_;
  650. printall $foo;
  651. }
  652. if (not $skipchar and not $Fake) {
  653. $t = $now - $then;
  654. ($h, $m, $s) = hms $t;
  655. printfall "Elapsed time: %5d seconds (%d:%02d:%02d) <%s>\n", $t, $h, $m, $s, $_;
  656. }
  657. }
  658. }
  659. die $PGM, "Could not find RESUME <tag=$ResumeTag>\n" if $DoResume;
  660. if (not $Fake) {
  661. $t = time() - $begintime;
  662. ($h, $m, $s) = hms $t;
  663. printfall "Total Elapsed time: %5d seconds (%d:%02d:%02d)\n", $t, $h, $m, $s;
  664. }
  665. #
  666. # Close the logfile and copy it into the binplace directory.
  667. #
  668. close TIMEHISTFILE;
  669. close TIMELOGFILE;
  670. $src = $TimeLogFileName;
  671. $dst = $nttree . "\\build_logs\\";
  672. if (not $Fake and -r $src and -d $dst and -w $dst) {
  673. $rc = system("xcopy /y $src $dst");
  674. if ($rc) {
  675. $foo = sprintf "Warning... could not copy %s to %s\n", $src, $dst;
  676. print $PGM, $foo;
  677. }
  678. }
  679. #
  680. # Copy the sd change log to the binplace directory also.
  681. #
  682. $src = $ChangeLogFileName;
  683. if (not $Fake and -r $src and -d $dst and -w $dst) {
  684. $rc = system("xcopy /y $src $dst");
  685. if ($rc) {
  686. $foo = sprintf "Warning... could not copy %s to %s\n", $src, $dst;
  687. print $PGM, $foo;
  688. }
  689. }
  690. exit $rc;