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.

1039 lines
29 KiB

  1. # FileName: PopulateFromVBL.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. # Usage = PopulateFromVBL.pl [-force] [-vbl=vblreleasedir] [-nttree=nttreedir] [-symbols]
  8. #
  9. # Function: Populate missing files in nttreedir from vblreleaseddir so
  10. # 0) Verify that binplacedir and VBL are (compatible?) release directories
  11. # 1) Find the binplace.log output for both paths
  12. # 2) Figure out what projects were built in the nttree
  13. # 3) Generate a list of files that were built on VBL for the projectlist
  14. # 4) Output a list of files we should have built locally, but didn't
  15. # 5) If (4) is empty, or -force, populate missing files in nttreedir
  16. # from vblreleaseedir forall projects
  17. #
  18. # No files in nttreedir are overwritten from vblreleasedir
  19. # The checks for what should be there are not exact, because we rely only on
  20. # binplace.log entries -- and the VBL build may not exactly match the nttree build.
  21. #
  22. # [-force] -- do copying even if the nttree doesn't contain project files built in VBL
  23. # [-verbose] -- chatter while working
  24. # [-fake] -- don't do the actual copies
  25. # [-checkbinplace] -- note VBL files that are in binplace.log but not build.binlist
  26. # [-fulltargetok] -- run even if the target machine has built in all projects
  27. #
  28. #
  29. # VBLpath will be computed from BuildMachines.txt if not supplied either
  30. # on the command line, or in the VBL_RELEASE environment variable.
  31. #
  32. # If we are a build lab, we succeed without doing much.
  33. #
  34. # WARNING:
  35. # WARNING: make sure pathname comparisons are case insensitive. Either convert the case or do the
  36. # WARNING: comparisons like this:
  37. # WARNING: if ($foo =~ /^\Q$bar\E$/i) {}
  38. # WARNING: or if ($foo !~ /^\Q$bar\E$/i) {}
  39. # WARNING:
  40. #
  41. # BUGBUG: Still need to copy down the compressed directory, per Wade's request...
  42. # ... but I'm really hoping that this will translate into an opportunity not
  43. # ... to copy down the uncompressed version from the VBL... Or, as MarkL suggested,
  44. # ... I should uncompress the compressed version rather than copy it. I'd need to
  45. # ... validate this, maybe in postbuild on the VBL?
  46. $begintime = time();
  47. $VBLPathVariableName = 'VBL_RELEASE';
  48. $BuildMachinesFile = $ENV{ "RazzleToolPath" } . "\\BuildMachines.txt";
  49. $SdDotMapPathname = "sd.map";
  50. $LogFile = "build.populate";
  51. $BinListFile = "build.binlist";
  52. $TestFileName = "build.testpopulate";
  53. $CDDATAFileName = "cddata.txt";
  54. #
  55. # Build the complete list of non-root projects
  56. #
  57. @Projects = (public, mergedcomponents,
  58. admin, base, com, drivers, ds, enduser, inetcore, inetsrv,
  59. multimedia, net, printscan, sdktools, shell, termsrv, windows);
  60. for (@Projects) {
  61. $Project{$_} = 1;
  62. }
  63. #
  64. # Usage variables
  65. #
  66. $PGM='PopulateFromVBL: ';
  67. $Usage = $PGM . "Usage: PopulateFromVBL.pl [-force] [-vbl=vblreleasedir] [-nttree=nttreedir] [-symbols]\n";
  68. #
  69. # Get the current directory
  70. #
  71. open CWD, 'cd 2>&1|';
  72. $CurrDir = <CWD>;
  73. close CWD;
  74. chomp $CurrDir;
  75. $CurrDrive = substr($CurrDir, 0, 2);
  76. #
  77. # Check variables expected to be set in the environment.
  78. #
  79. $sdxroot = $ENV{'SDXROOT'} or die $PGM, "Error: SDXROOT not set in environment\n";
  80. $buildarch = $ENV{'_BuildArch'} or die $PGM, "Error: _BuildArch not set in environment\n";
  81. $computername = $ENV{'COMPUTERNAME'} or die $PGM, "Error: COMPUTERNAME not set in environment\n";
  82. $branchname = $ENV{'_BuildBranch'} or die $PGM, "Error: _BuildBranch not set in environment\n";
  83. $foo = $ENV{'NTDEBUG'} or die $PGM, "Error: NTDEBUG not set in environment\n";
  84. $dbgtype = 'chk';
  85. $dbgtype = 'fre' if $foo =~ /nodbg$/i;
  86. #
  87. # initialize argument variables
  88. #
  89. $Fake = $ENV{'POPULATEFROMVBL_FAKE'};
  90. $Verbose = $ENV{'POPULATEFROMVBL_VERBOSE'};
  91. $Compare = $ENV{'POPULATEFROMVBL_COMPARE'};
  92. $Progress = $ENV{'POPULATEFROMVBL_PROGRESS'};
  93. $Test = $ENV{'POPULATEFROMVBL_TEST'};
  94. $Symbols = $ENV{'POPULATEFROMVBL_SYMBOLS'};
  95. $SkipPats = $ENV{'POPULATEFROMVBL_SKIP'};
  96. $CDDataOnly = $ENV{'POPULATEFROMVBL_CDDATAONLY'};
  97. $Force = 0;
  98. $FullTargetOk = 0;
  99. $CheckBinplace = 0;
  100. #
  101. # Debug routines for printing out variables
  102. #
  103. sub gvar {
  104. for (@_) {
  105. print "\$$_ = $$_\n";
  106. }
  107. }
  108. #
  109. # print on the various files
  110. #
  111. sub printall {
  112. print TSTFILE @_ if $Test;
  113. print LOGFILE @_;
  114. print $PGM unless @_ == 1 and @_[0] eq "\n";
  115. print @_;
  116. }
  117. sub printfall {
  118. printf TSTFILE @_ if $Test;
  119. printf LOGFILE @_;
  120. print $PGM unless @_ == 1 and @_[0] eq "\n";
  121. printf @_;
  122. }
  123. #
  124. # Sub hms
  125. # Takes Argument time in seconds and returns as list of (hrs, mins, secs)
  126. #
  127. sub hms {
  128. $s = shift @_;
  129. $h = int ($s / 3600);
  130. $s -= 3600*$h;
  131. $m = int ($s / 60);
  132. $s -= 60*$m;
  133. return ($h, $m, $s);
  134. }
  135. #
  136. # signal catcher (at least this would work on unix)
  137. #
  138. sub catch_ctrlc {
  139. printall "Aborted.\n";
  140. die $PGM, "Error: Aborted.\n";
  141. }
  142. $SIG{INT} = \&catch_ctrlc;
  143. #
  144. # routine to fully qualify a pathname
  145. #
  146. sub fullyqualify {
  147. die $PGM . "Error: Internal error in fullpathname().\n" unless @_ == 1;
  148. $_ = @_[0];
  149. if (/\s/) { die $PGM, "Error: Spaces in pathnames not allowed: '", $_, "'\n"; }
  150. return $_ unless $_; # empty strings are a noop
  151. s/([^:])\\$/$1/; # get rid of trailing \
  152. while (s/\\\.\\/\\/) {} # get rid of \.\
  153. while (s/\\[^\\]+\\\.\.\\/\\/) {} # get rid of \foo\..\
  154. s/\\[^\\]+\\\.\.$/\\/; # get rid of \foo\..
  155. s/:[^\\]+\\\.\.$/:/; # get rid of x:foo\..
  156. s/([^:])\\\.$/$1/; # get rid of foo\.
  157. s/:\\\.$/:\\/; # get rid of x:\.
  158. s/:[^\\]+\\\.\.$/:/; # get rid of x:foo\..
  159. s/^$CurrDrive[^\\]/$CurrDir\\/i; # convert drive-relative on current drive
  160. if (/^[a-z]:\\/i) { return $_; } # full
  161. if (/^\\[^\\].*/) { return "$CurrDrive$_"; } # rooted
  162. if (/^\\\\[^\\]/) {
  163. # print $PGM, 'Warning: Use of UNC name bypasses safety checks: ', $_, "\n";
  164. return $_; # UNC
  165. }
  166. if (/^\.$/) { return "$CurrDir"; } # dot
  167. if (/^$CurrDrive\.$/i) { return "$CurrDir"; } # dot on current drive
  168. if (/^[^\\][^:].*/i) { return "$CurrDir\\$_"; } # relative
  169. if (/^([a-z]:)([^\\].*)/i) { $drp = $CurrDir; # this case handled above
  170. if ($1 ne $CurrDir) {
  171. # $drp = $ENV{"=$1"}; # doesn't work!
  172. die $PGM, "Error: Can't translate drive-relative pathnames: ", $_, "\n";
  173. }
  174. return "$drp\\$2"; # drive:relative
  175. }
  176. die $PGM, "Error: Unrecognized pathname format: $_\n";
  177. }
  178. #
  179. # Routine for exploding directory names into a list of components (for mkdir)
  180. #
  181. sub explodedir {
  182. my(@explodelist) = ();
  183. my(@components);
  184. my($path);
  185. for (@_) {
  186. $_ = shift;
  187. @components = split /\\/;
  188. push @components, "";
  189. $path = shift @components;
  190. for (@components) {
  191. push @explodelist, $path;
  192. $path = $path . "\\" . $_;
  193. }
  194. }
  195. return @explodelist;
  196. }
  197. #
  198. # Routine to copy a file -- avoiding win32::CopyFile
  199. #
  200. # BUGBUG: This doesn't work. sysread() seems broken.
  201. #
  202. #
  203. use Fcntl;
  204. sub populatecopy {
  205. my $writesize = 64*4096;
  206. my($src, $dst) = @_;
  207. my($infile, $outfile, $buf, $n, $r, $o);
  208. if (not sysopen INFILE, $src, O_RDONLY() | O_BINARY()) {
  209. return 0;
  210. }
  211. if (not sysopen OUTFILE, $dst, O_WRONLY() | O_CREAT() | O_TRUNC() | O_BINARY(), 0666) {
  212. close INFILE;
  213. return 0;
  214. }
  215. $r = 0; # need this to be defined in case INFILE is empty
  216. ERR: while ($n = sysread INFILE, $buf, $writesize) {
  217. last ERR unless defined $n;
  218. $o = 0;
  219. while ($n) {
  220. $r = syswrite OUTFILE, $buf, $n, $o;
  221. last ERR unless defined $r;
  222. $n -= $r;
  223. $o += $r;
  224. }
  225. }
  226. close INFILE;
  227. close OUTFILE;
  228. return 0 if not defined $n or not defined $r or $n != 0;
  229. return 1;
  230. }
  231. use File::Copy;
  232. use File::Compare;
  233. #
  234. # Process and validate arguments
  235. #
  236. for (@ARGV) {
  237. if (/^[\/\-]test$/i) { $Test++; next; }
  238. if (/^[\/\-]verbose$/i) { $Verbose++; next; }
  239. if (/^[\/\-]cddataonly$/i) { $CDDataOnly++; next; }
  240. if (/^[\/\-]compare$/i) { $Compare++; next; }
  241. if (/^[\/\-]symbols$/i) { $Symbols++; next; }
  242. if (/^[\/\-]force$/i) { $Force++; next; }
  243. if (/^[\/\-]fake$/i) { $Fake++; next; }
  244. if (/^[\/\-]fulltargetok$/i) { $FullTargetOk++; next; }
  245. if (/^[\/\-]vbl=(.+)$/i) { $VBL = $1; next; }
  246. if (/^[\/\-]nttree=(.+)$/i) { $NTTree = $1; next; }
  247. if (/^[\/\-]skip=(.+)$/i) { $SkipPats .= "$1;"; next; }
  248. if (/^[\/\-]?$/i) { die $Usage; }
  249. if (/^[\/\-]help$/i) { die $Usage; }
  250. if (/^[\/\-]checkbinplace$/i) { $CheckBinplace++; next; }
  251. die $Usage;
  252. }
  253. #
  254. # If we didn't get the NTTree directory from the command line,
  255. # get it from the _NTTREE environment variable.
  256. #
  257. $NTTree = $ENV{'_NTTREE'} unless $NTTree;
  258. #
  259. # Can only populate with the current directory the same as sdxroot.
  260. #
  261. die $PGM, "Error: Can only populate if CD <$CurrDir> is SDXROOT <$sdxroot>\n" unless $sdxroot =~ /^\Q$CurrDir\E$/io;
  262. $rc = system 'perl %sdxroot%\Tools\CombineDistributedBinplaceLogs.pl', "-nttree=$NTTree";
  263. die $PGM, "Error: CombineDistributedBinplaceLogs.pl failed.\n" if $rc;
  264. #
  265. # We always need to build a current binlist file -- unless it already exists.
  266. #
  267. $foo = "Creating binlist file with dir command.\n";
  268. print $PGM, $foo;
  269. $NTTreeBinListFile = "$NTTree\\build_logs\\$BinListFile";
  270. if (! -s $NTTreeBinListFile) {
  271. $rc = system "dir /b/s /a-d %_NTTREE% > $NTTreeBinListFile";
  272. die $PGM, "Error: Error building $NTTreeBinListFile: $!\n" if $rc;
  273. }
  274. #
  275. # If we didn't get the local target directory from the command line,
  276. # get it from the environment. If that fails, we parse BuildMachines.txt.
  277. #
  278. $VBL = $ENV{$VBLPathVariableName} unless $VBL;
  279. if ((not $VBL) || ($VBL =~ /^[\d\w_]+$/)) {
  280. $tbranchname = $branchname;
  281. $tbranchname = $VBL if $VBL =~ /^[\d\w_]+$/;
  282. $fname = $BuildMachinesFile;
  283. open BMFILE, $fname or die $PGM, "Error: Could not open: $fname\n";
  284. for (<BMFILE>) {
  285. s/\s+//g;
  286. s/;.*$//;
  287. next if /^$/;
  288. ($vblmach, $vblprime, $vblbranch, $vblarch, $vbldbgtype, $vbldl, $disttype, $alt_release ) = split /,/;
  289. #
  290. #BUGBUG:
  291. # Should this really come through the environment
  292. # variable that declares this to be a VBL?
  293. #
  294. if ($vblmach =~ /\Q$computername\E/io) {
  295. print $PGM, "Skipping populate because this is a VBL machine.\n";
  296. exit 0;
  297. }
  298. if ($vblarch =~ /\Q$buildarch\E/io and $vbldbgtype =~ /\Q$dbgtype\E/io
  299. and $vblbranch =~ /\Q$tbranchname\E/io
  300. and $disttype !~ /distbuild/i) {
  301. if ( defined $alt_release) {
  302. $VBL = $alt_release;
  303. last;
  304. }
  305. else {
  306. $dname = "\\\\$vblmach\\release";
  307. }
  308. opendir BDIR, "$dname\\" or die $PGM, "Error: Could not open directory: $dname\n";
  309. @reldirs = readdir BDIR;
  310. close BDIR;
  311. $rname = 0;
  312. $date = 0;
  313. for (@reldirs) {
  314. next unless /[0-9]+\.$vblarch$vbldbgtype\.$vblbranch\.(.+)$/io;
  315. ($date = $1, $rname = $_) unless $date gt $1
  316. or substr($date, 0, 2) eq '00' and substr($1, 0, 2) eq '99'; # Y2K trade-off
  317. }
  318. if (not $rname) {
  319. print $PGM, "Warning: No valid release shares found on $dname.\n";
  320. } else {
  321. $VBL = "$dname\\$rname";
  322. }
  323. last;
  324. }
  325. }
  326. close BMFILE;
  327. }
  328. die $PGM, "Error: Not a directory: ", $VBL, "\n" if $VBL and ! -d $VBL;
  329. die $Usage unless $NTTree;
  330. die $PGM, "Error: Not a directory: ", $NTTree, "\n" unless -d $NTTree;
  331. die $PGM, "Error: Not writable: ", $NTTree, "\n" unless -w $NTTree;
  332. $SkipPats =~ tr/@/^/;
  333. $SkipPats =~ s/;;+/;/g;
  334. $SkipPats =~ s/\\/\\\\/g;
  335. $SkipPats =~ s/\\\\\./\\./g;
  336. $SkipPats =~ s/^;//;
  337. $SkipPats =~ s/;$//;
  338. @SkipPatterns = split /;/, $SkipPats if $SkipPats;
  339. #
  340. # Fully qualify the pathnames
  341. #
  342. $VBL = fullyqualify($VBL) if $VBL;
  343. $NTTree = fullyqualify($NTTree);
  344. #
  345. # Open the logfile, and maybe the testfile
  346. #
  347. $foo = "$NTTree\\build_logs\\$LogFile";
  348. open LOGFILE, ">>$foo" or die $PGM, "Error: Could not create logfile: ", $foo, ": $!\n";
  349. open TSTFILE, ">$TestFileName" or die $PGM, "Error: Could not create testfile: ", $TestFileName, ": $!\n" if $Test;
  350. #
  351. # Verify that VBL and NTTree are compatible release directories
  352. # BUGBUG:
  353. # For now, this just means ensure they both have build_logs directories.
  354. # It might be nice to check that the builds are from the same branch, and the same main branch build, but ...
  355. #
  356. die $PGM . "Error: The nttree build_logs not found.\n" unless -d "$NTTree\\build_logs\\.";
  357. if ($VBL) {
  358. die $PGM . "Error: The VBL build_logs not found.\n" unless -d "$VBL\\build_logs\\.";
  359. printall "Populating $NTTree from VBL $VBL\n";
  360. }
  361. #
  362. # Process the CDDATA file to build a real copylist.
  363. #
  364. # BUGBUG: I put the code in to do this (if the flag is set), but
  365. # I don't understand how Wade and Mike thought I could use
  366. # this data to automatically trim what gets copied from the VBL.
  367. #
  368. if ($VBL) {
  369. $CDDATAFileName = "$VBL\\build_logs\\$CDDATAFileName";
  370. printall $PGM . "Warning: Could not open $CDDATAFileName: $!\n" unless -r $CDDATAFileName;
  371. @CDData = ();
  372. if ($CDDataOnly) {
  373. open CDDATA, $CDDATAFileName or die $PGM, "Error: Could not open: ", $CDDATAFileName, ": $!\n";
  374. for (<CDDATA>) {
  375. chomp;
  376. s/\s+//g;
  377. s/;.*//;
  378. next if /^$/;
  379. ($name, $signed, $prodlist, $iscompressed, $isdriver, $isprinter, $dosnet)
  380. = /(.*)=([tf]):([a-z]+):([tf]):([tf]):([tf]):([tf])/;
  381. printall $PGM . "WARNING: failed to parse cddata line: $_\n" unless $name;
  382. next unless $name;
  383. $CDData{$name}++;
  384. }
  385. close CDDATA;
  386. }
  387. }
  388. #
  389. # Alert that we are skipping certain classes of files
  390. #
  391. printall "Skipping various symbols directories.\n" unless $Symbols;
  392. printall "Skipping delayload directory.\n";
  393. printall "Skip Patterns:\n";
  394. for (@SkipPatterns) {
  395. $pat = $_;
  396. $pat =~ s/\\\\/\\/g;
  397. printall "Skip /$pat/\n";
  398. }
  399. #
  400. # BUGBUG:
  401. # At some point, there will be a file in build_logs which we tell use
  402. # interesting details about a build. We will want to dump out the contents
  403. # of this file for both VBL and NTTree, so the user can see what they
  404. # are getting themselves into.
  405. #
  406. #
  407. # Read in the VBL and NTTree binplace logs and process them
  408. #
  409. open BINPLACE, "$NTTree\\build_logs\\binplace.log"
  410. #or open BINPLACE, "$NTTree\\binplace.log"
  411. or die $PGM, "Error: Could not open: ", "$NTTree\\build_logs\\binplace.log", "\n";
  412. $nignored = 0;
  413. for (<BINPLACE>) {
  414. $whichline++;
  415. tr/A-Z/a-z/;
  416. $skipline = 0;
  417. # First test skips case where NTTree is under SDXROOT and there are binplace records (thanks to SCP)
  418. if (/^\Q$NTTree\E\\/io) {
  419. $skipline = 1;
  420. } elsif (/^\Q$sdxroot\E\\([^\\]+)\\([^\s]+)\\([^\\\s]*)\s+/io) {
  421. $project=$1; $relpath=$2; $filename=$3;
  422. } else {
  423. $skipline = 1;
  424. }
  425. if ($skipline) {
  426. print TSTFILE "Ignored TARG binplace record at line $whichline: ", $_ if $Test;
  427. $nignored++;
  428. if ($Verbose && $nignored <= 10) {
  429. print LOGFILE $PGM . "Ignored TARG binplace record at line $whichline: ", $_;
  430. print LOGFILE $PGM . "...\n" if $nignored == 10;
  431. }
  432. next;
  433. }
  434. $project =~ tr/A-Z/a-z/;
  435. $relpath =~ tr/A-Z/a-z/;
  436. $filename =~ tr/A-Z/a-z/;
  437. if (not $Project{$project}) {
  438. $msg = $PGM . "Error: NTTREE: unknown project '$project' at line $whichline: $_\n";
  439. if ($Fake) { warn $msg; } else { die $msg; }
  440. next;
  441. }
  442. $TargCounts{$project}++;
  443. push @{"T_" . $project . "_binplaced"}, "$relpath\\$filename";
  444. }
  445. close BINPLACE;
  446. if ($Verbose) {
  447. $total = 0;
  448. printall "\n";
  449. printall "NTTree project counts\n";
  450. for (@Projects) {
  451. printfall " %5d %s\n", $TargCounts{$_}, $_;
  452. $total += $TargCounts{$_};
  453. }
  454. printall "-----------------\n";
  455. printfall " %5d TOTAL\n", $total;
  456. printfall " %5d records ignored\n\n", $nignored if $nignored;
  457. }
  458. #
  459. # If files have been binplaced in all the projects, we assume all projects are built locally, and
  460. # don't try to populate -- unless explictly told to do so by the -fulltargetbuildok
  461. #
  462. if (not $FullTargetOk) {
  463. $TargetIsFullBuild = 1;
  464. for (@Projects) {
  465. next if /public/;
  466. next if $TargCounts{$_};
  467. $TargetIsFullBuild = 0;
  468. }
  469. if ($TargetIsFullBuild) {
  470. printall "Not run because $NTTree should be a full build of all projects.\n";
  471. close LOGFILE;
  472. close TSTFILE if $Test;
  473. exit 0;
  474. }
  475. }
  476. die $PGM, "Error: There was trouble finding a VBL.\n" unless $VBL;
  477. open BINPLACE, "$VBL\\build_logs\\binplace.log"
  478. #or open BINPLACE, "$VBL\\binplace.log"
  479. or die $PGM, "Error: Could not open: ", "$VBL\\build_logs\\binplace.log", "\n";
  480. $nignored = 0;
  481. $whichline = 0;
  482. for (<BINPLACE>) {
  483. $whichline++;
  484. tr/A-Z/a-z/;
  485. #
  486. # BUGBUG: assumes all VBLs build under an sdxroot something like x:\foo
  487. #
  488. if (/^[a-z]:\\[^\\]+\\([^\\]+)\\([^\s]+)\\([^\\\s]*)\s+/io) { $project=$1; $relpath=$2; $filename=$3; }
  489. else {
  490. print TSTFILE "Ignored VBL binplace record at line $whichline: ", $_ if $Test;
  491. $nignored++;
  492. if ($Verbose && $nignored <= 10) {
  493. print LOGFILE $PGM, "Ignored VBL binplace record at line $whichline: ", $_;
  494. print LOGFILE $PGM, "...\n" if $nignored == 10;
  495. }
  496. next;
  497. }
  498. $project =~ tr/A-Z/a-z/;
  499. $relpath =~ tr/A-Z/a-z/;
  500. $filename =~ tr/A-Z/a-z/;
  501. die $PGM . "Error: VBL: unknown project at line $whichline: " . $_ . "\n" unless $Project{$project};
  502. $VBLCounts{$project}++;
  503. push @{"V_" . $project . "_binplaced"}, "$relpath\\$filename";
  504. }
  505. close BINPLACE;
  506. #
  507. # Check that VBL built stuff everywhere, except maybe 'public'.
  508. #
  509. for (@Projects) {
  510. next if /public/;
  511. if (not $VBLCounts{$project}) {
  512. printall "VBL did not build anything in ", $_, "\n";
  513. $fatal++;
  514. }
  515. }
  516. if ($Verbose or $fatal) {
  517. $total = 0;
  518. printall "\n";
  519. printall "VBL project counts\n";
  520. for (@Projects) {
  521. printfall " %5d %s\n", $VBLCounts{$_}, $_;
  522. $total += $VBLCounts{$_};
  523. }
  524. printall "-----------------\n";
  525. printfall " %5d TOTAL\n", $total;
  526. printfall " %5d records ignored\n\n", $nignored if $nignored;
  527. }
  528. die $PGM, "Error: VBL release seems bad.\n" if $fatal;
  529. #
  530. # Analyze what got built on the VBL versus the local tree
  531. #
  532. # For each project that we built locally, see if there are any files
  533. # in the VBL tree that we are missing.
  534. #
  535. $NotLocallyPlaced = 0;
  536. %VBLhash = ();
  537. %Targhash = ();
  538. for (@Projects) {
  539. next if /public/ or not $TargCounts{$_};
  540. $project = $_;
  541. #
  542. # Build a hash table for the VBL files, and check target files.
  543. # and vice-versa...
  544. #
  545. for (@{"V_" . $project . "_binplaced"}) {
  546. $VBLhash{$_} = 1;
  547. }
  548. for (@{"T_" . $project . "_binplaced"}) {
  549. printall 'Warning: non-VBL file binplaced on target: ', $_, "\n" unless $VBLhash{$_};
  550. $Targhash{$_} = 1;
  551. }
  552. for (@{"V_" . $project . "_binplaced"}) {
  553. next if $Targhash{$_};
  554. printall 'WARNING: VBL file not binplaced on target: ', $_, "\n";
  555. $NotLocallyPlaced++;
  556. }
  557. }
  558. if ($NotLocallyPlaced and not $Force) {
  559. die $PGM, "Error: ", $NotLocallyPlaced, " binplaced VBL files were not binplaced into ", $NTTree, "\n";
  560. }
  561. #
  562. # Thats the checks. Now we just have to do the actual populate.
  563. #
  564. #
  565. # Do a directory listing
  566. # Build build.binlist for NTTREE
  567. # Read in the build.binlist files for NTTree.
  568. # Read in the build.binlist files for the VBL.
  569. #
  570. open BINLIST, "$NTTreeBinListFile"
  571. or die $PGM, "Error: Could not open: ", "$NTTreeBinListFile", "\n";
  572. $whichline = 0;
  573. for (<BINLIST>) {
  574. #
  575. #
  576. $whichline++;
  577. tr/A-Z/a-z/;
  578. chomp;
  579. if (/^\Q$NTTree\E\\([^\s]*)$/io) {
  580. $relpath = $1;
  581. #
  582. # ignore symbol and other directories
  583. #
  584. if (not $Symbols) {
  585. next if /\\symbolcd\\/i;
  586. next if /\\symbols\.pri\\/i;
  587. next if /\\symbols\\/i;
  588. next if /\\scp_wpa\\/i;
  589. # instead we use $SkipPatterns
  590. # next if $relpath =~ /^mstools\\/i;
  591. # next if $relpath =~ /^idw\\/i;
  592. # next if $relpath =~ /^dump\\/i;
  593. # next if $relpath =~ /^clients\\/i;
  594. }
  595. #
  596. # ignore delayload directory
  597. #
  598. next if /\\delayload\\/i;
  599. #
  600. # ignore HelpAndSupportServices directory
  601. #
  602. next if /\\HelpAndSupportServices\\/i;
  603. #
  604. # ignore paths that match skip patterns
  605. #
  606. $skiphit = 0;
  607. for (@SkipPatterns) {
  608. $skiphit = $relpath =~ /$_/i;
  609. $spat = $_;
  610. last if $skiphit;
  611. }
  612. print TSTFILE "TARG: skipping $relpath\n" if $Test and $skiphit;
  613. next if $skiphit;
  614. $TargFileList{$relpath} = 1;
  615. } else {
  616. $fatal++;
  617. printall "Could not parse target build.binplace at line ", $whichline, ": ", $_, "\n";
  618. }
  619. }
  620. close BINLIST;
  621. #
  622. # BUGBUG... in a few releases these will all be in build_logs
  623. #
  624. $foo = "$VBL\\build_logs\\$BinListFile";
  625. open BINLIST, $foo
  626. or open BINLIST, "$VBL\\$BinListFile"
  627. or die $PGM, "Error: Could not open: ", $foo, "\n";
  628. $whichline = 0;
  629. for (<BINLIST>) {
  630. $whichline++;
  631. tr/A-Z/a-z/;
  632. chomp;
  633. if (/^[a-z]:\\[^\\]+\\([^\s]*)$/io) {
  634. $relpath = $1;
  635. #
  636. # skip log files found in VBL.
  637. #
  638. next if /\\build\.[^\\]+$/i;
  639. next if /\\build_logs\\/i;
  640. #
  641. # ignore symbol directories
  642. #
  643. if (not $Symbols) {
  644. next if /\\symbolcd\\/i;
  645. next if /\\symbols\.pri\\/i;
  646. next if /\\symbols\\/i;
  647. # instead we use $SkipPatterns
  648. # next if $relpath =~ /^mstools\\/i;
  649. # next if $relpath =~ /^idw\\/i;
  650. # next if $relpath =~ /^dump\\/i;
  651. # next if $relpath =~ /^clients\\/i;
  652. }
  653. #
  654. # ignore delayload directory
  655. #
  656. next if /\\delayload\\/i;
  657. #
  658. # ignore HelpAndSupportServices directory
  659. #
  660. next if /\\HelpAndSupportServices\\/i;
  661. #
  662. # ignore paths that match skip patterns
  663. #
  664. $skiphit = 0;
  665. for (@SkipPatterns) {
  666. $skiphit = $relpath =~ /$_/i;
  667. $spat = $_;
  668. last if $skiphit;
  669. }
  670. print TSTFILE "VBL: skipping $relpath\n" if $Test and $skiphit;
  671. next if $skiphit;
  672. $VBLFileList{$relpath} = 1;
  673. } else {
  674. $fatal++;
  675. printall "Could not parse VBL build.binplace at line ", $whichline, ": ", $_, "\n";
  676. }
  677. }
  678. close BINLIST;
  679. die $PGM, "Error: Fatal error parsing build.binplace.\n" if $fatal;
  680. #
  681. # Optionally note VBL files that were not binplaced.
  682. #
  683. if ($CheckBinplace) {
  684. printall "Checking non-binplaced VBL files\n";
  685. for (@VBLFileList) {
  686. next unless $VBLhash{$_};
  687. printall "Info: Non-binplaced VBL file: ", $_, "\n";
  688. }
  689. }
  690. if ($Test) {
  691. print TSTFILE "#VBLhash=", scalar keys %VBLhash, " #Targhash=", scalar keys %Targhash, "\n";
  692. print TSTFILE "#VBLFileList=", scalar keys %VBLFileList, " #TargFileList=", scalar keys %TargFileList, "\n";
  693. }
  694. #
  695. # Generate list of files to copy (i.e. every file in VBLFileList not in TargFileList).
  696. #
  697. printall "FAKING -- NO COPYING ACTUALLY BEING DONE\n" if $Fake;
  698. $preptime = time();
  699. $TotalCount = scalar keys %VBLFileList;
  700. $ToCopy = $TotalCount - keys %TargFileList;
  701. if ($TotalCount < 1000 or $ToCopy < 0) {
  702. printall "ERROR: Something wrong with VBL build.binlist -- only $TotalCount files.\n";
  703. exit 1;
  704. }
  705. $CopyCount = 0;
  706. $NonCopyCount = 0;
  707. $CopyBytes = 0;
  708. # 12/28/2000 - added by jonwis
  709. #
  710. # Special code for SxS goop:
  711. # - Copies down the vbl's binplace logs to $NTTree\\build_logs\\$(binplace file name root)-vbl.log-sxs
  712. # This ensures that the sxs wfp updating code will actually pick up the vbl's binplaced assemblies
  713. # as well as assemblies that the user has created.
  714. $vblsxslogs = "$VBL\\build_logs\\binplace*.log-sxs";
  715. for (glob($vblsxslogs)) {
  716. $orig = $_;
  717. s/.*\\(.*)(\.log-sxs)/$1-vbl$2/;
  718. copy ($orig, "$NTTree\\build_logs\\$_") or die "Can't copy down vbl's WinFuse sxs list [$orig]?";
  719. $atleastonesxslogexisted = true;
  720. }
  721. die "No WinFuse build logs exist on build server, can't continue" unless $atleastonesxslogexisted;
  722. printall "Copying $ToCopy files from VBL\n";
  723. for (keys %VBLFileList) {
  724. if ($TargFileList{$_}) {
  725. $NonCopyCount++;
  726. next;
  727. }
  728. $VBfile = "$VBL\\$_";
  729. $NTfile = "$NTTree\\$_";
  730. #
  731. # We try to create each directory the first time we see it, just in case.
  732. #
  733. $dir = $_;
  734. $r = $dir =~ s/\\[^\\]+$//;
  735. if ($r) {
  736. @dirs = explodedir $dir;
  737. for (@dirs) {
  738. $mdname = "$NTTree\\$_";
  739. next if $seencount{$_}++ or -d $mdname;
  740. $r = mkdir $mdname, 0777;
  741. if (not $r) {
  742. printall $PGM . "ERROR: mkdir $mdname FAILED: $!\n";
  743. }
  744. }
  745. }
  746. $CopyCount++;
  747. if ($Fake) {
  748. print LOGFILE "Faking: copy $VBfile $NTfile\n";
  749. } else {
  750. #
  751. # Do copy.
  752. #
  753. # populatecopy seems to be faster than copy, but what we should
  754. # really get is a parallel copy.
  755. #
  756. # copy has been used more than populatecopy because the latter wasn't
  757. # using O_BINARY when opening the files. populatecopy seems to work fine now,
  758. # but it is only 9% faster -- so we'll stick with copy.
  759. #
  760. # $r = populatecopy ($VBfile, $NTfile);
  761. $r = copy ($VBfile, $NTfile);
  762. print TSTFILE "Copy<$r>: $VBfile -> $NTfile\n" if $Test;
  763. if (not $r) {
  764. printall "FAILED: copy $VBfile $NTfile: $!\n";
  765. } else {
  766. $t = -s $NTfile;
  767. $v = -s $VBfile;
  768. if ($v != $t) {
  769. printall "SIZE ERROR $_: NTTree=$t VBL=$v\n";
  770. }
  771. $CopyBytes += $t;
  772. }
  773. #
  774. # Do comparison, if requested.
  775. #
  776. if ($Compare) {
  777. $r = compare ($VBfile, $NTfile);
  778. if ($r) {
  779. printall "COMPARSION ERROR <$r>: $VBfile $NTfile: $!\n";
  780. }
  781. }
  782. #
  783. # Mark progress (if requested)
  784. # Estimated completion is pretty bogus
  785. # The adaptive timing of updates sort of works. At least
  786. # we aren't checking the time a lot.
  787. #
  788. $datarate = 1024*1024;
  789. if (not $Fake and $Progress) {
  790. if ($CopyBytes > $lastcopybytes + 5*$datarate # every 5 secs
  791. or $CopyCount > $lastcopycount + 100) { # or every 100 files
  792. $lasttime = $preptime unless $lasttime;
  793. $newtime = time();
  794. $datarate = ($CopyBytes-$lastcopybytes)/($newtime - $lasttime);
  795. $esttotalbytes = $CopyBytes * ($ToCopy / $CopyCount);
  796. $eta = ($esttotalbytes - $CopyBytes) / $datarate;
  797. ($h0, $m0, $s0) = hms $eta;
  798. $foo = sprintf "Status: %5dMB (%5d of %5d files) copied (%%%5.2f)"
  799. . " %7.2f KB/S estimated complete in %d:%02d:%02d \r",
  800. $CopyBytes/1024/1024,
  801. $CopyCount, $ToCopy,
  802. 100 * $CopyCount / $ToCopy,
  803. $datarate/1024, $h0, $m0, $s0;
  804. print $foo;
  805. if ($Test) {
  806. $foo =~ s/\r/\n/;
  807. print TSTFILE $foo;
  808. }
  809. $lastcopybytes = $CopyBytes;
  810. $lastcopycount = $CopyCount;
  811. $lasttime = $newtime;
  812. }
  813. }
  814. }
  815. }
  816. printf "\n";
  817. $t0 = $preptime - $begintime;
  818. $t1 = time() - $preptime;
  819. ($h0, $m0, $s0) = hms $t0;
  820. ($h1, $m1, $s1) = hms $t1;
  821. ($h2, $m2, $s2) = hms ($t0 + $t1);
  822. if (not $Fake) {
  823. $KB = $CopyBytes/1024;
  824. $MB = $KB/1024;
  825. $kbrate = $KB/$t1 unless not $t1;
  826. printfall "Populated $NTTree with $CopyCount files (%4.0f MB)"
  827. . " from $VBL [%7.2f KB/S]\n", $MB, $kbrate;
  828. }
  829. printall "NTTree had $NonCopyCount non-replaced files. VBL total files were $TotalCount.\n";
  830. printfall "Preparation time %5d secs (%d:%02d:%02d)\n", $t0, $h0, $m0, $s0;
  831. printfall "CopyFile time %5d secs (%d:%02d:%02d)\n", $t1, $h1, $m1, $s1;
  832. printfall "TotalTime time %5d secs (%d:%02d:%02d)\n", $t0+$t1, $h2, $m2, $s2;
  833. #
  834. # Return an error if we were faking so timebuild doesn't proceed.
  835. #
  836. close LOGFILE;
  837. close TSTFILE if $Test;
  838. exit $Fake;