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.

1530 lines
45 KiB

  1. //
  2. // task.js
  3. //
  4. // Patrick Franklin 9/27/99
  5. //
  6. // DESCRIPTION:
  7. // This function is called to perform the tasks of actually sync'ing
  8. // and building.
  9. //
  10. Include('types.js');
  11. Include('utils.js');
  12. Include('staticstrings.js');
  13. Include('slavetask.js');
  14. Include('robocopy.js');
  15. // File System Object
  16. var g_FSObj;// = new ActiveXObject("Scripting.FileSystemObject");
  17. var g_fAbort = false;
  18. var g_ErrLog = null;
  19. var g_SyncLog = null;
  20. var g_MachineName = LocalMachine;
  21. var g_RetrySD = false;
  22. var g_strDelayedExitMessage = null;
  23. var g_fSDClientError = false; // When set we need to do special processing of the SD output
  24. var g_hTasks;
  25. // Global flags for syncing and parsing results
  26. var g_strTaskFlag;
  27. var g_strStepFlag;
  28. var g_strExitFlag;
  29. var g_strScriptSyncFlag; // Internal to this script
  30. var g_fIsBetweenSteps;
  31. var g_fIsRoot;
  32. var g_fIsMerged;
  33. var g_strMergeFile='';
  34. var g_cErrors = 0; // Used to track error count during file copy operations.
  35. var g_Depot;
  36. var g_strDepotName;
  37. var g_Task;
  38. var g_DepotIdx;
  39. var g_TaskIdx;
  40. var g_fAbort = false;
  41. var g_robocopy;
  42. var g_pid; // The PID of the currently running process.
  43. var g_aMergedPos = [0, 0];
  44. // Global Definitions
  45. var g_reSDRetryText = new RegExp(": (WSAECONNREFUSED|WSAETIMEDOUT)");
  46. var RESOLVE = 'resolve';
  47. var REVERT = 'revert';
  48. var PASS0 = 'pass0';
  49. var COMPILE = 'compile';
  50. var LINK = 'link';
  51. var STATUS = 'status';
  52. var EXITED = 'exited';
  53. var SYNC_STATUS_UPDATE_INTERVAL = 3000; // Check once every 3 seconds for updated sync status
  54. var WAIT_FOR_PROCESS_EXIT_TIME = 5 * 1000; // During abort, wait this long for a process to terminate
  55. // Constants for controlling SD.exe command retry operations.
  56. var INITIAL_RETRY_DELAY = (10 * 1000) // Wait 10 seconds before we retry
  57. var MAX_RETRY_DELAY = (5 * 60 * 1000) // Wait at most 5 minutes between SD attempts
  58. var MAX_TOTAL_RETRY_TIME = (30 * 60 * 1000) // Wait no more than 30 minutes for SD to succeed
  59. var strRetryNow = "DoubleClickToRetryNow";
  60. /*************************************************************************
  61. *
  62. * Functions
  63. *
  64. *************************************************************************/
  65. function task_js::OnScriptError(strFile, nLine, nChar, strText, sCode, strSource, strDescription)
  66. {
  67. var vRet = 1;
  68. var strDepotName = '';
  69. try
  70. {
  71. SignalThreadSync(g_strAbortTask); // Tell 'task.js' to exit ASAP
  72. SignalThreadSync(g_strExitFlag); // Play dead -- lie to slave.js and say we terminated.
  73. if (g_strDepotName)
  74. strDepotName = g_strDepotName;
  75. vRet = CommonOnScriptError("task_js(" + LocalMachine + "," + g_strDepotName + ")", strFile, nLine, nChar, strText, sCode, strSource, strDescription);
  76. // Tell all our tasks to terminate
  77. // Once this function returns, strScript.js will stop executing.
  78. g_fAbort = true;
  79. }
  80. catch(ex)
  81. {
  82. }
  83. if (g_pid)
  84. {
  85. TerminateProcess(g_pid);
  86. g_pid = null;
  87. }
  88. return vRet;
  89. }
  90. function SPLogMsg(msg)
  91. {
  92. LogMsg('(' + g_strDepotName + ') ' + msg, 1);
  93. }
  94. function SPSignalThreadSync(signal)
  95. {
  96. LogMsg('(' + g_strDepotName + ') Signalling ' + signal, 1);
  97. SignalThreadSync(signal);
  98. }
  99. //
  100. // ScriptMain()
  101. //
  102. // DESCRIPTION:
  103. // This script is called to perform the operation in the supplied task.
  104. //
  105. // RETURNS:
  106. // none
  107. //
  108. function task_js::ScriptMain()
  109. {
  110. var ii;
  111. var aParams;
  112. var strSyncFlag;
  113. var strSDRoot;
  114. var iRet;
  115. var strBuildType;
  116. var strBuildPlatform;
  117. try
  118. {
  119. InitTasks();
  120. // Parse input Parameter List
  121. aParams = ScriptParam.split(',');
  122. g_strTaskFlag = aParams[0]; // Sync Flag
  123. g_strStepFlag = aParams[1]; // Step Flag
  124. g_strExitFlag = aParams[2]; // Exit Flag
  125. strSDRoot = aParams[3]; // SD Root
  126. g_DepotIdx = aParams[4]; // Depot Index
  127. g_TaskIdx = aParams[5]; // Task Index
  128. // Signal that the Task is started
  129. SignalThreadSync(g_strTaskFlag);
  130. CommonVersionCheck(/* $DROPVERSION: */ "V(########) F(!!!!!!!!!!!!!!)" /* $ */);
  131. g_strTaskFlag += ',AStepFinished';
  132. // Get global handles the Depot and Task
  133. g_Depot = PublicData.aBuild[0].aDepot[g_DepotIdx];
  134. // Grab a local copy of the depot name for OnScriptError
  135. // because if slave_js has crashed, OnScriptError will be
  136. // unable to deference g_Depot.
  137. g_strDepotName = g_Depot.strName;
  138. g_Task = PublicData.aBuild[0].aDepot[g_DepotIdx].aTask[g_TaskIdx]
  139. // Initialize error counts and mark the task as in progress
  140. g_Task.strStatus = NOTSTARTED;
  141. g_Task.cFiles = 0;
  142. g_Task.cResolved = 0;
  143. g_Task.cErrors = 0;
  144. g_Task.cWarnings = 0;
  145. g_Task.fSuccess = true;
  146. g_fIsRoot = g_Depot.strName.toLowerCase() == g_strRootDepotName;
  147. g_fIsMerged = g_Depot.strName.toLowerCase() == g_strMergedDepotName;
  148. g_FSObj = new ActiveXObject("Scripting.FileSystemObject"); // Parse input Parameter List
  149. SPLogMsg(g_Task.strName + ' task thread for ' + g_Depot.strName + ' launched & waiting.');
  150. // Wait until instructed to step
  151. iRet = WaitAndAbort(g_strStepFlag, 0, null);
  152. SignalThreadSync(g_strStepAck);
  153. if (iRet == 0)
  154. ThrowError("Task abort on start", strSDRoot);
  155. SPLogMsg(g_Task.strName + ' task thread for ' + g_Depot.strName + ' started.');
  156. ResetSync(g_strStepFlag);
  157. g_Task.strStatus = INPROGRESS;
  158. g_Task.dateStart = new Date().toUTCString();
  159. FireUpdateEvent();
  160. JAssert(g_Depot.strName.toLowerCase() == g_strRootDepotName || (g_Depot.strPath.toLowerCase() == (strSDRoot.toLowerCase() + '\\' + g_Depot.strName.toLowerCase())),
  161. 'Mismatched depot and path! (' + g_Depot.strPath + ', ' + strSDRoot + '\\' + g_Depot.strName + ')');
  162. // Check to see what task is to be executed and go
  163. g_strScriptSyncFlag = g_Depot.strPath + 'InternalTaskFinished';
  164. ResetSync(g_strScriptSyncFlag);
  165. if (g_hTasks[g_Task.strName])
  166. {
  167. if (!g_hTasks[g_Task.strName](strSDRoot))
  168. {
  169. OnError('Error during ' + g_Task.strName + '.', null, g_Task.cErrors != 0);
  170. }
  171. }
  172. }
  173. catch(ex)
  174. {
  175. SPLogMsg("task.js exception occurred : " + ex);
  176. OnError('task.js exception occurred : ' + ex);
  177. }
  178. SPLogMsg(g_Task.strName + ' for ' + g_Depot.strName + ' completed.');
  179. // Mark the Task as complete.
  180. g_Task.strStatus = COMPLETED;
  181. g_Task.dateFinish = new Date().toUTCString();
  182. if (g_Task.fSuccess)
  183. g_Depot.strStatus = WAITING;
  184. else
  185. {
  186. g_Depot.strStatus = ERROR;
  187. SPLogMsg("Set Depot Status to error 1");
  188. }
  189. FireUpdateEvent();
  190. try
  191. {
  192. if (g_ErrLog)
  193. g_ErrLog.Close();
  194. if (g_SyncLog)
  195. g_SyncLog.Close();
  196. }
  197. catch(ex)
  198. {
  199. }
  200. if (g_robocopy != null)
  201. g_robocopy.UnRegister();
  202. // Signal that the Task is done and that a Step has finished
  203. SignalThreadSync(g_strTaskFlag + ',' + g_strExitFlag);
  204. }
  205. function InitTasks()
  206. {
  207. g_hTasks = new Object();
  208. g_hTasks[SCORCH] = taskScorchFiles;
  209. g_hTasks[SYNC] = taskSyncFiles;
  210. g_hTasks[BUILD] = taskBuildFiles;
  211. g_hTasks[COPYFILES] = taskCopyFiles;
  212. g_hTasks[POSTBUILD] = taskPostBuild;
  213. }
  214. function task_js::OnEventSourceEvent(RemoteObj, DispID, cmd, params)
  215. {
  216. var objRet = new Object;
  217. objRet.rc = 0;
  218. try
  219. {
  220. if (g_robocopy == null || !g_robocopy.OnEventSource(objRet, arguments))
  221. {
  222. }
  223. }
  224. catch(ex)
  225. {
  226. JAssert(false, "an error occurred in OnEventSourceEvent() \n" + ex);
  227. }
  228. return objRet.rc;
  229. }
  230. function DoRetryableSDCommand(strOperation, strStatus, objDepot, objTask, strTitle, strNewCmd)
  231. {
  232. var iRet;
  233. strTitle = strTitle + ' ' + objDepot.strName;
  234. var nTimeout = INITIAL_RETRY_DELAY ;
  235. var nTotalWaitTime = 0;
  236. var strMsg;
  237. do
  238. {
  239. if (g_RetrySD)
  240. {
  241. FireUpdateEvent();
  242. ResetSync(g_strScriptSyncFlag);
  243. SPLogMsg("Waiting " + nTimeout / 1000 + " seconds before retry");
  244. ResetSync(strRetryNow);
  245. WaitAndAbort(strRetryNow, nTimeout, null);
  246. nTotalWaitTime += nTimeout;
  247. nTimeout *= 2; // Double the delay
  248. if (nTimeout > MAX_RETRY_DELAY)
  249. nTimeout = MAX_RETRY_DELAY;
  250. }
  251. if (g_fAbort)
  252. break;
  253. objTask.strOperation = strOperation;
  254. objDepot.strStatus = strStatus;
  255. g_RetrySD = false;
  256. if (g_pid = MyRunLocalCommand(strNewCmd, objDepot.strPath, strTitle, true, true, false)) {
  257. objTask.strStatus = INPROGRESS;
  258. } else {
  259. g_ErrLog.WriteLine('Unable to execute command (' + GetLastRunLocalError() + '): ' + strNewCmd);
  260. return false;
  261. }
  262. SPLogMsg(strOperation + ' for ' + objDepot.strName + ' started. PID='+g_pid);
  263. iRet = WaitAndAbortParse(g_strScriptSyncFlag, g_pid, false);
  264. g_fSDClientError = false;
  265. }
  266. while (g_RetrySD && !g_fAbort && nTotalWaitTime < MAX_TOTAL_RETRY_TIME);
  267. if (g_Task.nRestarted > 0)
  268. {
  269. if (g_RetrySD || !g_Task.fSuccess)
  270. {
  271. strMsg = strOperation + " failed after retrying " + g_Task.nRestarted + " times";
  272. g_ErrLog.Writeline(strMsg);
  273. OnError(strMsg);
  274. }
  275. else
  276. g_ErrLog.Writeline(strOperation + " completed successfully after retrying " + g_Task.nRestarted + " times");
  277. }
  278. g_pid = null;
  279. return iRet;
  280. }
  281. //
  282. // taskScorch Files
  283. //
  284. // DESCRIPTION:
  285. // This routine handles the process of actually Scorch'ing the files.
  286. // Scorch'ing has two phases.
  287. //
  288. // 1. revert_public
  289. // 2. Scorch
  290. //
  291. // RETURNS:
  292. // true - if successful
  293. // false - if failure
  294. //
  295. // TODO: make a subroutine to handle errlog and Scorchlog
  296. function taskScorchFiles(strSDRoot)
  297. {
  298. var strNewCmd;
  299. var strParams = '';
  300. var iRet;
  301. // Open the log files
  302. g_ErrLog = LogCreateTextFile(g_FSObj, g_Task.strErrLogPath, true);
  303. g_SyncLog = LogCreateTextFile(g_FSObj, g_Task.strLogPath, true);
  304. if (g_fIsRoot && !PrivateData.objConfig.Options.fIncremental)
  305. {
  306. //
  307. // revert public
  308. //
  309. if (PrivateData.objConfig.Options.RevertParams)
  310. strParams = PrivateData.objConfig.Options.RevertParams;
  311. strNewCmd = MakeRazzleCmd(strSDRoot) + ' && revert_public.cmd ' + strParams + ' 2>&1';
  312. // Run the Command
  313. iRet = DoRetryableSDCommand(REVERT, SCORCHING, g_Depot, g_Task, "Revert_Public", strNewCmd);
  314. if (iRet == 0 || g_Task.fSuccess == false)
  315. return false;
  316. //
  317. // Scorch
  318. //
  319. ResetSync(g_strScriptSyncFlag);
  320. g_Task.strOperation = SCORCH;
  321. FireUpdateEvent();
  322. if (PrivateData.objConfig.Options.ScorchParams)
  323. strParams = PrivateData.objConfig.Options.ScorchParams;
  324. else
  325. strParams = '';
  326. // Construct Command
  327. strNewCmd = MakeRazzleCmd(strSDRoot) + ' && nmake -lf makefil0 scorch_source ' + strParams + ' 2>&1';
  328. // Run the Command
  329. iRet = DoRetryableSDCommand(SCORCH, SCORCHING, g_Depot, g_Task, "Scorch", strNewCmd);
  330. if (iRet == 0 || g_Task.fSuccess == false)
  331. return false;
  332. }
  333. return true;
  334. }
  335. //
  336. // taskSyncFiles
  337. //
  338. // DESCRIPTION:
  339. // This routine handles the process of actually sync'ing the files.
  340. // Sync'ing has two phases.
  341. //
  342. // 1. Sync
  343. // 2. Resolve
  344. //
  345. // RETURNS:
  346. // true - if successful
  347. // false - if failure
  348. //
  349. // TODO: make a subroutine to handle errlog and synclog
  350. function taskSyncFiles(strSDRoot)
  351. {
  352. var strNewCmd;
  353. var strParams = '';
  354. var iRet;
  355. // Open the log files
  356. g_ErrLog = LogCreateTextFile(g_FSObj, g_Task.strErrLogPath, true);
  357. g_SyncLog = LogCreateTextFile(g_FSObj, g_Task.strLogPath, true);
  358. //
  359. // Sync the files
  360. //
  361. if (PrivateData.objConfig.Options.SyncParams)
  362. strParams = PrivateData.objConfig.Options.SyncParams;
  363. // Construct the new Cmd
  364. strNewCmd = MakeRazzleCmd(strSDRoot) + ' && sd -s sync ' + strParams + ' 2>&1';
  365. // Run the Command
  366. iRet = DoRetryableSDCommand(SYNC, SYNCING, g_Depot, g_Task, "Sync", strNewCmd);
  367. if (iRet == 0 || g_Task.fSuccess == false)
  368. return false;
  369. //
  370. // Resolve any merge conflicts
  371. //
  372. ResetSync(g_strScriptSyncFlag);
  373. g_Task.strOperation = RESOLVE;
  374. FireUpdateEvent();
  375. if (PrivateData.objConfig.Options.ResolveParams)
  376. strParams = PrivateData.objConfig.Options.ResolveParams;
  377. else
  378. strParams = '';
  379. // Construct Command
  380. strNewCmd = MakeRazzleCmd(strSDRoot) + ' && sd -s resolve -af ' + strParams + ' 2>&1';
  381. // Run the Command
  382. iRet = DoRetryableSDCommand(RESOLVE, SYNCING, g_Depot, g_Task, "Resolve", strNewCmd);
  383. if (iRet == 0 || g_Task.fSuccess == false)
  384. return false;
  385. return true;
  386. }
  387. function WaitAndAbortParse(strScriptSyncFlag, pid, fPostBuild)
  388. {
  389. var nEvent;
  390. g_nSyncParsePosition = 0;
  391. do
  392. {
  393. nEvent = WaitAndAbort(strScriptSyncFlag, SYNC_STATUS_UPDATE_INTERVAL, pid);
  394. if (g_fAbort)
  395. return nEvent;
  396. if (nEvent == 0)
  397. HandleParseEvent(pid, "update", 0, fPostBuild);
  398. }
  399. while(nEvent == 0);
  400. // After SYNC exits, check to see if we have a delayed error message
  401. if (g_strDelayedExitMessage)
  402. {
  403. g_ErrLog.WriteLine('SD unexpectedly exited with one or more errors.');
  404. g_ErrLog.Writeline(g_strDelayedExitMessage );
  405. OnError(g_strDelayedExitMessage);
  406. }
  407. return nEvent;
  408. }
  409. //
  410. // taskBuildFiles
  411. //
  412. // DESCRIPTION:
  413. // This routine handles the process of actually buldinging the files.
  414. // building requires only a signal command but reports status after
  415. // each pass.
  416. //
  417. // When each pass completes the status should be updated and then
  418. // the process should continue.
  419. //
  420. //
  421. // RETURNS:
  422. // true - if successful
  423. // false - if failure
  424. //
  425. function taskBuildFiles(strSDRoot)
  426. {
  427. var nTracePoint = 0;
  428. try
  429. {
  430. var strNewCmd;
  431. var strTitle;
  432. var iSignal;
  433. var strParams = '';
  434. var strDepotExcl = '';
  435. var strLogOpt = "-j build_" + g_Depot.strName + " -jpath " + PrivateData.strLogDir;
  436. var strCleanBuild = "-c";
  437. //
  438. // Build the files
  439. //
  440. g_Task.strOperation = PASS0;
  441. // Construct Command Elements
  442. strTitle = 'Build ' + g_Depot.strName;
  443. if (PrivateData.objConfig.Options.BuildParams)
  444. strParams = PrivateData.objConfig.Options.BuildParams;
  445. if (PrivateData.objConfig.Options.fIncremental)
  446. strCleanBuild = "";
  447. if (g_fIsRoot)
  448. {
  449. strDepotExcl = '~' + PrivateData.aDepotList.join(' ~');
  450. strLogOpt = "-j build_2" + g_Depot.strName + " -jpath " + PrivateData.strLogDir;
  451. }
  452. if (g_fIsMerged)
  453. strLogOpt = "-j build_merged" + " -jpath " + PrivateData.strLogDir;
  454. strNewCmd = MakeRazzleCmd(strSDRoot) + ' && build -3 ' + strCleanBuild + ' -p ' + strLogOpt + ' ' + strParams + ' ' + strDepotExcl + ' 2>&1';
  455. g_Depot.strStatus = BUILDING;
  456. // Execute Command
  457. if (g_pid = MyRunLocalCommand(strNewCmd, g_Depot.strPath, strTitle, true, false, false)) {
  458. g_Task.strStatus = INPROGRESS;
  459. } else {
  460. AppendToFile(g_ErrLog, g_Task.strErrLogPath, 'Unable to execute command (' + GetLastRunLocalError() + '): ' + strNewCmd);
  461. return false;
  462. }
  463. SPLogMsg('Build for ' + g_Depot.strName + ' started. PID='+g_pid);
  464. FireUpdateEvent();
  465. nTracePoint = 1;
  466. // Wait for Command to complete
  467. g_fIsBetweenSteps = false;
  468. do
  469. {
  470. nTracePoint = 2;
  471. iSignal = WaitAndAbort(g_strScriptSyncFlag + ',' + g_strStepFlag, 0, g_pid);
  472. if (g_fAbort)
  473. return false;
  474. nTracePoint = 3;
  475. if (iSignal == 2)
  476. {
  477. var iSend;
  478. // We've been told to move to the next pass in the build.
  479. // Indicate that we received the signal
  480. // BUGBUG Extra debug info messages
  481. //SPLogMsg("SignalThreadSync(" + g_strStepAck + ");");
  482. SignalThreadSync(g_strStepAck);
  483. nTracePoint = 4;
  484. ResetSync(g_strStepFlag);
  485. JAssert(g_fIsBetweenSteps, 'Bug in slave.js or harness.js! Told to step when we werent waiting.');
  486. g_Depot.strStatus = BUILDING;
  487. g_fIsBetweenSteps = false;
  488. // Continue on
  489. SPLogMsg("TASK STEPPING " + g_Depot.strName);
  490. iSend = SendToProcess(g_pid, 'resume', '');
  491. nTracePoint = 5;
  492. if (iSend != 0)
  493. {
  494. nTracePoint = 5.5;
  495. SPLogMsg('SendToProcess on pid ' + g_pid + ' returned ' + iSend);
  496. }
  497. nTracePoint = 6;
  498. FireUpdateEvent();
  499. }
  500. nTracePoint = 7;
  501. } while (iSignal == 2);
  502. g_pid = null;
  503. return true;
  504. }
  505. catch(ex)
  506. {
  507. SPLogMsg("exception caught, TracePoint = " + nTracePoint + " " + ex);
  508. throw ex;
  509. }
  510. }
  511. //+---------------------------------------------------------------------------
  512. //
  513. // Function: taskCopyFiles
  514. //
  515. // Synopsis: Copy the log files and other stuff necessary for postbuild.
  516. //
  517. // Arguments: [strSDRoot] -- Enlistment root
  518. //
  519. //----------------------------------------------------------------------------
  520. function taskCopyFiles(strSDRoot)
  521. {
  522. var strDestDir;
  523. var i;
  524. g_SyncLog = LogCreateTextFile(g_FSObj, g_Task.strLogPath, true);
  525. g_SyncLog.WriteLine("Copying log files");
  526. SPLogMsg("taskCopyFiles");
  527. if (PrivateData.objEnviron.BuildManager.PostBuildMachine == LocalMachine)
  528. {
  529. // Do nothing - this is the postbuild machine.
  530. /*
  531. for (i = 0; i < PrivateData.objEnviron.Machine.length; ++i)
  532. {
  533. if (PrivateData.objEnviron.Machine[i].Name == PrivateData.objEnviron.BuildManager.PostBuildMachine)
  534. {
  535. strDestDir = MakeUNCPath(PrivateData.objEnviron.BuildManager.PostBuildMachine, "Build_Logs", BUILDLOGS);
  536. CopyLogFiles(strDestDir, true);
  537. }
  538. }
  539. */
  540. }
  541. else
  542. {
  543. // Copy my logfiles to the postbuild machine.
  544. for (i = 0; i < PrivateData.objEnviron.Machine.length; ++i)
  545. {
  546. if (PrivateData.objEnviron.Machine[i].Name == PrivateData.objEnviron.BuildManager.PostBuildMachine)
  547. {
  548. strDestDir = MakeUNCPath(PrivateData.objEnviron.BuildManager.PostBuildMachine, "Build_Logs", BUILDLOGS);
  549. CopyBinariesFiles(PrivateData.objEnviron.Machine[i].Enlistment);
  550. CopyLogFiles(strDestDir);
  551. }
  552. }
  553. }
  554. SPLogMsg("End of copyfiles");
  555. return true;
  556. }
  557. //+---------------------------------------------------------------------------
  558. //
  559. // Function: taskPostBuild
  560. //
  561. // Synopsis: Does post build processing to create a setup version of
  562. // the product.
  563. //
  564. // Arguments: [strSDRoot] -- Enlistment root
  565. //
  566. //----------------------------------------------------------------------------
  567. function taskPostBuild(strSDRoot)
  568. {
  569. var iRet;
  570. var strNewCmd;
  571. var strTitle;
  572. var strParams = '';
  573. if (PrivateData.fIsStandalone == true || PrivateData.objEnviron.BuildManager.PostBuildMachine == LocalMachine)
  574. {
  575. JAssert(g_fIsRoot, 'taskPostBuild called on a non-root depot!');
  576. g_Task.strOperation = POSTBUILD;
  577. g_ErrLog = LogCreateTextFile(g_FSObj, g_Task.strErrLogPath, true);
  578. g_SyncLog = LogCreateTextFile(g_FSObj, g_Task.strLogPath, true);
  579. // Construct Command Elements
  580. strTitle = 'PostBuild';
  581. if (PrivateData.objConfig.Options.PostbuildParams)
  582. strParams = PrivateData.objConfig.Options.PostbuildParams;
  583. strNewCmd = MakeRazzleCmd(strSDRoot);
  584. strNewCmd += ' & perl ' + strSDRoot + '\\Tools\\populatefromvbl.pl -verbose -checkbinplace -force';
  585. strNewCmd += ' && postbuild.cmd ' + strParams + ' 2>&1';
  586. g_Depot.strStatus = POSTBUILD;
  587. // Execute Command
  588. if (g_pid = MyRunLocalCommand(strNewCmd, g_Depot.strPath, strTitle, true, true, false)) {
  589. g_Task.strStatus = INPROGRESS;
  590. } else {
  591. g_ErrLog.WriteLine('Unable to execute command (' + GetLastRunLocalError() + '): ' + strNewCmd);
  592. return false;
  593. }
  594. SPLogMsg('Postbuild started. PID='+g_pid);
  595. FireUpdateEvent();
  596. iRet = WaitAndAbortParse(g_strScriptSyncFlag, g_pid, true);
  597. FireUpdateEvent();
  598. if (iRet == 0 || g_Task.fSuccess == false)
  599. return false;
  600. g_pid = null;
  601. }
  602. else
  603. {
  604. AppendToFile(g_SyncLog, g_Task.strLogPath, "postbuild not necessary on this machine.");
  605. }
  606. return true;
  607. }
  608. //
  609. // OnProcessEvent
  610. //
  611. // DESCRIPTION:
  612. // This routine is called when the command issues by RunLocalCommand
  613. // is completed
  614. //
  615. // RETURNS:
  616. // none
  617. //
  618. function task_js::OnProcessEvent(pid, evt, param)
  619. {
  620. try
  621. {
  622. switch (g_Task.strOperation)
  623. {
  624. case REVERT:
  625. case SCORCH:
  626. case SYNC:
  627. case RESOLVE:
  628. HandleParseEvent(pid, evt, param, false);
  629. SignalThreadSync(g_strScriptSyncFlag);
  630. break;
  631. case PASS0:
  632. case COMPILE:
  633. case LINK:
  634. if (ParseBuildMessages(pid, evt, param) == 'exited') {
  635. FireUpdateEvent();
  636. SignalThreadSync(g_strScriptSyncFlag);
  637. }
  638. break;
  639. case POSTBUILD:
  640. HandleParseEvent(pid, evt, param, true);
  641. SignalThreadSync(g_strScriptSyncFlag);
  642. break;
  643. default:
  644. JAssert(false, "Unhandled task type in OnProcessEvent!");
  645. break;
  646. }
  647. }
  648. catch(ex)
  649. {
  650. SPLogMsg("exception in OnProcessEvent pid=" + pid + ",evt=" + evt + ", " + ex);
  651. }
  652. }
  653. function HandleParseEvent(pid, evt, param, fPostBuild)
  654. {
  655. var strMsg;
  656. ParseSDResults(pid, GetProcessOutput(pid), fPostBuild);
  657. if (evt == 'crashed' || evt == 'exited' || evt == 'terminated')
  658. {
  659. if (evt != 'exited' || param != 0) // If Not normal exit
  660. {
  661. strMsg = ") terminated abnormally";
  662. if (g_Task.cErrors == 0)
  663. strMsg += " (with no previously reported errors)";
  664. AppendToFile(g_ErrLog, g_Task.strErrLogPath, g_Task.strName + " (" + g_Depot.strName + strMsg);
  665. if (param == null)
  666. param = 1; // Simplify the "if" below, and ensure that OnError() gets called.
  667. }
  668. }
  669. if (!g_RetrySD)
  670. {
  671. if ((evt == 'crashed' || evt == 'exited' || evt == 'terminated') && param != 0 && g_Task.fSuccess )
  672. {
  673. if (evt != 'exited' || g_Task.cErrors == 0) // If Not (error exit, but errors already reported && ignored by user)
  674. OnError(g_Task.strName + ' for ' + g_Depot.strName + ' returned ' + param);
  675. }
  676. }
  677. FireUpdateEvent();
  678. }
  679. // ParseSDResults()
  680. //
  681. // DESCRIPTION:
  682. // This routine parses the results from Source Depot or PostBuild
  683. //
  684. // RETURNS:
  685. // true - if successful
  686. // false - if unsuccessful
  687. //
  688. // NOTES:
  689. //
  690. // The source depot log format is
  691. // <message type>: <details>
  692. // where <details> often is of the format:
  693. // <sd filename> - <operation> <operation details>
  694. //
  695. // The postbuild log format is
  696. // <script name>: [<error/warning>:] <details>
  697. // this format is loosely held but we ignore any lines which do not
  698. // conform to this format.
  699. //
  700. //
  701. function ParseSDResults(pid, strOutputBuffer, fPostBuild)
  702. {
  703. var xPos;
  704. var xStart;
  705. var iIndex;
  706. var iIndex2;
  707. var strLine;
  708. var strType;
  709. var strDesc;
  710. var strKeyword='';
  711. var strMsg;
  712. var aStrSDErrorType;
  713. // Initialize
  714. xStart = g_nSyncParsePosition;
  715. JAssert(g_ErrLog != null, "Must have err log opened for ParseSDResults!");
  716. // Parse the output one line at a time
  717. while ((xPos = strOutputBuffer.indexOf( '\n', xStart)) != -1) {
  718. strLine = strOutputBuffer.slice(xStart, xPos - 1);
  719. xStart = xPos + 1;
  720. if (g_SyncLog)
  721. g_SyncLog.WriteLine(strLine);
  722. if (g_fSDClientError) {
  723. g_ErrLog.WriteLine(strLine);
  724. aStrSDErrorType = g_reSDRetryText.exec(strLine);
  725. if (g_Task.fSuccess == true && aStrSDErrorType) // We will retry the SD command for this particular error
  726. {
  727. g_strDelayedExitMessage = null;
  728. strMsg = "source depot client error (" + aStrSDErrorType[1] + "): Build Console will retry this operation";
  729. g_Task.cErrors++;
  730. g_ErrLog.Writeline(strMsg);
  731. SPLogMsg("Retry Sync (client error), errors = " + g_Task.cErrors);
  732. g_RetrySD = true;
  733. ++g_Task.nRestarted;
  734. }
  735. continue;
  736. }
  737. // Parse the line
  738. if ((iIndex2 = strLine.indexOf(':')) != -1) {
  739. if (fPostBuild)
  740. {
  741. // For postbuild scripts, skip over the script name and
  742. // see if there is an error:/warning: field.
  743. iIndex = iIndex2 + 2; // Skip the space after the ':'
  744. iIndex2 = iIndex + strLine.substr(iIndex).indexOf(':');
  745. if (iIndex2 <= iIndex)
  746. {
  747. continue;
  748. }
  749. }
  750. else
  751. {
  752. iIndex = 0;
  753. }
  754. strType = strLine.substring(iIndex, iIndex2);
  755. strDesc = strLine.substr(iIndex2 + 2); // Skip the space after the ':'
  756. iIndex = strDesc.indexOf(' - ');
  757. if (iIndex != -1) {
  758. try {
  759. strKeyword = strDesc.match(/ - (\w+)/)[1]
  760. } catch(ex) {
  761. // Ignore any errors here;
  762. strKeyword = '';
  763. }
  764. }
  765. switch (strType.toLowerCase())
  766. {
  767. case 'error':
  768. if ((strDesc.toLowerCase().indexOf('file(s) up-to-date') == -1)
  769. && (strDesc.toLowerCase().indexOf('no file(s) to resolve') == -1)) {
  770. g_ErrLog.WriteLine(strLine);
  771. OnError(strLine, g_Task.strErrLogPath);
  772. }
  773. break;
  774. case 'warning':
  775. g_ErrLog.WriteLine(strLine);
  776. ++g_Task.cWarnings;
  777. break;
  778. case 'info':
  779. switch (strKeyword)
  780. {
  781. case 'merge':
  782. g_Task.cResolved++;
  783. if (g_strMergeFile.length > 0)
  784. {
  785. // This line indicates the completion of the merge.
  786. // Clear our stored filename so we don't get confused.
  787. g_strMergeFile = '';
  788. }
  789. break;
  790. case 'added':
  791. case 'deleted':
  792. case 'replacing':
  793. case 'refreshing':
  794. case 'updating':
  795. case 'updated':
  796. g_Task.cFiles++;
  797. break;
  798. case 'is':
  799. if (strDesc.indexOf("can't") != -1) {
  800. g_ErrLog.WriteLine(strLine);
  801. OnError(strLine, g_Task.strErrLogPath);
  802. }
  803. break;
  804. case 'vs':
  805. case 'resolve':
  806. //
  807. // Because the public headers are checked in, we will
  808. // typically get many conflicts in the public directory.
  809. // We have to ignore them.
  810. //
  811. //$ BUGBUG -- We should find a way to filter out files
  812. // checked out as part of the public changelist. Perhaps
  813. // by getting the list of files in the public changelist
  814. // and matching them up with files that show up with
  815. // merge issues? (lylec)
  816. //
  817. if (strKeyword == 'resolve')
  818. {
  819. g_Task.cResolved++;
  820. }
  821. if (!g_fIsRoot)
  822. {
  823. g_ErrLog.WriteLine(strLine);
  824. OnError(strLine, g_Task.strErrLogPath);
  825. }
  826. break;
  827. case 'merging':
  828. // Save the file currently being merged in case there are any
  829. // merge conflicts.
  830. g_strMergeFile = strDesc;
  831. break;
  832. default:
  833. break;
  834. }
  835. break;
  836. //
  837. // Parse the SD Diff Chunks line:
  838. // "Diff chunks: v yours + w theirs + x both + y conflicting"
  839. //
  840. case 'diff chunks':
  841. //
  842. // We need to find out if there was a merge conflict.
  843. //
  844. if (!g_fIsRoot)
  845. {
  846. var cConflicts;
  847. try
  848. {
  849. cConflicts = strDesc.match(/ \+ (\d+) conflicting/)[1];
  850. }
  851. catch(ex)
  852. {
  853. cConflicts = 0;
  854. }
  855. if (cConflicts > 0)
  856. {
  857. g_ErrLog.WriteLine('Merge conflict detected: ' + g_strMergeFile);
  858. OnError('Merge conflict detected: ' + g_strMergeFile, g_Task.strErrLogPath);
  859. }
  860. }
  861. break;
  862. case 'exit':
  863. // If the exit code is not zero, then a failure occurred.
  864. // The error condition may be non-deterministic.
  865. if ((strDesc != '0') && (g_Task.cErrors == 0)) {
  866. g_StrDelayedExitMessage = strLine;
  867. }
  868. break;
  869. case 'source depot client error':
  870. g_ErrLog.WriteLine(strLine);
  871. g_fSDClientError = true;
  872. break;
  873. default:
  874. break;
  875. }
  876. }
  877. }
  878. g_nSyncParsePosition = xStart;
  879. }
  880. function MergeFiles(strSrc, strDst, nSrcOffset)
  881. {
  882. try
  883. {
  884. var nPos = CopyOrAppendFile(strSrc, strDst, nSrcOffset, -1, 1);
  885. return nPos;
  886. }
  887. catch(ex)
  888. {
  889. if (ex.number != -2147024894) // ignore file not found errors.
  890. {
  891. SPLogMsg("MergeFiles failed, " + ex);
  892. SPLogMsg("MergeFiles failed params=[" + [strSrc, strDst, nSrcOffset].toString() + "]");
  893. }
  894. }
  895. return nSrcOffset;
  896. }
  897. //
  898. // ParseBuildMessages
  899. //
  900. // DESCRIPTION:
  901. // This function parses the messages that are sent during the build process.
  902. // This function then updates the task strOperation to reflect the current state
  903. // of the build itself
  904. //
  905. // RETURNS:
  906. // evt - Event Passed into ParseBuildMessages
  907. //
  908. function ParseBuildMessages(pid, evt, param)
  909. {
  910. // SPLogMsg('Process id ' + pid + ' ' + evt + "param is " + param);
  911. var aParams;
  912. var strRootFile;
  913. if (g_fIsRoot || g_fIsMerged)
  914. {
  915. if (g_fIsRoot)
  916. strRootFile = "build_2root";
  917. else
  918. strRootFile = "build_merged";
  919. g_aMergedPos[0] = MergeFiles(PrivateData.strLogDir + strRootFile + ".log", PrivateData.strLogDir + "build_root.log", g_aMergedPos[0]);
  920. g_aMergedPos[1] = MergeFiles(PrivateData.strLogDir + strRootFile + ".err", PrivateData.strLogDir + "build_root.err", g_aMergedPos[1]);
  921. }
  922. switch (evt.toLowerCase())
  923. {
  924. case 'status':
  925. // format of the status command should be: "errors=x,warnings=x,files=x"
  926. aParams = param.split(',');
  927. var cErrors;
  928. JAssert(aParams.length == 3, "Build status params unknown: '" + param + "'");
  929. if (aParams.length == 3) {
  930. cErrors = parseInt(aParams[0].split(/\s*=\s*/)[1]);
  931. g_Task.cWarnings = parseInt(aParams[1].split(/\s*=\s*/)[1]);
  932. g_Task.cFiles = parseInt(aParams[2].split(/\s*=\s*/)[1]);
  933. if (g_Task.cErrors != cErrors)
  934. {
  935. g_Task.cErrors = cErrors;
  936. OnError('Build.exe reported an error in the build.', g_Task.strErrLogPath, true);
  937. }
  938. }
  939. FireUpdateEvent();
  940. break;
  941. case 'pass 0 complete':
  942. case 'pass 1 complete':
  943. g_fIsBetweenSteps = true;
  944. if (evt.toLowerCase() == 'pass 0 complete') {
  945. g_Task.strOperation = COMPILE;
  946. } else if (evt.toLowerCase() == 'pass 1 complete') {
  947. g_Task.strOperation = LINK;
  948. }
  949. SPLogMsg(evt + ' on pid ' + pid);
  950. if (g_Task.fSuccess)
  951. g_Depot.strStatus = WAITING;
  952. else
  953. {
  954. g_Depot.strStatus = ERROR;
  955. SPLogMsg("Set Depot Status to error 2");
  956. }
  957. FireUpdateEvent();
  958. // Signal the step is complete
  959. // BUGBUG Extra debug info message
  960. //SPLogMsg("Signalling " + g_strTaskFlag);
  961. SignalThreadSync(g_strTaskFlag);
  962. // The resume will happen in taskBuildFiles(). We don't want to wait
  963. // here because build.exe is in the middle of an RPC call and we don't
  964. // want to hold it captive while we wait. Cleanup becomes messy
  965. // otherwise.
  966. break;
  967. case 'pass 2 complete':
  968. SPLogMsg(evt + ' on pid ' + pid);
  969. break;
  970. case 'exited':
  971. SPLogMsg('Process id ' + pid + ' exited!');
  972. //
  973. // Just to be sure
  974. //
  975. if ((param != 0) && (g_Task.cErrors == 0)) {
  976. OnError('Build exited with an exit code of ' + param);
  977. }
  978. if (param != 0) {
  979. AppendToFile(g_ErrLog, g_Task.strErrLogPath, "build (" + g_Depot.strName + ") terminated abnormally");
  980. }
  981. break;
  982. case 'crashed':
  983. // Update evt to exited and note the crash
  984. SPLogMsg('Process id ' + pid + ' crashed!');
  985. evt = 'exited';
  986. AppendToFile(g_ErrLog, g_Task.strErrLogPath, "build (" + g_Depot.strName + ") crashed");
  987. if (g_Task.cErrors == 0)
  988. {
  989. OnError('Build.exe or one of its child processes crashed!');
  990. }
  991. TerminateProcess(pid);
  992. break;
  993. case 'terminated':
  994. evt = 'exited';
  995. AppendToFile(g_ErrLog, g_Task.strErrLogPath, "build (" + g_Depot.strName + ") terminated abnormally(2)");
  996. break;
  997. default:
  998. break;
  999. }
  1000. return evt;
  1001. }
  1002. function FireUpdateEvent()
  1003. {
  1004. g_Depot.objUpdateCount.nCount++;
  1005. }
  1006. function OnError(strDetails, strLogFile, fDontIncrement)
  1007. {
  1008. var strErrorMsg;
  1009. var aStrMsg;
  1010. if (!fDontIncrement)
  1011. {
  1012. JAssert(g_Task, 'g_Task is null!');
  1013. g_Task.cErrors++;
  1014. }
  1015. SetSuccess(g_Task, false);
  1016. if (g_fAbort || !PrivateData || !PrivateData.objEnviron.Options)
  1017. {
  1018. return;
  1019. }
  1020. if (PrivateData.fIsStandalone)
  1021. aStrMsg = CreateTaskErrorMail(LocalMachine, g_Depot.strName, g_Task.strName, strDetails, strLogFile);
  1022. else
  1023. aStrMsg = CreateTaskErrorMail(PrivateData.objEnviron.BuildManager.Name, LocalMachine + ":" + g_Depot.strName, g_Task.strName, strDetails, strLogFile);
  1024. }
  1025. /*
  1026. WaitAndAbort is used in place of WaitForSync and WaitForMultipleSyncs.
  1027. It waits for the supplied signal(s), and the abort signal.
  1028. On abort, it will TerminateProcess the supplied pid, set
  1029. g_fAbort and return 0.
  1030. Otherwise the return value is the same as WaitForMultipleSyncs().
  1031. */
  1032. function WaitAndAbort(strSyncs, nTimeOut, pid)
  1033. {
  1034. var nTracePoint = 0;
  1035. try
  1036. {
  1037. var nEvent;
  1038. var strMySyncs = g_strAbortTask + "," + strSyncs;
  1039. // BUGBUG Extra debug info messages
  1040. //SPLogMsg("WaitAndAbort waiting on " + strMySyncs);
  1041. nTracePoint = 1;
  1042. nEvent = WaitForMultipleSyncsWrapper(strMySyncs, nTimeOut);
  1043. //SPLogMsg("WaitAndAbort wait returned " + nEvent);
  1044. if (nEvent > 0)
  1045. {
  1046. nTracePoint = 2;
  1047. if (nEvent == 1)
  1048. {
  1049. nTracePoint = 3;
  1050. SPLogMsg("User abort detected " + g_strDepotName);
  1051. g_fAbort = true;
  1052. g_Task.cErrors++;
  1053. SetSuccess(g_Task, false);
  1054. if (pid != null)
  1055. {
  1056. TerminateProcess(pid);
  1057. if (g_strScriptSyncFlag)
  1058. WaitForSync(g_strScriptSyncFlag, WAIT_FOR_PROCESS_EXIT_TIME);
  1059. JAssert(pid == g_pid);
  1060. if (pid == g_pid)
  1061. g_pid = null;
  1062. }
  1063. return 0;
  1064. }
  1065. nTracePoint = 4;
  1066. --nEvent;
  1067. }
  1068. nTracePoint = 5;
  1069. return nEvent;
  1070. }
  1071. catch(ex)
  1072. {
  1073. SPLogMsg("exception caught, TracePoint = " + nTracePoint + " " + ex);
  1074. throw ex;
  1075. }
  1076. }
  1077. /*
  1078. Copy the log files from our logdir to some
  1079. destination - presumably on the postbuild machine.
  1080. */
  1081. function CopyLogFiles(strDestDir, fFake)
  1082. {
  1083. var fnCopyFileNoThrow = PrivateData.objUtil.fnCopyFileNoThrow;
  1084. var i;
  1085. var aParts;
  1086. var ex;
  1087. var strSrc;
  1088. var strDst;
  1089. var strMsg = "Copy logfiles from '" + PrivateData.strLogDir + "' to '" + strDestDir + "'";
  1090. g_SyncLog.WriteLine(strMsg);
  1091. aFiles = PrivateData.objUtil.fnDirScanNoThrow(PrivateData.strLogDir);
  1092. if (aFiles.ex == null)
  1093. {
  1094. for(i = 0; i < aFiles.length; ++i)
  1095. {
  1096. aParts = aFiles[i].SplitFileName();
  1097. strSrc = PrivateData.strLogDir + aFiles[i];
  1098. strDst = strDestDir + aParts[0] + aParts[1] + "_" + LocalMachine + aParts[2];
  1099. if (fFake)
  1100. g_SyncLog.WriteLine("Copy file (fake) " + strSrc + " to " + strDst);
  1101. else
  1102. {
  1103. ex = fnCopyFileNoThrow(strSrc, strDst);
  1104. if (ex == null)
  1105. g_SyncLog.WriteLine("Copy file from " + strSrc + " to " + strDst);
  1106. else
  1107. {
  1108. AppendToFile(g_ErrLog, g_Task.strErrLogPath, "Copy file from " + strSrc + " to " + strDst + " FAILED " + ex);
  1109. OnError(strMsg + "copy file failed " + aFiles[i]);
  1110. }
  1111. }
  1112. }
  1113. }
  1114. else
  1115. {
  1116. AppendToFile(g_ErrLog, g_Task.strErrLogPath, "DirScan failed: " + aFiles.ex);
  1117. OnError(strMsg + " dirscan failed");
  1118. }
  1119. }
  1120. /*
  1121. StatusFile()
  1122. The operation of this is non-obvious.
  1123. This function gets called by RoboCopy at the start of each
  1124. file copy operation.
  1125. If the previous copy operation had any warnings or errors,
  1126. g_Task.fSuccess will be false.
  1127. If the user pressed "Ignore error" g_Task.fSuccess will be
  1128. set to true.
  1129. So, if there were no errors or warnings, record the current
  1130. number of errors. (We can have non-zero error count if the
  1131. user has pressed "Ignore error".)
  1132. Then, if the current number of errors equals the recorded
  1133. number of errors, but fSuccess is false, then the previous
  1134. file operation must have had warnings, but then continued
  1135. successfully.
  1136. We cannot clear StatusValue(0) since
  1137. this value depends on all the depots being built on this
  1138. machine. Instead we signal the updatestatus thread to
  1139. do this for us.
  1140. */
  1141. function StatusFile()
  1142. {
  1143. //this.strSrcFile
  1144. if (g_Task.fSuccess)
  1145. g_cErrors = g_Task.cErrors;
  1146. if (g_cErrors == g_Task.cErrors && !g_Task.fSuccess)
  1147. {
  1148. SetSuccess(g_Task, true);
  1149. FireUpdateEvent();
  1150. }
  1151. return true;
  1152. }
  1153. /*
  1154. StatusProgress()
  1155. This is called as a RoboCopy member function.
  1156. We use it to print 1 message per file.
  1157. */
  1158. function StatusProgress(nPercent, nSize, nCopiedBytes)
  1159. {
  1160. if (g_fAbort)
  1161. return this.PROGRESS_CANCEL;
  1162. if (nPercent > 0)
  1163. {
  1164. var strMsg = "Copying " + this.strSrcFile + " (" + nSize + " bytes)";
  1165. g_SyncLog.WriteLine(strMsg);
  1166. SPLogMsg(strMsg);
  1167. g_Task.cFiles++;
  1168. FireUpdateEvent();
  1169. return this.PROGRESS_QUIET;
  1170. }
  1171. return this.PROGRESS_CONTINUE;
  1172. }
  1173. /*
  1174. StatusError()
  1175. This is called as a RoboCopy member function.
  1176. Called when RoboCopy cannot copy a file for some reason.
  1177. Log the event and continue.
  1178. */
  1179. function StatusError()
  1180. {
  1181. // Note, that the paths printed can be inaccurate.
  1182. // We only know the starting directories and the filename
  1183. // of the file in question.
  1184. // Since we may be doing a recursive copy, some of the
  1185. // path information is not available to us.
  1186. var strErrDetail = 'Unknown';
  1187. if (g_fAbort)
  1188. return this.RC_FAIL;
  1189. if (this.nErrorCode == 0 || this.nErrorCode == this.RCERR_RETRYING)
  1190. return this.RC_CONTINUE; // Eliminate some clutter in the log file.
  1191. var fNonFatal = false;
  1192. if (this.nErrorCode == this.RCERR_WAITING_FOR_RETRY)
  1193. {
  1194. fNonFatal = true;
  1195. g_Task.cWarnings++;
  1196. }
  1197. if (this.ErrorMessages[this.nErrorCode])
  1198. strErrDetail = this.ErrorMessages[this.nErrorCode];
  1199. var strMsg = "CopyBinariesFiles error " +
  1200. this.nErrorCode +
  1201. "(" + strErrDetail + ")" +
  1202. " copying file " +
  1203. this.strSrcFile +
  1204. " to " +
  1205. this.strDstDir;
  1206. AppendToFile(g_SyncLog, g_Task.strLogPath, strMsg);
  1207. AppendToFile(g_ErrLog, g_Task.strErrLogPath, strMsg);
  1208. OnError(strMsg, g_Task.strErrLogPath, fNonFatal);
  1209. FireUpdateEvent();
  1210. return this.RC_CONTINUE
  1211. }
  1212. function StatusMessage(nErrorCode, strErrorMessage, strRoboCopyMessage, strFileName)
  1213. {
  1214. if (g_fAbort)
  1215. return this.RC_FAIL;
  1216. var strMsg = "CopyBinariesFiles message (" +
  1217. nErrorCode +
  1218. ": " + strErrorMessage +
  1219. ") " + strRoboCopyMessage +
  1220. " " +
  1221. strFileName;
  1222. AppendToFile(g_SyncLog, g_Task.strLogPath, strMsg);
  1223. AppendToFile(g_ErrLog, g_Task.strErrLogPath, strMsg);
  1224. return this.RC_CONTINUE
  1225. }
  1226. /*
  1227. CopyBinariesFiles()
  1228. Copy the contents of the "binaries" directory to the
  1229. "postbuild" machine in a distributed build. The source
  1230. directory is determined by our ENV_NTTREE, and the destination
  1231. is a combination of that and the "postbuild" machines
  1232. enlistment dirctory.
  1233. The destination path is of the form "\\Postbuild\C$\binaries..."
  1234. All we need to do is a bit of setup, then call
  1235. robocopy to do the rest.
  1236. */
  1237. function CopyBinariesFiles(strPostBuildMachineEnlistment)
  1238. {
  1239. var strDestDir;
  1240. var nEnlistment;
  1241. var strSDRoot;
  1242. var aParts;
  1243. var fLoggedAnyFiles = false;
  1244. if (!RoboCopyInit())
  1245. {
  1246. AppendToFile(g_ErrLog, g_Task.strErrLogPath, "RoboCopyInit() failed");
  1247. return false;
  1248. }
  1249. // Supply overides for the RoboCopy file copy
  1250. // status functions.
  1251. // We are only interested in 2 of them.
  1252. g_robocopy.StatusFile = StatusFile;
  1253. g_robocopy.StatusProgress = StatusProgress;
  1254. g_robocopy.StatusError = StatusError;
  1255. g_robocopy.StatusMessage = StatusMessage;
  1256. // Now attempt to copy the binaries files from each enlistment
  1257. for(nEnlistment = 0 ; nEnlistment < PublicData.aBuild[0].hMachine[g_MachineName].aEnlistment.length; ++nEnlistment)
  1258. {
  1259. strSDRoot = PublicData.aBuild[0].hMachine[g_MachineName].aEnlistment[nEnlistment].strRootDir;
  1260. // Check to see that we have env info for the enlistment
  1261. // If so, attempt the create the log directory (just once)
  1262. // If not, then complain about it (just once)
  1263. if (PrivateData.aEnlistmentInfo[nEnlistment] == null ||
  1264. PrivateData.aEnlistmentInfo[nEnlistment].hEnvObj[ENV_NTTREE] == null)
  1265. {
  1266. AppendToFile(g_ErrLog, g_Task.strErrLogPath, "No aEnlistmentInfo entry for " + ENV_NTTREE + " on '" + strSDRoot + "' - cannot copy binaries");
  1267. continue;
  1268. }
  1269. strSrcDir = PrivateData.aEnlistmentInfo[nEnlistment].hEnvObj[ENV_NTTREE];
  1270. // Now, where do we copy to???
  1271. aParts = strSrcDir.SplitFileName(); // _NTTREE=E:\binaries.x86chk
  1272. // build path:
  1273. // Use UNC form "\\Machine\E$\binaraies..."
  1274. strDestDir = "\\\\" +
  1275. PrivateData.objEnviron.BuildManager.PostBuildMachine +
  1276. "\\" +
  1277. strPostBuildMachineEnlistment.charAt(0) +
  1278. "$\\" +
  1279. aParts[1] + aParts[2];
  1280. fLoggedAnyFiles = true;
  1281. g_SyncLog.WriteLine("Copy binaries from " + strSrcDir + " to " + strDestDir);
  1282. if (PrivateData.objEnviron.Options.CopyBinariesExcludes != null)
  1283. g_robocopy.SetExcludeFiles(PrivateData.objEnviron.Options.CopyBinariesExcludes.split(/[,; ]/));
  1284. g_robocopy.CopyDir(strSrcDir, strDestDir, true);
  1285. StatusFile(); // Reset fSuccess status if necessary
  1286. }
  1287. if (!fLoggedAnyFiles )
  1288. g_SyncLog.WriteLine("no binary files copied");
  1289. }
  1290. /*
  1291. MyRunLocalCommand()
  1292. Simple wrapper function for RunLocalCommand() that
  1293. logs the inputs with SPLogMsg();
  1294. */
  1295. function MyRunLocalCommand(strCmd, strDir, strTitle, fMin, fGetOutput, fWait)
  1296. {
  1297. var pid;
  1298. SPLogMsg("RunLocalCommand('" +
  1299. [strCmd, strDir, strTitle, fMin, fGetOutput, fWait].join("', '") +
  1300. "')");
  1301. pid = RunLocalCommand(strCmd, strDir, strTitle, fMin, fGetOutput, fWait);
  1302. if (!pid)
  1303. SPLogMsg('Unable to execute command (' + GetLastRunLocalError() + '): ' + strNewCmd);
  1304. return pid;
  1305. }