Leaked source code of windows server 2003
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.

2243 lines
79 KiB

  1. # =========================================================================
  2. # Name: UpdFX.pl
  3. # Owner: RickKr
  4. # Purpose: Update one or more netfx layouts in this depot
  5. # History:
  6. # 02/23/01, RickKr: Created.
  7. # 03/08/01, RickKr: Added logic to determine layout variants of each file,
  8. # Simplified some error messages.
  9. # 03/30/01, RickKr: Added support for other layouts,
  10. # Added /from option.
  11. # 03/30/01, RickKr: Added editing of dirs file and sync of qcmp tool.
  12. # 03/30/01, RickKr: Updated testing instructions.
  13. # 05/29/01, RickKr: Fixed problem with dot releases.
  14. # 05/29/01, RickKr: Changed default source location.
  15. # 06/01/01, RickKr: Use symchk to figure out which files belong in symbad.txt,
  16. # Exclude netfx.cab/ddf from add/edit/remove lists,
  17. # Binplace ndp files to the netfx subdir.
  18. # 06/06/01, RickKr: Don't mess with inx file anymore, handle ddf files,
  19. # better output for symbol errors.
  20. # 06/08/01, RickKr: Changed default source location,
  21. # Get cab name from ddf template file,
  22. # Disable changes to symbad.txt.
  23. # 06/08/01, RickKr: Allow explicit specification of bld, lang, or cpu.
  24. # 06/08/01, RickKr: Exclude PDB files from datafile edits.
  25. # (See "http://dbg/symbols/symbols_ase.html#What to check in" for more info.)
  26. # 06/08/01, RickKr: Exclude cab/ddf from datafile edits.
  27. # 06/12/01, RickKr: Added /docabs, simplified some error messages.
  28. # 06/21/01, RickKr: Fixed usage message.
  29. # 08/21/01, RickKr: VS7-300525: OCM: long file names on 3 specific files already exist in Whistler build system and cause a conflict.
  30. # 08/22/01, RickKr: Changed default source location.
  31. # 08/23/01, RickKr: Allow either type of source location.
  32. use UpdFX;
  33. use Text::Tabs;
  34. use Cwd;
  35. # -------------------------------------------------------------------------
  36. # Module constants
  37. # -------------------------------------------------------------------------
  38. my %mhcScriptUsage =
  39. (
  40. "usage" =>
  41. [
  42. "UpdFX [/? | /help]",
  43. "UpdFX /update:<####> [/from:<path>] [/bld:<all|rtl|fcd>] [/cpu:<all|x86|i64>] [/lang:<all|<TLA>>] [/ignore_err]",
  44. "UpdFX /submit",
  45. "UpdFX /revert",
  46. "UpdFX /docabs [/bld:<all|rtl|fcd>] [/cpu:<all|x86|i64>]",
  47. ],
  48. "notes" =>
  49. [
  50. "/update\t- Updates files in your workspace but does not submit the changes",
  51. "/submit\t- Submits the changes made with /update",
  52. "/revert\t- Reverts the changes made with /update",
  53. "/docabs\t- Creates setup cabs",
  54. "",
  55. "- You must define SDXROOT and run this script from a RAZZLE window.",
  56. "- If an optional arg is not specified, the value for the arg is 'all'.",
  57. "- Args can be specified with the fewest chars that will uniquely identify them.",
  58. ],
  59. "args" =>
  60. {
  61. "valid" => #value for each entry is a regex that can be used to check the user-supplied value
  62. {
  63. "update" => "\\d+|\\d+\\.\\d+",
  64. "submit" => "",
  65. "revert" => "",
  66. "docabs" => "",
  67. "from" => ".+",
  68. "bld" => "all|rtl|fcd",
  69. "cpu" => "all|x86|i64",
  70. "lang" => "all|[a-zA-Z]{3}",
  71. "ignore_err"=> "",
  72. },
  73. "required" =>
  74. [
  75. "update|submit|revert|docabs",
  76. ],
  77. },
  78. );
  79. my %mhcDepotPath = #maps layouts to their depot locations
  80. (
  81. "x86/rtl" => "binary_release\\i386\\fre",
  82. "x86/fcd" => "binary_release\\i386\\chk",
  83. "i64/rtl" => "binary_release\\ia64\\fre",
  84. "i64/fcd" => "binary_release\\ia64\\chk",
  85. );
  86. my %mhcDepotNode = #maps devdiv path nodes to winxp path nodes
  87. (
  88. "x86" => "i386",
  89. "i64" => "ia64",
  90. "rtl" => "fre",
  91. "fcd" => "chk",
  92. );
  93. my %mhcSrcFileList = #maps file variants to a filelist section name in the sources datafile
  94. (
  95. "---/---" => "MISCFILES = \\",
  96. "x86/rtl" => "!IF (\$(FREEBUILD) && \$(386))",
  97. "x86/fcd" => "!IF (! \$(FREEBUILD) && \$(386))",
  98. "i64/rtl" => "!IF (\$(FREEBUILD) && \$(IA64))",
  99. "i64/fcd" => "!IF (! \$(FREEBUILD) && \$(IA64))",
  100. );
  101. my @mscLayoutKeys = #used to sequence %mhcSrcFileList ops
  102. (
  103. "---/---",
  104. "x86/rtl",
  105. "x86/fcd",
  106. "i64/rtl",
  107. "i64/fcd",
  108. );
  109. my $mscNetFxDdfFileName = "netfx.ddf"; #name of the ddf file we use/update/create
  110. my $mscSymsRaidNum = "VS#218857"; #raid number for binaries with no symbols (they cause binplace errors)
  111. my $mscSymChk_EXE = "symchk.exe"; #to determine which binaries have symbol problems
  112. # default source location
  113. my $mscDefSrcRoot =
  114. "\\\\cpvsbuild\\drops\\v7.0evewin\\layouts";
  115. #Keys to the summary hash
  116. my $mscKeyAdd = "Added"; #layout files added
  117. my $mscKeyEdit = "Edited"; #data files edited
  118. my $mscKeyChange = "Changed"; #layout files changed
  119. my $mscKeyRemove = "Removed"; #layout files removed
  120. my $mscKeyFailure = "Failures"; #failures with add, edit, change, or remove
  121. # -------------------------------------------------------------------------
  122. # Module variables
  123. # -------------------------------------------------------------------------
  124. my $msQCmp_EXE; #used for quick binary compares
  125. my $msSdxRoot; #path to the root of the sdx workspace
  126. my $msNetFxRoot; #path to the root of the netfx workspace
  127. my $msNetFxDirsFileSpec; #spec for the netfx dirs file (dirs)
  128. my $msNetFxSourcesFileSpec; #spec for the netfx sources file (sources)
  129. my $msBinplaceDataFileSpec; #spec for the binplace data file (placefil.txt)
  130. my $msBinplaceSymsFileSpec; #spec for another binplace data file (symbad.txt)
  131. my @msTemplateDdfText; #contents of the template ddf file
  132. my @msExcludeFileNames = #files to exclude from data file edits and sd delete ops
  133. (
  134. $mscNetFxDdfFileName,
  135. );
  136. my @msBinplaceExcludes = #files to exclude from binplace data file edits--see VS7-300525
  137. (
  138. "c_g18030.dll",
  139. "cvtres.exe",
  140. "System.dll",
  141. );
  142. my $msAllCpusMask; #mask formed by or'ing all cpus variants together
  143. my $mnAllLayouts; #count of layouts that will exist after update
  144. my %mhSrcPathSpec; #maps layouts to their source locations
  145. my %mhRealFileName; #maps lowercased-filenames to the actual names
  146. my %mhFileVariants; #records layout variants of files
  147. my %mhParsedArgs; #parsed and validated script args
  148. my %mhSummary = #summary of update actions
  149. (
  150. $mscKeyAdd => [],
  151. $mscKeyEdit => [],
  152. $mscKeyChange => [],
  153. $mscKeyRemove => [],
  154. $mscKeyFailure => [],
  155. );
  156. # -------------------------------------------------------------------------
  157. # Data Access Helper Routines
  158. # -------------------------------------------------------------------------
  159. # use these with the keys in %mhcDepotPath
  160. sub UpdFX_Cpu {return (split(/\//, $_[0]))[0];}
  161. sub UpdFX_Bld {return (split(/\//, $_[0]))[1];}
  162. # this identifies a datafile
  163. sub UpdFX_Dat {return ("ARRAY" eq ref($_[0]));}
  164. # -------------------------------------------------------------------------
  165. # If no args are present or help was requested, show help and get out
  166. # -------------------------------------------------------------------------
  167. if ((! @ARGV) || (_DoesHelpArgExist(\@ARGV)))
  168. {
  169. UpdFX_ShowHelp();
  170. }
  171. # -------------------------------------------------------------------------
  172. # Else update the layouts
  173. # -------------------------------------------------------------------------
  174. elsif (UpdFX_Init(@ARGV))
  175. {
  176. my $bSucceeded = $FALSE;
  177. if (! UpdFX_GetArgs(@ARGV))
  178. {
  179. UpdFX_ShowHelp();
  180. }
  181. elsif (UpdFX_GetResources())
  182. {
  183. $bSucceeded = UpdFX_DoTasks();
  184. }
  185. UpdFX_Exit($bSucceeded);
  186. }
  187. # =========================================================================
  188. # UpdFX_Init()
  189. #
  190. # Purpose:
  191. # Execute startup tasks
  192. # Inputs:
  193. # @sScriptArgs Args passed to the script
  194. # Outputs:
  195. # Returns $TRUE for success, $FALSE for failure
  196. # Dependencies:
  197. # None
  198. # Notes:
  199. # =========================================================================
  200. sub UpdFX_Init
  201. {
  202. my (@sScriptArgs) = @_;
  203. _RequireArgument(@sScriptArgs, "\@sScriptArgs");
  204. #Make sure prereqs are met
  205. $msSdxRoot = $ENV{"SDXROOT"};
  206. if (! defined($msSdxRoot))
  207. {
  208. return (_Error("You must define SDXROOT and run this script from a RAZZLE window"));
  209. }
  210. if (! defined($ENV{"RazzleToolPath"}))
  211. {
  212. return (_Error("You must run this script from a RAZZLE window"));
  213. }
  214. #Make sure user hasn't redirected input or output
  215. if (! (-t STDIN && -t STDOUT))
  216. {
  217. return (_Error("This script cannot be used with redirected input or output"));
  218. }
  219. #Make sure the data in related structures is kept in sync
  220. my $sAssertText;
  221. $sAssertText = "\%mhcDepotPath and \%mhcSrcFileList are in sync";
  222. foreach my $sLayoutKey (keys(%mhcDepotPath))
  223. {
  224. _Assert($mhcSrcFileList{$sLayoutKey}, $sAssertText);
  225. }
  226. foreach my $sLayoutKey (keys(%mhcSrcFileList))
  227. {
  228. if ($sLayoutKey !~ /---/)
  229. {
  230. _Assert($mhcDepotPath{$sLayoutKey}, $sAssertText);
  231. }
  232. }
  233. $sAssertText = "\%mhcSrcFileList and \@mscLayoutKeys are in sync";
  234. foreach my $sLayoutKey (keys(%mhcSrcFileList))
  235. {
  236. _Assert(0 < grep(/$sLayoutKey/, @mscLayoutKeys), $sAssertText);
  237. }
  238. foreach my $sLayoutKey (@mscLayoutKeys)
  239. {
  240. _Assert($mhcSrcFileList{$sLayoutKey}, $sAssertText);
  241. }
  242. return ($TRUE);
  243. }
  244. # =========================================================================
  245. # UpdFX_GetArgs()
  246. #
  247. # Purpose:
  248. # Parse and validate script args
  249. # Inputs:
  250. # @sScriptArgs Args passed to the script
  251. # Outputs:
  252. # Returns $TRUE for success, $FALSE for failure
  253. # Dependencies:
  254. # None
  255. # Notes:
  256. # =========================================================================
  257. sub UpdFX_GetArgs
  258. {
  259. my (@sScriptArgs) = @_;
  260. my @scValidArgs = keys(%{$mhcScriptUsage{"args"}{"valid"}});
  261. my @scRequiredArgs = @{$mhcScriptUsage{"args"}{"required"}};
  262. _RequireArgument(@sScriptArgs, "\@sScriptArgs");
  263. if (! _ParseArgs(\%mhParsedArgs, \@sScriptArgs, \@scValidArgs))
  264. {
  265. return ($FALSE); # error already output
  266. }
  267. my @sSpecifiedArgs = keys(%mhParsedArgs);
  268. foreach my $sRequiredArg (@scRequiredArgs)
  269. {
  270. if (0 == grep(/$sRequiredArg/, @sSpecifiedArgs))
  271. {
  272. return (_Error("Missing required argument (" . $sRequiredArg . ")"));
  273. }
  274. }
  275. while (my ($sArg, $sValue) = each(%mhParsedArgs))
  276. {
  277. my $sValidationRegEx = $mhcScriptUsage{"args"}{"valid"}{$sArg};
  278. if ($sValue !~ /^$sValidationRegEx$/i)
  279. {
  280. return (_Error("Unknown value (" . $sValue . ") specified for argument (" . $sArg . ")"));
  281. }
  282. }
  283. return ($TRUE);
  284. }
  285. # =========================================================================
  286. # UpdFX_GetResources()
  287. #
  288. # Purpose:
  289. # Determine if we have the resources we need to do our job
  290. # Inputs:
  291. # None
  292. # Outputs:
  293. # Returns $TRUE if we have the resources, else $FALSE
  294. # Dependencies:
  295. # None
  296. # Notes:
  297. # =========================================================================
  298. sub UpdFX_GetResources
  299. {
  300. #Make sure the paths, tools, and files we need from the depot are there
  301. $msNetFxRoot = $msSdxRoot . "\\com\\netfx";
  302. if (! -d $msNetFxRoot)
  303. {
  304. return (_Error("Cannot find netfx root (" . $msNetFxRoot . ")"));
  305. }
  306. if (exists($mhParsedArgs{"submit"}) || exists($mhParsedArgs{"revert"}))
  307. {
  308. return ($TRUE);
  309. }
  310. if (exists($mhParsedArgs{"docabs"}))
  311. {
  312. return (UpdFX_GetCabResources());
  313. }
  314. $msQCmp_EXE = $msNetFxRoot . "\\qcmp.exe";
  315. if (! -e $msQCmp_EXE)
  316. {
  317. return (_Error("Cannot find required utility (" . $msQCmp_EXE . ")"));
  318. }
  319. $msNetFxDirsFileSpec = $msNetFxRoot . "\\dirs";
  320. if (! -e $msNetFxDirsFileSpec)
  321. {
  322. return (_Error("Cannot find dirs data file for netfx project (" . $msNetFxDirsFileSpec . ")"));
  323. }
  324. $msNetFxSourcesFileSpec = $msNetFxRoot . "\\binary_release\\sources";
  325. if (! -e $msNetFxSourcesFileSpec)
  326. {
  327. return (_Error("Cannot find sources data file for netfx project (" . $msNetFxSourcesFileSpec . ")"));
  328. }
  329. $msBinplaceDataFileSpec = $msSdxRoot . "\\tools\\placefil.txt";
  330. if (! -e $msBinplaceDataFileSpec)
  331. {
  332. return (_Error("Cannot find data file for binplace operation (" . $msBinplaceDataFileSpec . ")"));
  333. }
  334. if (0)
  335. {
  336. #Disabled. KathyHe was told that we no longer need to update this file because we're no longer
  337. #binplacing to the retail directory (except for 3 files, and they're already handled). However,
  338. #we'll keep the code around in case we ever hear differently...
  339. $msBinplaceSymsFileSpec = $msSdxRoot . "\\tools\\symbad.txt";
  340. if (! -e $msBinplaceSymsFileSpec)
  341. {
  342. return (_Error("Cannot find data file for binplace operation (" . $msBinplaceSymsFileSpec . ")"));
  343. }
  344. }
  345. #Make sure the layouts we intend to update from are there
  346. return (UpdFX_GetLayoutPathSpecs() && UpdFX_GetCabFileProps());
  347. }
  348. # =========================================================================
  349. # UpdFX_GetCabResources()
  350. #
  351. # Purpose:
  352. # Get the resources we'll need to create setup cabs
  353. # Inputs:
  354. # None
  355. # Outputs:
  356. # Returns $TRUE for success, $FALSE for failure
  357. # Dependencies:
  358. # None
  359. # Notes:
  360. # =========================================================================
  361. sub UpdFX_GetCabResources()
  362. {
  363. my $sLayoutRoot = $msNetFxRoot . "\\binary_release";
  364. my @sCpuList = $mhParsedArgs{"cpu"};
  365. if ((! defined($sCpuList[0])) || ("all" eq $sCpuList[0]))
  366. {
  367. @sCpuList = _GetDirList($sLayoutRoot, $TRUE);
  368. #TODO: REMOVE THIS BLOCK WHEN WE'RE READY TO INTEGRATE NON-X86 LAYOUTS
  369. if (1 < @sCpuList)
  370. {
  371. _Warning("Support for non-x86 cpus is NYI--limiting docabs to x86 only");
  372. @sCpuList = ("x86");
  373. }
  374. }
  375. foreach my $sCpu (@sCpuList)
  376. {
  377. my $sCpuPath = $sLayoutRoot . "\\" . (defined($mhcDepotNode{$sCpu}) ? $mhcDepotNode{$sCpu} : $sCpu);
  378. if (! -d $sCpuPath)
  379. {
  380. return (_Error("Cannot find layouts (" . $sCpuPath . ")"));
  381. }
  382. #Find the layouts for each specified build flavor or return failure
  383. my @sBldList = $mhParsedArgs{"bld"};
  384. if ((! defined($sBldList[0])) || ("all" eq $sBldList[0]))
  385. {
  386. @sBldList = _GetDirList($sCpuPath, $TRUE);
  387. #TODO: REMOVE THIS BLOCK WHEN WE'RE READY TO INTEGRATE NON-RTL LAYOUTS
  388. if (1 < @sBldList)
  389. {
  390. _Warning("Support for non-rtl blds is NYI--limiting docabs to rtl only");
  391. @sBldList = ("rtl");
  392. }
  393. }
  394. foreach my $sBld (@sBldList)
  395. {
  396. my $sBldPath = $sCpuPath . "\\" . (defined($mhcDepotNode{$sBld}) ? $mhcDepotNode{$sBld} : $sBld);
  397. if (! -d $sBldPath)
  398. {
  399. return (_Error("Cannot find layout (" . $sBldPath . ")"));
  400. }
  401. my $sDdfFileSpec = $sBldPath . "\\" . $mscNetFxDdfFileName;
  402. if (! -e $sDdfFileSpec)
  403. {
  404. return (_Error("Cannot find ddf file for layout (" . $sDdfFileSpec . ")"));
  405. }
  406. push(@{$mhParsedArgs{"docabs"}}, $sDdfFileSpec);
  407. }
  408. }
  409. return ($TRUE);
  410. }
  411. # =========================================================================
  412. # UpdFX_GetLayoutPathSpecs()
  413. #
  414. # Purpose:
  415. # Get the locations of the layouts we'll be updating from
  416. # Inputs:
  417. # None
  418. # Outputs:
  419. # Returns $TRUE for success, $FALSE for failure
  420. # Dependencies:
  421. # None
  422. # Notes:
  423. # =========================================================================
  424. sub UpdFX_GetLayoutPathSpecs
  425. {
  426. #Find the layout root or return failure
  427. my $sSrcRoot = $mhParsedArgs{"from"};
  428. if (! defined($sSrcRoot))
  429. {
  430. $sSrcRoot = $mscDefSrcRoot;
  431. }
  432. #If user supplied a relative path, make it fully-qualified
  433. elsif ((my $sStartPath = cwd()) && (chdir($sSrcRoot)) && (! -d $sSrcRoot))
  434. {
  435. $sSrcRoot = $sStartPath . "\\" . $sSrcRoot;
  436. $sSrcRoot =~ s/\//\\/g; #replace fwd slashes with backslashes
  437. }
  438. if (! -d $sSrcRoot)
  439. {
  440. return (_Error("Cannot find layout source (" . $sSrcRoot . ")"));
  441. }
  442. #Find the layouts for the specified revision or return failure
  443. # (Expecting source root to either point to the root of all layouts--
  444. # e.g. \\cpvsbuild\drops\v7.0\layouts--or the root of ndp layouts--
  445. # e.g. \\cpvsbuild\drops\v7.0\complus. In the former case, we need
  446. # to append "\\urt" to the location)
  447. my $sDropPath = $sSrcRoot . "\\" . $mhParsedArgs{"update"};
  448. if (-d $sDropPath . "\\urt")
  449. {
  450. $sDropPath .= "\\urt";
  451. }
  452. elsif (! -d $sDropPath)
  453. {
  454. return (_Error("Cannot find layouts (" . $sDropPath . ")"));
  455. }
  456. #Find the layouts for each specified cpu or return failure
  457. my @sCpuList = $mhParsedArgs{"cpu"};
  458. if ((! defined($sCpuList[0])) || ("all" eq $sCpuList[0]))
  459. {
  460. @sCpuList = _GetDirList($sDropPath, $TRUE);
  461. #TODO: REMOVE THIS BLOCK WHEN WE'RE READY TO INTEGRATE NON-X86 LAYOUTS
  462. if (1 < @sCpuList)
  463. {
  464. _Warning("Support for non-x86 cpus is NYI--limiting update to x86 only");
  465. @sCpuList = ("x86");
  466. }
  467. }
  468. foreach my $sCpu (@sCpuList)
  469. {
  470. my $sCpuPath = $sDropPath . "\\" . $sCpu . "\\ocm\\internal";
  471. if (! -d $sCpuPath)
  472. {
  473. return (_Error("Cannot find layouts (" . $sCpuPath . ")"));
  474. }
  475. #Find the layouts for each specified build flavor or return failure
  476. my @sBldList = $mhParsedArgs{"bld"};
  477. if ((! defined($sBldList[0])) || ("all" eq $sBldList[0]))
  478. {
  479. @sBldList = _GetDirList($sCpuPath, $TRUE);
  480. #TODO: REMOVE THIS BLOCK WHEN WE'RE READY TO INTEGRATE NON-RTL LAYOUTS
  481. if (1 < @sBldList)
  482. {
  483. _Warning("Support for non-rtl blds is NYI--limiting update to rtl only");
  484. @sBldList = ("rtl");
  485. }
  486. }
  487. foreach my $sBld (@sBldList)
  488. {
  489. my $sBldPath = $sCpuPath . "\\" . $sBld;
  490. if (! -d $sBldPath)
  491. {
  492. return (_Error("Cannot find layouts (" . $sBldPath . ")"));
  493. }
  494. #Find the layouts for each specified lang or return failure
  495. my @sLangList = $mhParsedArgs{"lang"};
  496. if ((! defined($sLangList[0])) || ("all" eq $sLangList[0]))
  497. {
  498. @sLangList = _GetDirList($sBldPath, $TRUE);
  499. #TODO: REMOVE THIS BLOCK WHEN WE'RE READY TO INTEGRATE NON-ENU LAYOUTS
  500. if (1 < @sLangList)
  501. {
  502. _Warning("Support for non-enu langs is NYI--limiting update to enu only");
  503. @sLangList = ("enu");
  504. }
  505. }
  506. foreach my $sLang (@sLangList)
  507. {
  508. #We now have the full path to a layout--if it doesn't exist, return failure
  509. my $sLangPath = $sBldPath . "\\" . $sLang;
  510. if (! -d $sLangPath)
  511. {
  512. return (_Error("Cannot find layouts (" . $sLangPath . ")"));
  513. }
  514. #Store the layout location and ensure we've got the data to map it to a depot location
  515. my $sLayoutKey = lc($sCpu) . "/" . lc($sBld);
  516. $mhSrcPathSpec{$sLayoutKey} = $sLangPath;
  517. _Assert(defined($mhcDepotPath{$sLayoutKey}), "Layout (" . $sLayoutKey . ") exists in \%mhcDepotPath");
  518. }
  519. }
  520. }
  521. return ($TRUE);
  522. }
  523. # =========================================================================
  524. # UpdFX_GetCabFileProps()
  525. #
  526. # Purpose:
  527. # Get the name of the cab file and the text we'll use as a template for
  528. # new ddf files
  529. # Inputs:
  530. # None
  531. # Outputs:
  532. # Returns $TRUE for success, $FALSE for failure
  533. # Dependencies:
  534. # None
  535. # Dependencies:
  536. # Notes:
  537. # =========================================================================
  538. sub UpdFX_GetCabFileProps
  539. {
  540. my $sCabFileName;
  541. my $sTemplateDdfSpec = $msNetFxRoot . "\\" . $mhcDepotPath{"x86/rtl"} . "\\" . $mscNetFxDdfFileName;
  542. if (! UpdFX_GetSyncedContentsOfDataFile($sTemplateDdfSpec, "ddf template file", \@msTemplateDdfText))
  543. {
  544. return ($FALSE); #error already output
  545. }
  546. foreach my $sDdfLine (@msTemplateDdfText)
  547. {
  548. if ($sDdfLine =~ /CabinetNameTemplate/)
  549. {
  550. ($sCabFileName) = ($sDdfLine =~ /"(.+)"/);
  551. if (! defined($sCabFileName))
  552. {
  553. return (_Error("Cannot extract cab name from definition line (" . $sDdfLine . ") " .
  554. "in ddf template file (" . $sTemplateDdfSpec . ")"));
  555. }
  556. last;
  557. }
  558. }
  559. if (! defined($sCabFileName))
  560. {
  561. return (_Error("Cannot find cab name in ddf template file (" . $sTemplateDdfSpec . ")"));
  562. }
  563. push(@msExcludeFileNames, $sCabFileName);
  564. return ($TRUE);
  565. }
  566. # =========================================================================
  567. # UpdFX_DoTasks()
  568. #
  569. # Purpose:
  570. # Perform the tasks specified by the user
  571. # Inputs:
  572. # None
  573. # Outputs:
  574. # Returns $TRUE for success, $FALSE for failure
  575. # Dependencies:
  576. # None
  577. # Notes:
  578. # =========================================================================
  579. sub UpdFX_DoTasks
  580. {
  581. my $bSucceeded = $FALSE;
  582. if (exists($mhParsedArgs{"update"}))
  583. {
  584. #To update the depot:
  585. # 1. Determine the changes that must be made to the layouts in the depot (UpdFX_GetChangeLists)
  586. # 2. Determine the changes that must be made to the build datafiles (UpdFX_Edit*)
  587. # 3. If there are no datafile conflicts, make the changes in the user's workspace (UpdFX_UpdateFiles)
  588. # 4. Display the results of the updates and some testing instructions (UpdFX_ShowResults)
  589. my ($rhAddList, $rhEditList, $rsaRemoveList) = UpdFX_GetChangeLists();
  590. $bSucceeded = UpdFX_EditNetFxDdfFiles($rhAddList, $rhEditList, $rsaRemoveList);
  591. $bSucceeded = UpdFX_EditNetFxDirsFile($rhAddList, $rhEditList, $rsaRemoveList) && $bSucceeded;
  592. $bSucceeded = UpdFX_EditNetFxSourcesFile($rhAddList, $rhEditList, $rsaRemoveList) && $bSucceeded;
  593. $bSucceeded = UpdFX_EditBinplaceDataFile($rhAddList, $rhEditList, $rsaRemoveList) && $bSucceeded;
  594. if (0)
  595. {
  596. #Disabled. KathyHe was told that we no longer need to update this file because we're no longer binplacing to
  597. #the retail directory (except for 3 files, and they're already handled). However, we'll keep the code around
  598. #in case we ever hear differently...
  599. $bSucceeded = UpdFX_EditBinplaceSymsFile($rhAddList, $rhEditList, $rsaRemoveList) && $bSucceeded;
  600. }
  601. if ($bSucceeded)
  602. {
  603. $bSucceeded = UpdFX_UpdateFiles($rhAddList, $rhEditList, $rsaRemoveList);
  604. }
  605. UpdFX_ShowResults($bSucceeded, $rhAddList, $rhEditList, $rsaRemoveList);
  606. }
  607. elsif (exists($mhParsedArgs{"submit"}))
  608. {
  609. $bSucceeded = UpdFX_SubmitChanges();
  610. }
  611. elsif (exists($mhParsedArgs{"revert"}))
  612. {
  613. $bSucceeded = UpdFX_RevertChanges();
  614. }
  615. elsif (exists($mhParsedArgs{"docabs"}))
  616. {
  617. $bSucceeded = UpdFX_MakeSetupCabs();
  618. }
  619. return ($bSucceeded);
  620. }
  621. # =========================================================================
  622. # UpdFX_GetChangeLists()
  623. #
  624. # Purpose:
  625. # Get the lists of layout files that have been added, changed, and removed
  626. # Inputs:
  627. # None
  628. # Outputs:
  629. # $rhAddList Reference to a hash describing added files
  630. # $rhEditList Reference to a hash describing changed files
  631. # $rsaRemoveList Reference to an array describing removed files
  632. # Dependencies:
  633. # None
  634. # Notes:
  635. # =========================================================================
  636. sub UpdFX_GetChangeLists
  637. {
  638. my @sRemoveList = ();
  639. my %hEditList = ();
  640. my %hAddList = ();
  641. my %hDepotFiles = ();
  642. my $nCount = 0;
  643. _SdExec("sync", $msQCmp_EXE);
  644. #Get the lists of files stored in the depot and sync those we intend to update
  645. while (my ($sLayoutKey, $sLayoutPath) = each(%mhcDepotPath))
  646. {
  647. my $sDepotPath = $msNetFxRoot . "\\" . $sLayoutPath;
  648. my @sFileList = UpdFX_GetDepotFileList($sDepotPath);
  649. if (@sFileList)
  650. {
  651. if ($mhSrcPathSpec{$sLayoutKey})
  652. {
  653. _SdExec("sync", $sDepotPath . "\\*");
  654. }
  655. $hDepotFiles{$sLayoutKey} = \@sFileList;
  656. }
  657. }
  658. #Determine which files need to be added, changed, and removed. We accomplish this with two loops:
  659. #First we compare the files in the source layouts with those in the depot to determine which files
  660. #need to be added or updated. Then we check the files already in the depot to determine which files
  661. #need to be removed.
  662. print("Gathering change lists.");
  663. while (my ($sLayoutKey, $sSrcPath) = each(%mhSrcPathSpec))
  664. {
  665. my $sDepotPath = $msNetFxRoot . "\\" . $mhcDepotPath{$sLayoutKey};
  666. my $rsaDepotFiles = $hDepotFiles{$sLayoutKey};
  667. foreach my $sFileName (_GetDirList($sSrcPath))
  668. {
  669. my $sDepotFileSpec = $sDepotPath . "\\" . $sFileName;
  670. my $sSrcFileSpec = $sSrcPath . "\\" . $sFileName;
  671. my $sFileKey = lc($sFileName);
  672. _Assert(! -d $sSrcFileSpec, "Dir entry (" . $sSrcFileSpec . ") is not a subdir");
  673. #If there are no depot files yet for this layout, or if this file isn't in the depot,
  674. #put the file in the add list
  675. if ((! defined($rsaDepotFiles)) || (0 == grep(/^\Q$sFileName\E$/i, @$rsaDepotFiles)))
  676. {
  677. $hAddList{$sDepotFileSpec} = $sSrcFileSpec;
  678. }
  679. #If this file is different from the depot file, put the file in the edit list
  680. elsif (0 != system($msQCmp_EXE, "-q", $sDepotFileSpec, $sSrcFileSpec))
  681. {
  682. $hEditList{$sDepotFileSpec} = $sSrcFileSpec;
  683. }
  684. #Store the layout variant for this file and its real name (needed for datafile edits)
  685. push(@{$mhFileVariants{$sFileKey}}, $sLayoutKey);
  686. if (! $mhRealFileName{$sFileKey})
  687. {
  688. $mhRealFileName{$sFileKey} = $sFileName;
  689. }
  690. print(".") if (0 == (++$nCount % 10));
  691. }
  692. #Update some variables we'll be using later to edit datafiles
  693. $msAllCpusMask |= UpdFX_Cpu($sLayoutKey);
  694. $mnAllLayouts++;
  695. }
  696. while (my ($sLayoutKey, $rsaDepotFiles) = each(%hDepotFiles))
  697. {
  698. my $sDepotPath = $msNetFxRoot . "\\" . $mhcDepotPath{$sLayoutKey};
  699. foreach my $sFileName (@$rsaDepotFiles)
  700. {
  701. my $sDepotFileSpec = $sDepotPath . "\\" . $sFileName;
  702. my $sFileKey = lc($sFileName);
  703. #If this file is from a layout we're not updating, just store the variant data
  704. if (! $mhSrcPathSpec{$sLayoutKey})
  705. {
  706. push(@{$mhFileVariants{$sFileKey}}, $sLayoutKey);
  707. }
  708. #If this layout isn't one of the variants already stored for this file, the file
  709. #was missing from the source layout and needs to be removed from the depot
  710. elsif (0 == grep(/$sLayoutKey/, @{$mhFileVariants{$sFileKey}}))
  711. {
  712. #Don't remove the files that we create in this depot (they aren't in the source layout)
  713. if (0 == grep(/^\Q$sFileName\E$/i, @msExcludeFileNames))
  714. {
  715. push(@sRemoveList, $sDepotFileSpec);
  716. }
  717. }
  718. #If we haven't stored the real name for this file yet, do so now
  719. if (! $mhRealFileName{$sFileKey})
  720. {
  721. $mhRealFileName{$sFileKey} = $sFileName;
  722. }
  723. print(".") if (0 == (++$nCount % 10));
  724. }
  725. if (! $mhSrcPathSpec{$sLayoutKey}) #if we haven't handled this layout yet (not updating it)...
  726. {
  727. #Update some variables we'll be using later to edit datafiles
  728. $msAllCpusMask |= UpdFX_Cpu($sLayoutKey);
  729. $mnAllLayouts++;
  730. }
  731. }
  732. print("\n");
  733. return (\%hAddList, \%hEditList, \@sRemoveList);
  734. }
  735. # =========================================================================
  736. # UpdFX_GetDepotFileList()
  737. #
  738. # Purpose:
  739. # Get the list of files contained in a depot dir
  740. # Inputs:
  741. # $sDepotPath Path to the depot dir
  742. # Outputs:
  743. # Returns the files contained in the dir (undefined if no files)
  744. # Dependencies:
  745. # None
  746. # Notes:
  747. # =========================================================================
  748. {
  749. my %hDepotDirs = ();
  750. sub UpdFX_GetDepotFileList
  751. {
  752. my ($sDepotPath) = @_;
  753. my @sFileList;
  754. _RequireArgument($sDepotPath, "\$sDepotPath");
  755. #If the depot path doesn't exist, find out whether it's missing from the depot
  756. #or just this workspace. If the former, return an undefined list to signify
  757. #that the path hasn't been added yet
  758. if (! -d $sDepotPath)
  759. {
  760. #Check each dir following the nexfx root to see if it's in the depot
  761. my $sNextPath = $msNetFxRoot;
  762. my @sDirsToCheck = split(/\\/, substr($sDepotPath, length($sNextPath) + 1));
  763. while (defined(my $sDir = shift(@sDirsToCheck)))
  764. {
  765. #Get the depot dirs for this portion of the path
  766. my $rsaDepotDirs = $hDepotDirs{$sNextPath};
  767. if (! defined($rsaDepotDirs))
  768. {
  769. $hDepotDirs{$sNextPath} = [_SdExec("dirs", $sNextPath . "\\*")];
  770. $rsaDepotDirs = $hDepotDirs{$sNextPath};
  771. }
  772. #If this dir isn't one of the depot dirs, return an undefined list
  773. if (0 == grep(/\/$sDir\s*$/i, @$rsaDepotDirs))
  774. {
  775. return ();
  776. }
  777. $sNextPath .= "\\" . $sDir;
  778. }
  779. }
  780. #Assemble the list of files
  781. foreach my $sFileData (_SdExec("files", $sDepotPath . "\\*"))
  782. {
  783. if ($sFileData !~ /- delete change \d+/)
  784. {
  785. push(@sFileList, ($sFileData =~ /.+\/([^#]+)#/));
  786. }
  787. }
  788. return (@sFileList);
  789. }
  790. }
  791. # =========================================================================
  792. # UpdFX_EditNetFxDdfFiles()
  793. #
  794. # Purpose:
  795. # Edit the layout ddf files if layout files were added or removed
  796. # Inputs:
  797. # $rhAddList Reference to a hash describing added files
  798. # $rhEditList Reference to a hash describing changed files
  799. # $rsaRemoveList Reference to an array describing removed files
  800. # Outputs:
  801. # Returns $TRUE for success, $FALSE for failure
  802. # Dependencies:
  803. # None
  804. # Notes:
  805. # - The files aren't changed at this point--we simply create an array
  806. # containing the edited file contents, which is used to update the
  807. # files if all data files can be successfully edited
  808. # =========================================================================
  809. sub UpdFX_EditNetFxDdfFiles
  810. {
  811. my ($rhAddList, $rhEditList, $rsaRemoveList) = @_;
  812. _RequireReference($rhAddList, "\$rhAddList", $UpdFX::keRefHash);
  813. _RequireReference($rhEditList, "\$rhEditList", $UpdFX::keRefHash);
  814. _RequireReference($rsaRemoveList, "\$rsaRemoveList", $UpdFX::keRefArray);
  815. foreach my $sLayoutKey (keys(%mhSrcPathSpec))
  816. {
  817. my $sMatchPath = quotemeta($mhcDepotPath{$sLayoutKey});
  818. my @sFilesToAdd = grep(!/\.pdb$/i, grep(/$sMatchPath/i, keys(%$rhAddList)));
  819. my @sFilesToRemove = grep(!/\.pdb$/i, grep(/$sMatchPath/i, @$rsaRemoveList));
  820. if (@sFilesToRemove || @sFilesToAdd)
  821. {
  822. my @sFileText = ();
  823. my @sFileHead = ();
  824. my @sFileList = ();
  825. my @sNewText = ();
  826. my $nChanges = 0;
  827. my $sLayoutPathSpec = $msNetFxRoot . "\\" . $mhcDepotPath{$sLayoutKey} . "\\";
  828. my $sLayoutConfigFileSpec = $sLayoutPathSpec . $mscNetFxDdfFileName;
  829. my $bHaveLayoutConfigFile = (-e $sLayoutConfigFileSpec);
  830. if (! $bHaveLayoutConfigFile)
  831. {
  832. @sFileText = @msTemplateDdfText;
  833. }
  834. elsif (! UpdFX_GetSyncedContentsOfDataFile($sLayoutConfigFileSpec, $sLayoutKey . " ddf file", \@sFileText))
  835. {
  836. return ($FALSE); #error already output
  837. }
  838. while ((@sFileText) && ($sFileText[0] !~ /^\s*"/))
  839. {
  840. push(@sFileHead, shift(@sFileText));
  841. }
  842. if ($bHaveLayoutConfigFile)
  843. {
  844. @sFileList = @sFileText;
  845. if (! @sFileList)
  846. {
  847. return (_Error("Cannot find filelist in " . $sLayoutKey . " ddf file (" . $sLayoutConfigFileSpec . ")"));
  848. }
  849. }
  850. else
  851. {
  852. my @sFileSpecs = UpdFX_GetDepotFileList($sLayoutPathSpec);
  853. foreach my $sFileSpec (sort(@sFileSpecs))
  854. {
  855. my ($sFileDrive, $sFilePath, $sFileName) = _SplitPath($sFileSpec);
  856. push(@sFileList, "\"" . $sFileName . "\"");
  857. }
  858. }
  859. foreach my $sFileSpec (@sFilesToRemove)
  860. {
  861. my ($sFileDrive, $sFilePath, $sFileName) = _SplitPath($sFileSpec);
  862. $nChanges += UpdFX_RemoveFilesFromList(\@sFileList, [$sFileName], "^\"\%s\"\$", $sLayoutConfigFileSpec);
  863. }
  864. foreach my $sFileSpec (sort{lc($a) cmp lc($b)}(@sFilesToAdd))
  865. {
  866. my ($sFileDrive, $sFilePath, $sFileName) = _SplitPath($sFileSpec);
  867. if ((0 == grep(/^\Q$sFileName\E$/i, @msExcludeFileNames)) &&
  868. (0 == grep(/^\s*\"\Q$sFileName\E\"\s*$/i, @sFileList)))
  869. {
  870. push(@sNewText, "\"" . $sFileName . "\"");
  871. $nChanges++;
  872. }
  873. }
  874. #If we had any changes in the filelist, assemble the new file contents in preparation for the update
  875. if (0 < $nChanges)
  876. {
  877. #Insert the new text alphabetically (case insensitive)
  878. while (@sNewText)
  879. {
  880. if ((! @sFileList) || (lc($sNewText[0]) lt lc($sFileList[0])))
  881. {
  882. push(@sFileHead, shift(@sNewText));
  883. }
  884. else
  885. {
  886. push(@sFileHead, shift(@sFileList));
  887. }
  888. }
  889. @sFileText = join("\n", (@sFileHead, @sFileList));
  890. if ($bHaveLayoutConfigFile)
  891. {
  892. $$rhEditList{$sLayoutConfigFileSpec} = \@sFileText;
  893. }
  894. else
  895. {
  896. $$rhAddList{$sLayoutConfigFileSpec} = \@sFileText;
  897. }
  898. }
  899. }
  900. }
  901. return ($TRUE);
  902. }
  903. # =========================================================================
  904. # UpdFX_EditNetFxDirsFile()
  905. #
  906. # Purpose:
  907. # Edit the netfx dirs file if i64 layout files were added
  908. # Inputs:
  909. # $rhAddList Reference to a hash describing added files
  910. # $rhEditList Reference to a hash describing changed files
  911. # $rsaRemoveList Reference to an array describing removed files
  912. # Outputs:
  913. # Returns $TRUE for success, $FALSE for failure
  914. # Dependencies:
  915. # None
  916. # Notes:
  917. # - The file isn't changed at this point--we simply create an array
  918. # containing the edited file contents, which is used to update the
  919. # file if all data files can be successfully edited
  920. # Notes:
  921. # =========================================================================
  922. sub UpdFX_EditNetFxDirsFile
  923. {
  924. my ($rhAddList, $rhEditList, $rsaRemoveList) = @_;
  925. _RequireReference($rhAddList, "\$rhAddList", $UpdFX::keRefHash);
  926. _RequireReference($rhEditList, "\$rhEditList", $UpdFX::keRefHash);
  927. _RequireReference($rsaRemoveList, "\$rsaRemoveList", $UpdFX::keRefArray);
  928. my @sFileText = ();
  929. my $nChanges = 0;
  930. #If we're adding files and i64 layouts are included, see if we need to remove the {win32} build restriction
  931. if ((keys(%$rhAddList)) && ("i64" eq ("i64" & $msAllCpusMask)))
  932. {
  933. if (! UpdFX_GetSyncedContentsOfDataFile($msNetFxDirsFileSpec, "netfx dirs file", \@sFileText))
  934. {
  935. return ($FALSE); #error already output
  936. }
  937. foreach my $sText (@sFileText)
  938. {
  939. $nChanges += ($sText =~ s/{win32}//ig);
  940. }
  941. }
  942. #If we had any changes in the file, assemble the new file contents in preparation for the update
  943. if (0 < $nChanges)
  944. {
  945. @sFileText = join("\n", @sFileText);
  946. $$rhEditList{$msNetFxDirsFileSpec} = \@sFileText;
  947. }
  948. return ($TRUE);
  949. }
  950. # =========================================================================
  951. # UpdFX_EditNetFxSourcesFile()
  952. #
  953. # Purpose:
  954. # Edit the netfx sources file if layout files were added or removed
  955. # Inputs:
  956. # $rhAddList Reference to a hash describing added files
  957. # $rhEditList Reference to a hash describing changed files
  958. # $rsaRemoveList Reference to an array describing removed files
  959. # Outputs:
  960. # Returns $TRUE for success, $FALSE for failure
  961. # Dependencies:
  962. # None
  963. # Notes:
  964. # - The file isn't changed at this point--we simply create an array
  965. # containing the edited file contents, which is used to update the
  966. # file if all data files can be successfully edited
  967. # =========================================================================
  968. sub UpdFX_EditNetFxSourcesFile
  969. {
  970. my ($rhAddList, $rhEditList, $rsaRemoveList) = @_;
  971. _RequireReference($rhAddList, "\$rhAddList", $UpdFX::keRefHash);
  972. _RequireReference($rhEditList, "\$rhEditList", $UpdFX::keRefHash);
  973. _RequireReference($rsaRemoveList, "\$rsaRemoveList", $UpdFX::keRefArray);
  974. my @sFileHead = ();
  975. my @sFileText = ();
  976. my @sFileList = ();
  977. my %hFileList = ();
  978. my %hFilesToAdd = ();
  979. my %hFilesToRemove = ();
  980. my %hTextToAdd = ();
  981. my $nChanges = 0;
  982. #If we are adding or removing files, get the filelist(s) from the datafile and prep the changes
  983. if (@$rsaRemoveList || keys(%$rhAddList))
  984. {
  985. my %hFileLayouts;
  986. my $rsaActiveFileList;
  987. my $sKeyList = lc(join("#", ("", values(%mhcSrcFileList), "")));
  988. $sKeyList =~ s/\s+//g; #remove spaces
  989. if (! UpdFX_GetSyncedContentsOfDataFile($msNetFxSourcesFileSpec, "netfx sources file", \@sFileText))
  990. {
  991. return ($FALSE); #error already output
  992. }
  993. #The sources data file can contain several sections of files. Files common to all layout variants
  994. #are listed in the MISCFILES section, which is always present and always first. If there are files
  995. #that exist in a subset of the variants, they are bracketed by nmake "!IF" directives that specify
  996. #the condition(s) for their inclusion.
  997. #
  998. #In order to keep UpfFx.pl from becoming too complicated, there are a number of conventions that
  999. #must be followed when updating the sources file. If someone hand-edits that file and ignores these
  1000. #conventions, we'll refuse to update the layouts.
  1001. #
  1002. #The conventions that must be followed are:
  1003. # - The MISCFILES section must be the 1st section
  1004. # - Sections can only be defined using the directives in %mhcSrcFileList
  1005. # - Sections cannot be nested
  1006. #
  1007. #To make sure we reconstruct the file in the proper order, we'll store each section name in an array
  1008. #and its filelist in a hash, referenced via the section name
  1009. while (defined(my $sText = shift(@sFileText)))
  1010. {
  1011. if ($sText =~ /^MISCFILES\s*=\s*\\/i)
  1012. {
  1013. last;
  1014. }
  1015. push(@sFileHead, $sText);
  1016. }
  1017. push(@sFileList, $mhcSrcFileList{"---/---"});
  1018. $hFileList{$sFileList[0]} = $rsaActiveFileList = [];
  1019. while (defined(my $sText = shift(@sFileText)))
  1020. {
  1021. if ($sText =~ /^!\s*ENDIF/i)
  1022. {
  1023. $rsaActiveFileList = $hFileList{$sFileList[0]};
  1024. }
  1025. elsif ($sText =~ /^!/)
  1026. {
  1027. my $sKeyFind = "#" . lc($sText) . "#";
  1028. $sKeyFind =~ s/\s+//g; #remove spaces
  1029. if (-1 == index($sKeyList, $sKeyFind))
  1030. {
  1031. return (_Error("Unexpected nmake directive (" . $sText . ") found\n" .
  1032. "in netfx sources file (" . $msNetFxSourcesFileSpec . ")\n" .
  1033. "Only the following nmake directives are allowed:\n" .
  1034. join("\n", sort(grep(/!/, values(%mhcSrcFileList))))));
  1035. }
  1036. $hFileList{$sText} = $rsaActiveFileList = [];
  1037. push(@sFileList, $sText);
  1038. }
  1039. else
  1040. {
  1041. push(@$rsaActiveFileList, $sText);
  1042. }
  1043. }
  1044. if (! @sFileList)
  1045. {
  1046. return (_Error("Cannot find filelist in netfx sources file (" . $msNetFxSourcesFileSpec . ")"));
  1047. }
  1048. #Figure out the changes that will actually be needed. (We can't just use the add/remove lists
  1049. #because they identify individual files and we have to know about the effect of those changes
  1050. #on the file variants. For example, if we remove an x86 variant but still have an i64 variant,
  1051. #we remove it from the common list and add it to the i64 list.)
  1052. #
  1053. #To start, we have to determine whether each file is valid in all layouts or a subset
  1054. while (my ($sFileKey, $rsaVariants) = each(%mhFileVariants))
  1055. {
  1056. if (@$rsaVariants == $mnAllLayouts)
  1057. {
  1058. $hFileLayouts{$sFileKey}{$mscLayoutKeys[0]} = 1;
  1059. }
  1060. else
  1061. {
  1062. @{$hFileLayouts{$sFileKey}}{@$rsaVariants} = (1) x @$rsaVariants;
  1063. }
  1064. }
  1065. #After we know the layouts for each file, we can figure out which lists each should be in
  1066. foreach my $sFileKey (sort(grep(!/\.pdb$/i, keys(%hFileLayouts)))) #sort now so we can merge alphabetically later
  1067. {
  1068. if (0 == grep(/^\Q$sFileKey\E$/i, @msExcludeFileNames))
  1069. {
  1070. my $rhLayouts = $hFileLayouts{$sFileKey};
  1071. while (my ($sLayoutKey, $sFileList) = each(%mhcSrcFileList))
  1072. {
  1073. if ($$rhLayouts{$sLayoutKey})
  1074. {
  1075. push(@{$hFilesToAdd{$sFileList}}, $sFileKey);
  1076. }
  1077. else
  1078. {
  1079. push(@{$hFilesToRemove{$sFileList}}, $sFileKey);
  1080. }
  1081. }
  1082. }
  1083. }
  1084. #If we are creating any new filelists, add that info to the list of filelist names
  1085. foreach my $sLayoutKey (@mscLayoutKeys)
  1086. {
  1087. my $sFileList = $mhcSrcFileList{$sLayoutKey};
  1088. if ((@{$hFilesToAdd{$sFileList}}) && (! $hFileList{$sFileList}))
  1089. {
  1090. push(@sFileList, $sFileList);
  1091. $hFileList{$sFileList} = [];
  1092. }
  1093. }
  1094. }
  1095. #Apply the changes to the filelist(s)
  1096. while (my ($sFileList, $rsaFileList) = each(%hFileList))
  1097. {
  1098. if ($hFilesToRemove{$sFileList})
  1099. {
  1100. $nChanges += UpdFX_RemoveFilesFromList($rsaFileList, $hFilesToRemove{$sFileList}, "\\\\\%s\\s*", $msNetFxSourcesFileSpec);
  1101. }
  1102. foreach my $sFileKey (@{$hFilesToAdd{$sFileList}})
  1103. {
  1104. if (0 == grep(/\\\Q$sFileKey\E\s*/i, @$rsaFileList))
  1105. {
  1106. push(@{$hTextToAdd{$sFileList}}, " \$(TARGET_DIRECTORY)\$(BUILDFLAVOR)\\" . $mhRealFileName{$sFileKey} . " \\");
  1107. $nChanges++;
  1108. }
  1109. }
  1110. }
  1111. #If we had any changes in the filelist(s), assemble the new file contents in preparation for the update
  1112. if (0 < $nChanges)
  1113. {
  1114. #Insert the new text alphabetically (case insensitive). Note that we don't use
  1115. #sort() here because the existing list is not completely sorted--unless someone
  1116. #else sorts it, the best we'll do is ensure that we at least precede or follow
  1117. #a line that makes sense, without changing the order of the existing data
  1118. while (defined(my $sFileList = shift(@sFileList)))
  1119. {
  1120. my $rsaFileList = $hFileList{$sFileList};
  1121. my $rsaNewText = $hTextToAdd{$sFileList};
  1122. push(@sFileHead, $sFileList);
  1123. while (@$rsaNewText)
  1124. {
  1125. if ((! @$rsaFileList) || (lc($$rsaNewText[0]) lt lc($$rsaFileList[0])))
  1126. {
  1127. push(@sFileHead, shift(@$rsaNewText));
  1128. }
  1129. else
  1130. {
  1131. push(@sFileHead, shift(@$rsaFileList));
  1132. }
  1133. }
  1134. push(@sFileHead, @$rsaFileList);
  1135. if ($sFileList =~ /^!/)
  1136. {
  1137. push(@sFileHead, "!ENDIF");
  1138. }
  1139. }
  1140. @sFileText = join("\n", @sFileHead);
  1141. $$rhEditList{$msNetFxSourcesFileSpec} = \@sFileText;
  1142. }
  1143. return ($TRUE);
  1144. }
  1145. # =========================================================================
  1146. # UpdFX_EditBinplaceDataFile()
  1147. #
  1148. # Purpose:
  1149. # Edit the binplace data file if layout files were added or removed
  1150. # Inputs:
  1151. # $rhAddList Reference to a hash describing added files
  1152. # $rhEditList Reference to a hash describing changed files
  1153. # $rsaRemoveList Reference to an array describing removed files
  1154. # Outputs:
  1155. # Returns $TRUE for success, $FALSE for failure
  1156. # Dependencies:
  1157. # None
  1158. # Notes:
  1159. # - The file isn't changed at this point--we simply create an array
  1160. # containing the edited file contents, which is used to update the
  1161. # file if all data files can be successfully edited
  1162. # - If we have a new file that already has an entry in the binplace
  1163. # data file, we've got a name collision with a file from another
  1164. # team. When this happens, we output an error and refuse to update
  1165. # the layout until the collision is resolved.
  1166. # =========================================================================
  1167. sub UpdFX_EditBinplaceDataFile
  1168. {
  1169. my ($rhAddList, $rhEditList, $rsaRemoveList) = @_;
  1170. _RequireReference($rhAddList, "\$rhAddList", $UpdFX::keRefHash);
  1171. _RequireReference($rhEditList, "\$rhEditList", $UpdFX::keRefHash);
  1172. _RequireReference($rsaRemoveList, "\$rsaRemoveList", $UpdFX::keRefArray);
  1173. my @sFilesToRemove = ();
  1174. my @sFilesToAdd = ();
  1175. my @sFileNames = ();
  1176. my @sFileHead = ();
  1177. my @sFileList = ();
  1178. my @sFileText = ();
  1179. my @sNewText = ();
  1180. my %hFileListData = ();
  1181. my $nChanges = 0;
  1182. my $nErrors = 0;
  1183. #Ensure we're only removing data for files that have no variants left
  1184. foreach my $sFileSpec (grep(!/\.pdb$/i, @$rsaRemoveList))
  1185. {
  1186. my ($sFileDrive, $sFilePath, $sFileName) = _SplitPath($sFileSpec);
  1187. if (0 == @{$mhFileVariants{lc($sFileName)}})
  1188. {
  1189. if (0 < grep(/^\Q$sFileName\E$/i, @msBinplaceExcludes))
  1190. {
  1191. _Warning("Ignoring filename (" . $sFileName . ") for binplace edits as per VS7-300525");
  1192. }
  1193. else
  1194. {
  1195. push(@sFilesToRemove, $sFileName);
  1196. }
  1197. }
  1198. }
  1199. #Ensure we only try to add a filename once
  1200. my %hFileVariant;
  1201. foreach my $sFileSpec (grep(!/\.pdb$/i, keys(%$rhAddList)))
  1202. {
  1203. if (! UpdFX_Dat($$rhAddList{$sFileSpec}))
  1204. {
  1205. my ($sFileDrive, $sFilePath, $sFileName) = _SplitPath($sFileSpec);
  1206. if (0 == grep(/^\Q$sFileName\E$/i, @msExcludeFileNames))
  1207. {
  1208. if (0 < grep(/^\Q$sFileName\E$/i, @msBinplaceExcludes))
  1209. {
  1210. _Warning("Ignoring filename (" . $sFileName . ") for binplace edits as per VS7-300525");
  1211. }
  1212. else
  1213. {
  1214. my $sFileKey = lc($sFileName);
  1215. if (! $hFileVariant{$sFileKey}++)
  1216. {
  1217. push(@sFilesToAdd, $sFileKey);
  1218. }
  1219. }
  1220. }
  1221. }
  1222. }
  1223. #If we are adding or removing files, get the filelist from the datafile and prep the changes
  1224. if (@sFilesToRemove || @sFilesToAdd)
  1225. {
  1226. if (! UpdFX_GetSyncedContentsOfDataFile($msBinplaceDataFileSpec, "binplace data file", \@sFileText))
  1227. {
  1228. return ($FALSE); #error already output
  1229. }
  1230. while (@sFileText)
  1231. {
  1232. if ($sFileText[0] !~ /^\s*;/)
  1233. {
  1234. last;
  1235. }
  1236. push(@sFileHead, shift(@sFileText));
  1237. }
  1238. @sFileList = @sFileText;
  1239. if (! @sFileList)
  1240. {
  1241. return (_Error("Cannot find filelist in binplace data file (" . $msBinplaceDataFileSpec . ")"));
  1242. }
  1243. foreach my $sText (@sFileList)
  1244. {
  1245. if ($sText !~ /^\s*;/)
  1246. {
  1247. my ($sFileName) = ($sText =~ /^(\S+)/);
  1248. if (defined($sFileName))
  1249. {
  1250. $hFileListData{lc($sFileName)} = $sText;
  1251. }
  1252. }
  1253. }
  1254. @sFileNames = keys(%hFileListData);
  1255. $tabstop = 17;
  1256. }
  1257. #Apply the changes to the filelist
  1258. $nChanges = UpdFX_RemoveFilesFromList(\@sFileList, \@sFilesToRemove, "^\%s\\s+", $msBinplaceDataFileSpec);
  1259. foreach my $sFileKey (sort(@sFilesToAdd)) #sort now so we can merge alphabetically later
  1260. {
  1261. my $sFileData = $hFileListData{$sFileKey};
  1262. my $sMatchName = quotemeta($sFileKey);
  1263. if ((! defined($sFileData)) || ($sFileData !~ /^$sMatchName\s+.*;\s*netfx/i))
  1264. {
  1265. #If the name is already in the list and it's not our entry, we have a name collision
  1266. #If ignore_err is specified, do not check for name collisions
  1267. if ((! exists($mhParsedArgs{"ignore_err"})) && (0 < grep(/^$sMatchName$/, @sFileNames)))
  1268. {
  1269. _Error("Filename (" . $mhRealFileName{$sFileKey} . ") conflicts with another already found\n" .
  1270. "in binplace data file (" . $msBinplaceDataFileSpec . ")\n" .
  1271. "The following file(s) must be renamed and setup data adjusted:\n" .
  1272. join("\n", UpdFx_GetSrcFileSpecs($sFileKey)));
  1273. $nErrors++;
  1274. }
  1275. else
  1276. {
  1277. push(@sNewText, expand($mhRealFileName{$sFileKey} . "\tnetfx ; netfx"));
  1278. $nChanges++;
  1279. }
  1280. }
  1281. }
  1282. #If we had any changes in the filelist, assemble the new file contents in preparation for the update
  1283. if ((0 == $nErrors) && (0 < $nChanges))
  1284. {
  1285. #Insert the new text alphabetically (case insensitive). Note that we don't use
  1286. #sort() here because the existing list is not completely sorted--unless someone
  1287. #else sorts it, the best we'll do is ensure that we at least precede or follow
  1288. #a line that makes sense, without changing the order of the existing data
  1289. while (@sNewText)
  1290. {
  1291. if ((! @sFileList) || (lc($sNewText[0]) lt lc($sFileList[0])))
  1292. {
  1293. push(@sFileHead, shift(@sNewText));
  1294. }
  1295. else
  1296. {
  1297. push(@sFileHead, shift(@sFileList));
  1298. }
  1299. }
  1300. @sFileText = join("\n", (@sFileHead, @sFileList));
  1301. $$rhEditList{$msBinplaceDataFileSpec} = \@sFileText;
  1302. }
  1303. #If we didn't add all files to the list, we had name collision(s) and will return $FALSE,
  1304. #which will prevent further work until the collision(s) are resolved
  1305. return (0 == $nErrors);
  1306. }
  1307. # =========================================================================
  1308. # UpdFX_EditBinplaceSymsFile()
  1309. #
  1310. # Purpose:
  1311. # Edit the supporting binplace data file if layout files were added or removed
  1312. # Inputs:
  1313. # $rhAddList Reference to a hash describing added files
  1314. # $rhEditList Reference to a hash describing changed files
  1315. # $rsaRemoveList Reference to an array describing removed files
  1316. # Outputs:
  1317. # Returns $TRUE for success, $FALSE for failure
  1318. # Dependencies:
  1319. # None
  1320. # Notes:
  1321. # - The file isn't changed at this point--we simply create an array
  1322. # containing the edited file contents, which is used to update the
  1323. # file if all data files can be successfully edited
  1324. # - This data file identifies layout files with symbol problems. If a binary
  1325. # has problems and is not listed in this file, binplace will output
  1326. # an error. (See the VS RAID issue $mscSymsRaidNum for more info)
  1327. # =========================================================================
  1328. sub UpdFX_EditBinplaceSymsFile
  1329. {
  1330. my ($rhAddList, $rhEditList, $rsaRemoveList) = @_;
  1331. _RequireReference($rhAddList, "\$rhAddList", $UpdFX::keRefHash);
  1332. _RequireReference($rhEditList, "\$rhEditList", $UpdFX::keRefHash);
  1333. _RequireReference($rsaRemoveList, "\$rsaRemoveList", $UpdFX::keRefArray);
  1334. my %hSymbolErrors = ();
  1335. my @sFilesToRemove = ();
  1336. my @sFilesToAdd = ();
  1337. my @sFileHead = ();
  1338. my @sFileList = ();
  1339. my @sFileText = ();
  1340. my @sNewText = ();
  1341. my $nChanges = 0;
  1342. #Ensure we're only removing data for files that have no variants left
  1343. foreach my $sFileSpec (grep(!/\.pdb$/i, @$rsaRemoveList))
  1344. {
  1345. my ($sFileDrive, $sFilePath, $sFileName) = _SplitPath($sFileSpec);
  1346. if (0 == @{$mhFileVariants{lc($sFileName)}})
  1347. {
  1348. push(@sFilesToRemove, $sFileName);
  1349. }
  1350. }
  1351. #Ensure we only try to add a filename once and only if the file has symbol problems
  1352. my %hFileVariant;
  1353. foreach my $sFileSpec (grep(!/\.pdb$/i, values(%$rhAddList)))
  1354. {
  1355. if (! UpdFX_Dat($sFileSpec))
  1356. {
  1357. my ($sFileDrive, $sFilePath, $sFileName) = _SplitPath($sFileSpec);
  1358. if (0 == grep(/^\Q$sFileName\E$/i, @msExcludeFileNames))
  1359. {
  1360. my $sFileKey = lc($sFileName);
  1361. if (! $hFileVariant{$sFileKey}++)
  1362. {
  1363. #If the file fails the symchk test, add it to the list
  1364. my @sOutput = `$mscSymChk_EXE /s $sFileDrive$sFilePath /v $sFileSpec`;
  1365. if ($sOutput[0] =~ /\Q$sFileName\E\s+FAILED/)
  1366. {
  1367. push(@sFilesToAdd, $sFileKey);
  1368. push(@{$hSymbolErrors{$sFileDrive . $sFilePath}}, $sOutput[0]);
  1369. }
  1370. }
  1371. }
  1372. }
  1373. }
  1374. #If we are adding or removing files, get the filelist from the datafile and prep the changes
  1375. if (@sFilesToRemove || @sFilesToAdd)
  1376. {
  1377. if (! UpdFX_GetSyncedContentsOfDataFile($msBinplaceSymsFileSpec, "binplace data file", \@sFileList))
  1378. {
  1379. return ($FALSE); #error already output
  1380. }
  1381. if (! @sFileList)
  1382. {
  1383. return (_Error("Cannot find filelist in binplace data file (" . $msBinplaceSymsFileSpec . ")"));
  1384. }
  1385. if (keys(%hSymbolErrors))
  1386. {
  1387. my @sWarningText = "One or more files has symbol problems:";
  1388. while (my ($sPathSpec, $rsaSymbolErrors) = each(%hSymbolErrors))
  1389. {
  1390. push(@sWarningText, ("SYMCHK: " . $sPathSpec, sort{lc($a) cmp lc($b)}(@$rsaSymbolErrors)));
  1391. }
  1392. push(@sWarningText, "Please ensure that RAID issue " . $mscSymsRaidNum . " includes this data");
  1393. chomp(@sWarningText);
  1394. _Warning(join("\n", @sWarningText));
  1395. print("Press ENTER to continue...");
  1396. $sKeyPressed = <STDIN>;
  1397. }
  1398. $tabstop = 16;
  1399. }
  1400. #Apply the changes to the filelist
  1401. $nChanges = UpdFX_RemoveFilesFromList(\@sFileList, \@sFilesToRemove, "^\%s\\s*;\\s*" . $mscSymsRaidNum, $msBinplaceSymsFileSpec);
  1402. foreach my $sFileKey (sort(@sFilesToAdd)) #sort now so we can merge alphabetically later
  1403. {
  1404. if (0 == grep(/^\Q$sFileKey\E\s*(;|$)/i, @sFileList))
  1405. {
  1406. push(@sNewText, expand($mhRealFileName{$sFileKey} . "\t; " . $mscSymsRaidNum));
  1407. $nChanges++;
  1408. }
  1409. }
  1410. #If we had any changes in the filelist, assemble the new file contents in preparation for the update
  1411. if (0 < $nChanges)
  1412. {
  1413. #Insert the new text alphabetically (case insensitive). Note that we don't use
  1414. #sort() here because the existing list is not completely sorted--unless someone
  1415. #else sorts it, the best we'll do is ensure that we at least precede or follow
  1416. #a line that makes sense, without changing the order of the existing data
  1417. while (@sNewText)
  1418. {
  1419. if ((! @sFileList) || (lc($sNewText[0]) lt lc($sFileList[0])))
  1420. {
  1421. push(@sFileHead, shift(@sNewText));
  1422. }
  1423. else
  1424. {
  1425. push(@sFileHead, shift(@sFileList));
  1426. }
  1427. }
  1428. @sFileText = join("\n", (@sFileHead, @sFileList));
  1429. $$rhEditList{$msBinplaceSymsFileSpec} = \@sFileText;
  1430. }
  1431. return ($TRUE);
  1432. }
  1433. # =========================================================================
  1434. # UpdFX_GetSyncedContentsOfDataFile()
  1435. #
  1436. # Purpose:
  1437. # Sync and read a data file
  1438. # Inputs:
  1439. # $sFileSpec File specification
  1440. # $sFileDesc File description
  1441. # $rsaFileText Reference to an array that will receive the data
  1442. # Outputs:
  1443. # Returns $TRUE for success, $FALSE for failure
  1444. # Dependencies:
  1445. # None
  1446. # Notes:
  1447. # - All EOL is removed from the file contents to simplify handling
  1448. # =========================================================================
  1449. sub UpdFX_GetSyncedContentsOfDataFile
  1450. {
  1451. my ($sFileSpec, $sFileDesc, $rsaFileText) = @_;
  1452. _RequireArgument($sFileSpec, "\$sFileSpec");
  1453. _RequireArgument($sFileDesc, "\$sFileDesc");
  1454. _RequireReference($rsaFileText, "\$rsaFileText", $UpdFX::keRefArray);
  1455. if (! _SdExec("sync", $sFileSpec))
  1456. {
  1457. return (_Error("Cannot sync " . $sFileDesc . " (" . $sFileSpec . ")"));
  1458. }
  1459. if (! open(hFile, "<" . $sFileSpec))
  1460. {
  1461. return (_Error("Cannot open " . $sFileDesc . " (" . $sFileSpec . ")--" . $!));
  1462. }
  1463. @$rsaFileText = <hFile>;
  1464. close(hFile);
  1465. chomp(@$rsaFileText);
  1466. print("Preparing data file changes...\n");
  1467. return ($TRUE);
  1468. }
  1469. # =========================================================================
  1470. # UpdFX_RemoveFilesFromList()
  1471. #
  1472. # Purpose:
  1473. # Remove files from a list, using a regex to detect items containing them
  1474. # Inputs:
  1475. # $rsaFileList Reference to an array containing the list
  1476. # $rsaFileNames Reference to an array containing the filenames
  1477. # $sFilterFormat Format string for a regex
  1478. # $sDataFileSpec Filespec of data file containing the list
  1479. # Outputs:
  1480. # Returns the number of files removed from the list
  1481. # Dependencies:
  1482. # None
  1483. # Notes:
  1484. # - If a regex catches more than one file, we record an entry in the
  1485. # summary hash so that we can alert the user to a possible problem
  1486. # =========================================================================
  1487. sub UpdFX_RemoveFilesFromList
  1488. {
  1489. my ($rsaFileList, $rsaFileNames, $sFilterFormat, $sDataFileSpec) = @_;
  1490. my $nChanges = 0;
  1491. _RequireReference($rsaFileList, "\$rsaFileList", $UpdFX::keRefArray);
  1492. _RequireReference($rsaFileNames, "\$rsaFileNames", $UpdFX::keRefArray);
  1493. _RequireArgument($sFilterFormat, "\$sFilterFormat");
  1494. _RequireArgument($sDataFileSpec, "\$sDataFileSpec");
  1495. #Initialize a summary entry for problems encountered
  1496. if (! defined($mhSummary{$sDataFileSpec}))
  1497. {
  1498. $mhSummary{$sDataFileSpec} = [];
  1499. }
  1500. foreach my $sFileName (@$rsaFileNames)
  1501. {
  1502. my $sFilterRegEx = sprintf($sFilterFormat, $sFileName);
  1503. my $nCount = grep(/$sFilterRegEx/i, @$rsaFileList);
  1504. if (1 < $nCount)
  1505. {
  1506. push(@{$mhSummary{$sDataFileSpec}}, "Removed " . $nCount . " lines containing '" . $sFileName . "'");
  1507. }
  1508. @$rsaFileList = grep(!/$sFilterRegEx/i, @$rsaFileList);
  1509. $nChanges += $nCount;
  1510. }
  1511. #If we didn't encounter any problems, remove the summary entry
  1512. if (! @{$mhSummary{$sDataFileSpec}})
  1513. {
  1514. delete($mhSummary{$sDataFileSpec});
  1515. }
  1516. return ($nChanges);
  1517. }
  1518. # =========================================================================
  1519. # UpdFx_GetSrcFileSpecs()
  1520. #
  1521. # Purpose:
  1522. # Get the full src filespecs for a filekey
  1523. # Inputs:
  1524. # $sFileKey A filekey (lower-cased filename)
  1525. # Outputs:
  1526. # Returns a list of full filespecs for success, else just the filename
  1527. # Dependencies:
  1528. # None
  1529. # Notes:
  1530. # =========================================================================
  1531. sub UpdFx_GetSrcFileSpecs
  1532. {
  1533. my ($sFileKey) = @_;
  1534. my @sFileSpecs;
  1535. _RequireArgument($sFileKey, "\$sFileKey");
  1536. my $sFileName = $mhRealFileName{$sFileKey};
  1537. foreach my $sFilePath (values(%mhSrcPathSpec))
  1538. {
  1539. my $sSrcFileSpec = $sFilePath . "\\" . $sFileName;
  1540. if (-e $sSrcFileSpec)
  1541. {
  1542. push(@sFileSpecs, $sSrcFileSpec);
  1543. }
  1544. }
  1545. if (! defined(@sFileSpecs))
  1546. {
  1547. push(@sFileSpecs, $sFileName);
  1548. }
  1549. return (@sFileSpecs);
  1550. }
  1551. # =========================================================================
  1552. # UpdFX_UpdateFiles()
  1553. #
  1554. # Purpose:
  1555. # Update files in the depot
  1556. # Inputs:
  1557. # $rhAddList Reference to a hash describing added files
  1558. # $rhEditList Reference to a hash describing changed files
  1559. # $rsaRemoveList Reference to an array describing removed files
  1560. # Outputs:
  1561. # Returns $TRUE
  1562. # Dependencies:
  1563. # None
  1564. # Notes:
  1565. # =========================================================================
  1566. sub UpdFX_UpdateFiles
  1567. {
  1568. my ($rhAddList, $rhEditList, $rsaRemoveList) = @_;
  1569. my $sResultKey;
  1570. _RequireReference($rhAddList, "\$rhAddList", $UpdFX::keRefHash);
  1571. _RequireReference($rhEditList, "\$rhEditList", $UpdFX::keRefHash);
  1572. _RequireReference($rsaRemoveList, "\$rsaRemoveList", $UpdFX::keRefArray);
  1573. foreach my $sDepotFileSpec (@$rsaRemoveList)
  1574. {
  1575. $sResultKey = (_SdExec("delete", $sDepotFileSpec) ? $mscKeyRemove : $mscKeyFailure);
  1576. push(@{$mhSummary{$sResultKey}}, $sDepotFileSpec);
  1577. }
  1578. while (my ($sDepotFileSpec, $uData) = each(%$rhAddList))
  1579. {
  1580. $sResultKey = (UpdFX_UpdateFile($sDepotFileSpec, $uData) &&
  1581. _SdExec("add", $sDepotFileSpec) ? $mscKeyAdd : $mscKeyFailure);
  1582. push(@{$mhSummary{$sResultKey}}, $sDepotFileSpec);
  1583. }
  1584. while (my ($sDepotFileSpec, $uData) = each(%$rhEditList))
  1585. {
  1586. if (! (_SdExec("edit", $sDepotFileSpec) && UpdFX_UpdateFile($sDepotFileSpec, $uData)))
  1587. {
  1588. $sResultKey = $mscKeyFailure;
  1589. }
  1590. else
  1591. {
  1592. $sResultKey = (UpdFX_Dat($uData) ? $mscKeyEdit : $mscKeyChange);
  1593. }
  1594. push(@{$mhSummary{$sResultKey}}, $sDepotFileSpec);
  1595. }
  1596. return ($TRUE);
  1597. }
  1598. # =========================================================================
  1599. # UpdFX_UpdateFile()
  1600. #
  1601. # Purpose:
  1602. # Update a file in the depot
  1603. # Inputs:
  1604. # $sDepotFileSpec Location of the file in the depot
  1605. # $uData An array or a filespec
  1606. # Outputs:
  1607. # Returns $TRUE for success, $FALSE for failure
  1608. # Dependencies:
  1609. # None
  1610. # Notes:
  1611. # =========================================================================
  1612. sub UpdFX_UpdateFile
  1613. {
  1614. my ($sDepotFileSpec, $uData) = @_;
  1615. _RequireArgument($sDepotFileSpec, "\$sDepotFileSpec");
  1616. if (UpdFX_Dat($uData))
  1617. {
  1618. _RequireReference($uData, "\$uData", $UpdFX::keRefArray);
  1619. if (! open(hFile, ">" . $sDepotFileSpec))
  1620. {
  1621. return (_Error("Cannot update file (" . $sDepotFileSpec . ")--" . $!));
  1622. }
  1623. foreach my $sData (@$uData)
  1624. {
  1625. print(hFile $sData);
  1626. }
  1627. return (close(hFile));
  1628. }
  1629. _RequireArgument($uData, "\$uData");
  1630. return (_CopyFile($uData, $sDepotFileSpec));
  1631. }
  1632. # =========================================================================
  1633. # UpdFX_ShowResults()
  1634. #
  1635. # Purpose:
  1636. # Show results of the layout updates
  1637. # Inputs:
  1638. # $bSucceeded Success of layout updates
  1639. # Outputs:
  1640. # None
  1641. # Dependencies:
  1642. # - Windiff must be on the path
  1643. # Notes:
  1644. # =========================================================================
  1645. sub UpdFX_ShowResults
  1646. {
  1647. my ($bSucceeded) = @_;
  1648. if ($bSucceeded)
  1649. {
  1650. #Show results of updates to files
  1651. my $nUpdateCount = @{$mhSummary{$mscKeyChange}} + @{$mhSummary{$mscKeyRemove}} + @{$mhSummary{$mscKeyAdd}};
  1652. my $nTotalCount = @{$mhSummary{$mscKeyEdit}} + @{$mhSummary{$mscKeyFailure}} + $nUpdateCount;
  1653. my @sEyeCatcher =
  1654. (
  1655. "--------------------------------------------------------------------------------------",
  1656. "--------------------------------- PLEASE TAKE NOTE ---------------------------------",
  1657. "--------------------------------------------------------------------------------------",
  1658. );
  1659. my @sResultText =
  1660. (
  1661. "",
  1662. "Detected " . @{$mhSummary{$mscKeyFailure}} . " update failures for " . $nTotalCount . " files",
  1663. "",
  1664. );
  1665. my $sKeyPressed;
  1666. print(join("\n", @sResultText));
  1667. #For each changed data file, show results of update, ask user to verify, and launch windiff on file
  1668. if (@{$mhSummary{$mscKeyEdit}})
  1669. {
  1670. @sResultText =
  1671. (
  1672. "",
  1673. @sEyeCatcher,
  1674. "The filelist for a layout has been modified. As a result,",
  1675. "changes were made to the following data files:",
  1676. "",
  1677. @{$mhSummary{$mscKeyEdit}},
  1678. "",
  1679. "Please ensure these files are correct before submitting changes.",
  1680. "(To aid you in this, windiff will be launched against each file.)",
  1681. "Press ENTER to continue...",
  1682. );
  1683. print(join("\n", @sResultText));
  1684. $sKeyPressed = <STDIN>;
  1685. foreach my $sFileSpec (@{$mhSummary{$mscKeyEdit}})
  1686. {
  1687. my ($sFileDrive, $sFilePath, $sFileName) = _SplitPath($sFileSpec);
  1688. if (defined($mhSummary{$sFileSpec}))
  1689. {
  1690. my $scAProblem = "A potential problem was";
  1691. my $scProblems = "Potential problems were";
  1692. my $nProblems = @{$mhSummary{$sFileSpec}};
  1693. @sResultText =
  1694. (
  1695. "",
  1696. @sEyeCatcher,
  1697. (1 < $nProblems ? $scProblems : $scAProblem) . " detected with " . $sFileSpec . ":",
  1698. );
  1699. foreach my $sProblem (@{$mhSummary{$sFileSpec}})
  1700. {
  1701. push(@sResultText, "- " . $sProblem);
  1702. }
  1703. push(@sResultText, "Press ENTER to continue...");
  1704. print(join("\n", @sResultText));
  1705. $sKeyPressed = <STDIN>;
  1706. }
  1707. print("Windiff'ing " . $sFileSpec . "...\n");
  1708. chdir($sFileDrive . $sFilePath);
  1709. system("start /max /wait windiff /L " . $sFileName);
  1710. }
  1711. }
  1712. #If we made any changes, display instructions for testing and submitting them
  1713. if (0 < $nUpdateCount)
  1714. {
  1715. my ($sDataFileBuildRoot) = ($msBinplaceDataFileSpec =~ /(.+)\\/);
  1716. my @sInstructions =
  1717. (
  1718. "",
  1719. @sEyeCatcher,
  1720. "If you need to add, remove, or change additional files beyond those processed",
  1721. "by UpdFX /update, make sure you do it in the numbered changelists created by",
  1722. "this script. To find the correct number for each file, cd to the file's folder",
  1723. "and enter 'sd opened'. This will list the file changes you have pending in that",
  1724. "folder's depot and the changelist number associated with each.",
  1725. "",
  1726. @sEyeCatcher,
  1727. "Before submitting any changes, you should perform a number of test builds.",
  1728. "Skipping this may cause VBL BUILD BREAKS and BLOCK LARGE NUMBERS OF PEOPLE!!!",
  1729. "",
  1730. "At minimum your test matrix should cover free/checked and 32/64bit intel variants.",
  1731. "Each variant MUST be built in a separate console window, and each build console",
  1732. "must be initialized with the proper command:",
  1733. "",
  1734. "chk/32: razzle",
  1735. "chk/64: razzle win64",
  1736. "fre/32: razzle free",
  1737. "fre/64: razzle free win64",
  1738. "",
  1739. "After you've initialized each build console, run the following commands:",
  1740. "",
  1741. "revert_public",
  1742. "cd /d " . $sDataFileBuildRoot,
  1743. "build -cZ",
  1744. "cd /d " . $msNetFxRoot,
  1745. "build -cZ",
  1746. "",
  1747. "(If a machine hosts more than one console, you have to wait for each build",
  1748. "to finish before you start the next--i.e. no parallel builds.)",
  1749. "",
  1750. "A build is successful if there were no errors caused by your changes and",
  1751. "all layout files were propagated to the binaries directory. (The title of",
  1752. "the console tells you where the binaries dir is located.)",
  1753. "",
  1754. "If the 1st set of builds succeeded, you should run fully buddy builds on",
  1755. "\\\\netfxbld. These should also be done on at least the minimum set of build",
  1756. "variants (one at a time) and can be invoked by running \"buddy\" from the",
  1757. "netfx directory.",
  1758. "",
  1759. "If all builds are successful, you can submit the changes with UpdFX /submit.",
  1760. "If you want to back out the changes, you can do this with UpdFX /revert.",
  1761. );
  1762. print(join("\n", (@sInstructions, "")));
  1763. }
  1764. }
  1765. }
  1766. # =========================================================================
  1767. # UpdFX_SubmitChanges()
  1768. #
  1769. # Purpose:
  1770. # Submit all pending changes in the netfx changelists
  1771. # Inputs:
  1772. # None
  1773. # Outputs:
  1774. # None
  1775. # Dependencies:
  1776. # None
  1777. # Notes:
  1778. # =========================================================================
  1779. sub UpdFX_SubmitChanges
  1780. {
  1781. my $bSucceeded = $FALSE;
  1782. my @sChangeList;
  1783. push(@sChangeList, _SdExec("opened", $msNetFxRoot . "\\..."));
  1784. push(@sChangeList, _SdExec("opened", $msSdxRoot . "\\..."));
  1785. if (@sChangeList)
  1786. {
  1787. my $sKeyPressed;
  1788. _Warning("You are about to submit all changes in the netfx changelists");
  1789. print("Press ENTER to review these changes...");
  1790. $sKeyPressed = <STDIN>;
  1791. print(@sChangeList, "\n");
  1792. print("Press ENTER to submit these changes or Ctrl+C to exit...");
  1793. $sKeyPressed = <STDIN>;
  1794. if ("\n" eq $sKeyPressed)
  1795. {
  1796. $bSucceeded = _SdExec("submit", $msNetFxRoot . "\\...");
  1797. $bSucceeded = _SdExec("submit", $msSdxRoot . "\\...") && $bSucceeded;
  1798. }
  1799. }
  1800. else
  1801. {
  1802. _Error("No changes to submit in netfx changelists");
  1803. }
  1804. return ($bSucceeded);
  1805. }
  1806. # =========================================================================
  1807. # UpdFX_RevertChanges()
  1808. #
  1809. # Purpose:
  1810. # Revert all pending changes in the netfx changelists
  1811. # Inputs:
  1812. # None
  1813. # Outputs:
  1814. # None
  1815. # Dependencies:
  1816. # None
  1817. # Notes:
  1818. # =========================================================================
  1819. sub UpdFX_RevertChanges
  1820. {
  1821. my $bSucceeded = $FALSE;
  1822. my @sChangeList;
  1823. push(@sChangeList, _SdExec("opened", $msNetFxRoot . "\\..."));
  1824. push(@sChangeList, _SdExec("opened", $msSdxRoot . "\\..."));
  1825. if (@sChangeList)
  1826. {
  1827. my @sDeleteList = grep(/- add change \d+ \(/, @sChangeList);
  1828. my $sKeyPressed;
  1829. _Warning("You are about to revert all changes in the netfx changelists");
  1830. print("Press ENTER to review these changes...");
  1831. $sKeyPressed = <STDIN>;
  1832. print(@sChangeList, "\n");
  1833. if (@sDeleteList)
  1834. {
  1835. print("These files will be deleted after the changes are reverted:\n", @sDeleteList, "\n");
  1836. }
  1837. print("Press ENTER to revert these changes or Ctrl+C to exit...");
  1838. $sKeyPressed = <STDIN>;
  1839. if ("\n" eq $sKeyPressed)
  1840. {
  1841. my %hDirsToRemove;
  1842. $bSucceeded = _SdExec("revert", $msNetFxRoot . "\\...");
  1843. $bSucceeded = _SdExec("revert", $msSdxRoot . "\\...") && $bSucceeded;
  1844. foreach my $sChange (@sDeleteList)
  1845. {
  1846. my ($sFileSpec) = ($sChange =~ /(.+)#/);
  1847. my ($sFileDrive, $sFilePath) = _SplitPath($sFileSpec);
  1848. if (1 != unlink($sFileSpec))
  1849. {
  1850. _Error("Cannot delete file (" . $sFileSpec . ")--" . $!);
  1851. $bSucceeded = $FALSE;
  1852. }
  1853. else
  1854. {
  1855. $hDirsToRemove{lc($sFileDrive . $sFilePath)}++;
  1856. }
  1857. }
  1858. #If any dirs were added as a side-effect of adding files, get rid of them
  1859. foreach my $sDir (keys(%hDirsToRemove))
  1860. {
  1861. $sDir =~ s/\\+$//;
  1862. while (0 == _GetDirList($sDir))
  1863. {
  1864. rmdir($sDir);
  1865. $sDir =~ s/\\[^\\]+$//;
  1866. }
  1867. }
  1868. }
  1869. }
  1870. else
  1871. {
  1872. _Error("No changes to revert in netfx changelists");
  1873. }
  1874. return ($bSucceeded);
  1875. }
  1876. # =========================================================================
  1877. # UpdFX_MakeSetupCabs()
  1878. #
  1879. # Purpose:
  1880. # Create/update setup cabs
  1881. # Inputs:
  1882. # None
  1883. # Outputs:
  1884. # Returns $TRUE for success, $FALSE for failure
  1885. # Dependencies:
  1886. # None
  1887. # Notes:
  1888. # =========================================================================
  1889. sub UpdFX_MakeSetupCabs
  1890. {
  1891. my $nSucceeded = 0;
  1892. foreach my $sDdfFileSpec (@{$mhParsedArgs{"docabs"}})
  1893. {
  1894. if (! open(hFile, "<" . $sDdfFileSpec))
  1895. {
  1896. _Error("Cannot open ddf file (" . $sDdfFileSpec . ") to obtain cab name--" . $!);
  1897. next;
  1898. }
  1899. my $scCabNameTag = "CabinetNameTemplate";
  1900. my $sCabFileName;
  1901. my @sDdfText = <hFile>;
  1902. close(hFile);
  1903. foreach my $sDdfLine (@sDdfText)
  1904. {
  1905. if ($sDdfLine =~ /$scCabNameTag/)
  1906. {
  1907. ($sCabFileName) = ($sDdfLine =~ /"(.+)"/);
  1908. last;
  1909. }
  1910. }
  1911. if (! defined($sCabFileName))
  1912. {
  1913. if ($sDdfLine =~ /$scCabNameTag/)
  1914. {
  1915. _Error("Cannot extract cab name from definition line (" . $sDdfLine . ") " .
  1916. "in ddf file (" . $sDdfFileSpec . ")");
  1917. }
  1918. else
  1919. {
  1920. _Error("Cannot find cab name in ddf file (" . $sDdfFileSpec . ")");
  1921. }
  1922. next;
  1923. }
  1924. my ($sFileDrive, $sFilePath, $sDdfFileName) = _SplitPath($sDdfFileSpec);
  1925. my $sCabFileSpec = $sFileDrive . $sFilePath . $sCabFileName;
  1926. my @sFileData = _SdExec("files", $sCabFileSpec);
  1927. if ((defined(@sFileData)) && (! _SdExec("edit", $sCabFileSpec)))
  1928. {
  1929. _Error("Cannot check out cab file (" . $sCabFileSpec . ") for update");
  1930. next;
  1931. }
  1932. my $sCmdLine = "makecab /f " . $sDdfFileSpec;
  1933. print($sCmdLine . "\n");
  1934. if (0 == system($sCmdLine))
  1935. {
  1936. $nSucceeded++
  1937. }
  1938. }
  1939. return (@{$mhParsedArgs{"docabs"}} == $nSucceeded);
  1940. }
  1941. # =========================================================================
  1942. # UpdFX_Exit()
  1943. #
  1944. # Purpose:
  1945. # Execute closure tasks
  1946. # Inputs:
  1947. # $bSucceeded Success of primary tasks
  1948. # Outputs:
  1949. # Returns $TRUE for success, $FALSE for failure
  1950. # Dependencies:
  1951. # None
  1952. # Notes:
  1953. # - This routine simply returns its input param for now, but might be
  1954. # modified in future to base the return value on one or more exit ops
  1955. # =========================================================================
  1956. sub UpdFX_Exit
  1957. {
  1958. my ($bSucceeded) = @_;
  1959. return ($bSucceeded);
  1960. }
  1961. # =========================================================================
  1962. # UpdFX_ShowHelp()
  1963. #
  1964. # Purpose:
  1965. # Display help
  1966. # Inputs:
  1967. # None
  1968. # Outputs:
  1969. # None
  1970. # Dependencies:
  1971. # None
  1972. # Notes:
  1973. # =========================================================================
  1974. sub UpdFX_ShowHelp
  1975. {
  1976. my @sHelpText =
  1977. (
  1978. "",
  1979. "Usage:",
  1980. "",
  1981. @{$mhcScriptUsage{"usage"}},
  1982. "",
  1983. "Notes:",
  1984. "",
  1985. @{$mhcScriptUsage{"notes"}},
  1986. "",
  1987. );
  1988. print(join("\n", @sHelpText));
  1989. }
  1990. # =========================================================================
  1991. # =========================================================================