windows-nt/Source/XPSP1/NT/sdktools/mtscript/scripts/slaveproxy.js
2020-09-26 16:20:57 +08:00

1580 lines
55 KiB
JavaScript

/*
*/
Include('types.js');
Include('utils.js');
Include('staticstrings.js');
Include('MsgQueue.js');
/*
This script is invoked by harness.js to provide async
communications to the slave machines running "slave.js"
Communication between slaveproxy and harness is exclusivly thru
"messages".
*/
var g_FSObj;
var g_aPublishedEnlistments = null;
var g_aFiles = null;
var g_fUpdatePublicDataPending = false;
var g_MasterQueue = null;
var g_cDialogIndex = 0;
// If a build machine is reset after a build has completed, its OK to send it the "restart" command.
var g_fOKToRestartLostMachine = false;
var g_strConfigError = 'ConfigError';
var g_strOK = 'ok';
var g_strNoEnvTemplate = 'Must set config and environment templates first';
var g_strStartFailed = "An error occurred in StartRemoteMachine: ";
var g_strSlaveBusy = "A build server in your distributed build is already busy.";
var g_strSendCmdRemoteMachine = "SendCmdRemoteMachine failed: ";
var g_strSendCmdDisconnect = "The connection to the build server no longer exists";
var g_SlaveProxyThreadReady = 'SlaveProxyThreadReady';
var g_SlaveProxyThreadFailed = 'SlaveProxyThreadFailed';
// "'Update<machinename>'" is a placeholder. The real name is setup in ScriptMain.
var g_SlaveProxyWaitFor = ['SlaveProxyThreadExit', 'RebuildWaitArray', 'Update<machinename>'];
var g_strRemoteMachineName = '';
var g_MyName = 'slaveproxy';
var g_aDepotIndex = new Object(); // associate depot name to depot index.
//var g_fDirectCopy = true; // If true, execute XCOPY directly, instead of with a batch file.
var g_nBuildPass = 0;
function SPLogMsg(msg)
{
LogMsg('(' + g_strRemoteMachineName + ') ' + msg, 1);
}
function slaveproxy_js::OnScriptError(strFile, nLine, nChar, strText, sCode, strSource, strDescription)
{
return CommonOnScriptError("slaveproxy_js", strFile, nLine, nChar, strText, sCode, strSource, strDescription);
}
function slaveproxy_js::ScriptMain()
{
var nEvent;
var aWaitQueues;
g_MasterQueue = GetMsgQueue(ScriptParam);
g_MyName = g_MasterQueue.strName;
g_strRemoteMachineName = g_MyName.split(',')[1];
SignalThreadSync(g_SlaveProxyThreadReady);
CommonVersionCheck(/* $DROPVERSION: */ "V(########) F(!!!!!!!!!!!!!!)" /* $ */);
SPLogMsg("Queue name for this thread: " + g_MyName);
g_SlaveProxyWaitFor[2] = 'Update' + g_strRemoteMachineName;
g_FSObj = new ActiveXObject("Scripting.FileSystemObject");
do
{
aWaitQueues = new Array();
aWaitQueues[0] = g_MasterQueue;
nEvent = WaitForMultipleQueues(aWaitQueues, g_SlaveProxyWaitFor.toString(), SlaveProxyMsgProc, 0);
if (nEvent > 0 && nEvent <= g_SlaveProxyWaitFor.length)
{
ResetSync(g_SlaveProxyWaitFor[nEvent - 1]);
if (nEvent == 3)
{
RefreshPublicData(false);
}
}
}
while (nEvent != 1); // While not SlaveProxyThreadExit
AbortRemoteMachines();
SPLogMsg(g_MyName + ' Exit');
}
/*
slaveproxy_js::OnEventSourceEvent
Dispatch the event to the appropriate handler.
*/
function slaveproxy_js::OnEventSourceEvent(RemoteObj, DispID, cmd, params)
{
mach = PrivateData.hRemoteMachine[g_strRemoteMachineName].objRemote;
if (RemoteObj != mach.obj)
SPLogMsg("Event from stale remote object? [" + [DispID, cmd, params].toString() + "]");
RemoteObj = mach;
var vRet = '';
try
{
OnEventSourceEventSlave(RemoteObj, cmd, params)
}
catch(ex)
{
JAssert(false, "(" + g_strRemoteMachineName + ") " + "an error occurred in OnEventSourceEvent(" + cmd + ") \n" + ex);
}
}
/*
OnEventSourceEventSlave
Handle NotifyScript() events from slave.js
*/
function OnEventSourceEventSlave(RemoteObj, cmd, params)
{
var aDepotIdx;
var i;
switch(cmd)
{
case 'ScriptError':
NotifyScriptError(RemoteObj, params);
break;
}
}
/*
SlaveProxyMsgProc
Handle MsgQueue messages from harness.js
These messages are of course sent async between harness and slaveproxy.
They are received and dispatched in slaveproxy_js::ScriptMain().
*/
function SlaveProxyMsgProc(queue, msg)
{
try
{
var newmach;
var nTracePoint = 0;
var vRet = g_strOK;
var params = msg.aArgs;
var mach;
SPLogMsg('(' + g_MyName + ') (g_MasterQueue, msg): ' + params[0]);
switch (params[0])
{
case 'test':
SPLogMsg('Recieved a test message. ArgCount=' + params.length + ' arg1 is: ' + params[1]);
break;
case 'start':
newmach = new Machine();
newmach.strName = g_strRemoteMachineName;
PublicData.aBuild[0].hMachine[g_strRemoteMachineName] = newmach;
if (PrivateData.objConfig.Options.fRestart)
vRet = StartRemoteMachine('restart', true);
else
vRet = StartRemoteMachine('start', false);
break;
case 'restartcopyfiles':
vRet = SendCmdRemoteMachine("restartcopyfiles", 0);
break;
case 'abort':
vRet = AbortRemoteMachines();
break;
case 'copyfilestoslaves':
SPLogMsg("CopyFilesToSlaves");
vRet = CopyFilesToSlaves();
break;
case 'copyfilestopostbuild':
vRet = CopyFilesToPostBuild();
break;
case 'nextpass':
++g_nBuildPass;
SPLogMsg("nextpass counter is " + params[1]);
vRet = SendCmdRemoteMachine("nextpass", 0);
break;
case 'createmergedpublish.log':
if (PrivateData.objConfig.Options.fCopyPublishedFiles)
vRet = CreateMergedPublishLog();
else
SPLogMsg("Skipping CreateMergedPublishLog - as specified in the config template");
break;
case 'ignoreerror':
case 'remote':
case 'seval':
case 'eval':
vRet = SendCmdRemoteMachine(params[0], params[1]);
break;
case 'proxeval':
try
{
SPLogMsg("slaveproxy for " + g_strRemoteMachineName + " executing command " + params[1]);
vRet = MyEval(params[1]);
}
catch(ex)
{
vRet = 'Unhandled exception: ' + ex;
}
SPLogMsg("proxeval result was: " + vRet);
break;
case 'refreshpublicdata':
RefreshPublicData(true);
break;
case 'getspdata':
getspdata();
break;
case 'restarttask': // task id: "machine.nID"
break;
default:
vRet = 'invalid command: ' + cmd;
break;
}
}
catch(ex)
{
SPLogMsg("Exception thrown processing '" + params[0] + "'" + ex);
//throw(ex);
}
return vRet;
}
function SendCmdRemoteMachine(cmd, arg)
{
SPLogMsg("Enter");
var vRet = g_strOK;
var fRetry = false;
if (PrivateData.hRemoteMachine[g_strRemoteMachineName] != null)
{
SPLogMsg("About to " + cmd + ", arg = " + arg);
var mach = PrivateData.hRemoteMachine[g_strRemoteMachineName];
do
{
try
{
vRet = mach.objRemote.Exec(cmd, arg);
}
catch(ex)
{ // must have already died
SPLogMsg("Send failed: " + ex);
fRetry = RestartLostMachine();
vRet = g_strSendCmdRemoteMachine + cmd;
}
} while (fRetry);
}
else
{
vRet = g_strSendCmdDisconnect;
}
SPLogMsg("Exit");
return vRet;
}
function AbortRemoteMachines()
{
SPLogMsg("Enter");
var vRet = g_strOK;
if (PrivateData.hRemoteMachine[g_strRemoteMachineName] != null)
{
SPLogMsg("Machine is connected. Aborting...");
var mach = PrivateData.hRemoteMachine[g_strRemoteMachineName];
try
{
mach.objRemote.Unregister();
}
catch(ex)
{ // must have already died?
SPLogMsg("Abort failed (UnregisterEventSource): " + ex);
}
try
{
if (mach.fSetConfig)
mach.objRemote.Exec('setmode', 'idle');
delete mach.objRemote;
}
catch(ex)
{ // must have already died
SPLogMsg("Abort failed: " + ex);
}
ResetDepotStatus();
if (PublicData.aBuild[0].hMachine[g_strRemoteMachineName])
PublicData.aBuild[0].hMachine[g_strRemoteMachineName].fSuccess = false;
delete PrivateData.hRemoteMachine[g_strRemoteMachineName];
}
SPLogMsg("Exit");
return vRet;
}
function ResetDepotStatus()
{
var nLocalDepotIdx;
var Remote_aBuildZero;
var nDepotIdx;
if (!PrivateData.hRemotePublicDataObj[g_strRemoteMachineName])
return;
Remote_aBuildZero = PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0];
if (!Remote_aBuildZero)
return;
for(nDepotIdx = 0; nDepotIdx < Remote_aBuildZero.aDepot.length; ++nDepotIdx)
{
nLocalDepotIdx = g_aDepotIndex[Remote_aBuildZero.aDepot[nDepotIdx].strName.toLowerCase()];
PublicData.aBuild[0].aDepot[nLocalDepotIdx].strStatus = ABORTED;
PublicData.aBuild[0].aDepot[nLocalDepotIdx].objUpdateCount.nCount++;
}
}
function SetDisconnectedDepotStatus(strErrMsg)
{
var nLocalDepotIdx;
var Remote_aBuildZero;
var nDepotIdx;
var xTask;
var item;
var objMachine;
if (!PrivateData.hRemotePublicDataObj[g_strRemoteMachineName])
return;
Remote_aBuildZero = PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0];
if (!Remote_aBuildZero)
return;
for(nDepotIdx = 0; nDepotIdx < Remote_aBuildZero.aDepot.length; ++nDepotIdx)
{
nLocalDepotIdx = g_aDepotIndex[Remote_aBuildZero.aDepot[nDepotIdx].strName.toLowerCase()];
objDepot = new Depot;
for(item in Remote_aBuildZero.aDepot[nDepotIdx])
{
if (!Remote_aBuildZero.aDepot[nDepotIdx].__isPublicMember(item))
continue;
objDepot[item] = Remote_aBuildZero.aDepot[nDepotIdx][item];
}
objDepot.objUpdateCount = new UpdateCount();
objDepot.aTask = new Array();
xTask = new Task();
xTask.strName = ERROR;
xTask.strStatus = ERROR;
xTask.fSuccess = false;
xTask.strFirstLine = " Connection lost to " + g_strRemoteMachineName + " ";
xTask.strSecondLine = strErrMsg;
objDepot.aTask[0] = xTask;
objDepot.objUpdateCount.nCount = 0;
objDepot.fDisconnected = true;
PublicData.aBuild[0].aDepot[nLocalDepotIdx] = objDepot;
SPLogMsg("Marking " + objDepot.strName + " as disconnected");
objMachine = {fSuccess:false, strBuildPassStatus:""};
if (PublicData.aBuild[0].hMachine[g_strRemoteMachineName])
objMachine.strBuildPassStatus = PublicData.aBuild[0].hMachine[g_strRemoteMachineName].strBuildPassStatus;
PublicData.aBuild[0].hMachine[g_strRemoteMachineName] = objMachine;
}
}
function CreateErrorDepot(strErrMsg)
{
var tmpDepot = new Depot;
var xTask;
tmpDepot.strStatus = ERROR;
tmpDepot.strMachine = g_strRemoteMachineName;
tmpDepot.strName = 'root';
tmpDepot.aTask = new Array();
xTask = new Task();
xTask.strName = ERROR;
xTask.strStatus = ERROR;
xTask.strFirstLine = " Cannot connect to " + g_strRemoteMachineName + " ";
xTask.strSecondLine = strErrMsg;
tmpDepot.aTask[0] = xTask;
if (PublicData.aBuild[0].hMachine[g_strRemoteMachineName])
PublicData.aBuild[0].hMachine[g_strRemoteMachineName].fSuccess = false;
UpdatePublicDataDepot(tmpDepot);
}
function RestartLostMachine()
{
var vRet;
var RemoteObj;
var strTmp;
var nRetryCount;
RemoteObj = PrivateData.hRemoteMachine[g_strRemoteMachineName].objRemote;
if (RemoteObj.fMachineReset)
{
if (g_fOKToRestartLostMachine)
{
SPLogMsg("ABOUT TO RESTART REMOTE MACHINE");
vRet = StartRemoteMachine('restart', false);
// StartRemoteMachine recreates RemoteObj -- we must grab an updated copy.
RemoteObj = PrivateData.hRemoteMachine[g_strRemoteMachineName].objRemote;
if (vRet == g_strOK)
{
// Wait a little while for the remote machine to get to its completed state.
nRetryCount = 15;
if (!Already)
{
Already = true;
throw new Error(-1, "Bogus nogus");
}
do
{
strTmp = MyEval(newremotemach.objRemote.Exec('getpublic', 'PublicData.strMode'));
if (strTmp == COMPLETED)
break;
Sleep(500);
nRetryCount--;
} while(nRetryCount);
RemoteObj.fStopTryingToGetPublicData = true;
SPLogMsg("Restart remote machine successfull, retries=" + nRetryCount);
return true;
}
}
else
RemoteObj.fStopTryingToGetPublicData = true;
}
SPLogMsg("failed fMachineReset = " + RemoteObj.fMachineReset + ", g_fOKToRestartLostMachine = " + g_fOKToRestartLostMachine);
return false;
}
function StartRemoteMachine(strStart, fReconnectRunningBuild)
{
vRet = ConnectToRemoteMachine(strStart, fReconnectRunningBuild);
if (vRet == g_strOK)
{
SPLogMsg("Started machine " + g_strRemoteMachineName + ", now sending message");
return g_strOK;
}
else
{
if (vRet == "alreadyset")
vRet = "machine in use";
CreateErrorDepot(vRet);
ReportError("Starting build", "Cannot " + strStart + " build on machine : " + g_strRemoteMachineName + "\n" + vRet);
g_MasterQueue.SendMessage('abort', 0);
return vRet;
}
}
function ConnectToRemoteMachine(strStart, fReconnectRunningBuild)
{
var vRet = g_strOK;
var newremotemach;
var strTmp;
var RemotePublicData;
try
{
newremotemach = new RemoteMachine();
newremotemach.objRemote = new RemoteWrapper(g_strRemoteMachineName);
if (fReconnectRunningBuild)
{
strTmp = MyEval(newremotemach.objRemote.Exec('getpublic', 'PublicData.strMode'));
if (strTmp != 'idle')
{
SPLogMsg("Remote machine already busy, same templates?");
RemotePublicData = MyEval(newremotemach.objRemote.Exec('getpublic', 'root'));
if (RemotePublicData.aBuild && RemotePublicData.aBuild[0])
{
if (RemotePublicData.aBuild[0].strEnvTemplate == PublicData.aBuild[0].strEnvTemplate)
{
newremotemach.fSetConfig = true;
PrivateData.hRemoteMachine[g_strRemoteMachineName] = newremotemach;
newremotemach.objRemote.Register();
SPLogMsg("Remote machine env template matches -- no need to restart it");
return vRet;
}
SPLogMsg("Remote templates:" + RemotePublicData.aBuild[0].strConfigTemplate + ", " + RemotePublicData.aBuild[0].strEnvTemplate);
}
else
SPLogMsg("Remote machine is not idle, but aBuild[0] is missing.");
SPLogMsg("Remote machine template mismatch -- forcing idle");
vRet = newremotemach.objRemote.Exec('setmode', 'idle');
SPLogMsg("Setmode returns " + vRet);
}
}
SPLogMsg('Setconfig on machine');
vRet = newremotemach.objRemote.Exec('setstringmap', PrivateData.aStringMap.toString());
if (vRet != g_strOK)
return vRet;
vRet = newremotemach.objRemote.Exec('setconfig', PublicData.aBuild[0].strConfigTemplate);
if (vRet == g_strOK)
{
// If setconfig returns OK, then we know we have the undivided attention of the
// slave machine. If setconfig does not return OK, then the remote machine
// may already be busy with some other build. In this case it would be really
// bad for us to issue a 'setmode idle' command.
newremotemach.fSetConfig = true;
strTmp = MyEval(newremotemach.objRemote.Exec('getpublic', 'PublicData.strMode'));
if (strTmp != 'idle')
vRet = g_strSlaveBusy + " '" + g_strRemoteMachineName + "' (" + strTmp + ")";
}
if (vRet == g_strOK)
{
vRet = newremotemach.objRemote.Exec('setenv', PublicData.aBuild[0].strEnvTemplate);
SPLogMsg(' setenv returned: ' + vRet);
}
if (vRet == g_strOK)
{
vRet = newremotemach.objRemote.Exec('setmode', 'slave');
SPLogMsg(' setmode returned: ' + vRet);
}
if (vRet == g_strOK)
{
vRet = newremotemach.objRemote.Exec(strStart, 0);
SPLogMsg(' ' + strStart + ' returned: ' + vRet);
}
if (vRet == g_strOK)
{
PrivateData.hRemoteMachine[g_strRemoteMachineName] = newremotemach;
newremotemach.objRemote.Register();
SPLogMsg("Started machine " + g_strRemoteMachineName);
}
}
catch(ex)
{
// Oddly, if the remote machine is not found, "ex" has a helpful error message.
// However, if the remote machine is found, has mtscript.exe registered, but mtscript.exe
// is unable to run (somebody deleted it perhaps), then "ex" has only "number" set
// to the value -2147024894.
if (ex.description == null || ex.description.length == 0) //ex.number == -2147024894) // Mtscript.exe cannot run
{
vRet = "An error occurred connecting to mtscript.exe on machine " + g_strRemoteMachineName + ". Error is " + ex.number;
SPLogMsg(vRet + "\n" + ex);
}
else
{
vRet = g_strStartFailed + ex;
SPLogMsg(vRet);
}
}
return vRet;
}
/*
UpdatePublicDataDepot()
Update the local copy of depot public data from our
remote machine.
*/
function UpdatePublicDataDepot(objDepot)
{
var nLocalDepotIdx;
nLocalDepotIdx = g_aDepotIndex[objDepot.strName.toLowerCase()];
//JAssert(nLocalDepotIdx != null, "(" + g_strRemoteMachineName + ") " + "Unknown depot! " + objDepot.strName);
if (nLocalDepotIdx == null)
{ // This happens when there is an "error" depot - a depot with a bad enlistment directory.
SPLogMsg("Unknown depot " + objDepot.strName + " - assign new index");
TakeThreadLock('NewDepot');
try
{
nLocalDepotIdx = PublicData.aBuild[0].aDepot.length;
PublicData.aBuild[0].aDepot[nLocalDepotIdx] = null; // Extend the length of the array
}
catch(ex)
{
SPLogMsg("Exception while creating a new depot, " + ex);
}
ReleaseThreadLock('NewDepot');
g_aDepotIndex[objDepot.strName.toLowerCase()] = nLocalDepotIdx;
SPLogMsg("New index is " + nLocalDepotIdx + " new length is " + PublicData.aBuild[0].aDepot.length);
}
JAssert(!PublicData.aBuild[0].aDepot[nLocalDepotIdx] ||
PublicData.aBuild[0].aDepot[nLocalDepotIdx].strName == objDepot.strName,
"Overwriting another depot in the master depot list!");
PublicData.aBuild[0].aDepot[nLocalDepotIdx] = objDepot;
}
/*
SmartGetPublic(fForceRoot)
Refresh our copy of the remote machines PublicData.
If we have never retrieved status from the remote machine
then get a full copy.
Otherwise do a "smart" update - ask for a status update
on just the depots that have changed.
Always get fresh copies of elapsed time and error dialog.
*/
function SmartGetPublic(fForceRoot)
{
var objTracePoint = { fnName:'SmartGetPublic', nTracePoint:0 };
var fRetry;
var RemoteObj;
do
{
try
{
fRetry = false;
RemoteObj = PrivateData.hRemoteMachine[g_strRemoteMachineName].objRemote;
if (RemoteObj.fMachineReset && !g_fOKToRestartLostMachine)
return false;
if (RemoteObj.fStopTryingToGetPublicData)
return true;
SmartGetPublicWorker(objTracePoint, RemoteObj, fForceRoot);
if (RemoteObj.fMachineReset)
SPLogMsg("SmartGetPublic should have failed -- machine is reset");
return true;
}
catch(ex)
{
SPLogMsg("SmartGetPublic() failed, TracePoint = " + objTracePoint.nTracePoint + ", " + ex);
return RestartLostMachine();
}
} while (fRetry);
SPLogMsg("failed to get public data");
return false;
}
/*
GetPublicRoot(objTracePoint, RemoteObj)
Get a full copy of the remote machines PublicData.
Prune the object of the parts we are not interested in.
Place it in our own PublicData.
*/
function GetPublicRoot(objTracePoint, RemoteObj)
{
var objRemotePublicData;
objTracePoint.fnName = 'GetPublicRoot';
objRemotePublicData = RemoteObj.Exec('getpublic', 'root');
objRemotePublicData = PrivateData.objUtil.fnMyEval(objRemotePublicData);
objTracePoint.nTracePoint = 1;
if (objRemotePublicData != null)
{
objTracePoint.nTracePoint = 2;
delete objRemotePublicData.nDataVersion;
delete objRemotePublicData.strStatus;
delete objRemotePublicData.strMode;
objTracePoint.nTracePoint = 6;
if (objRemotePublicData.aBuild != null && objRemotePublicData.aBuild[0] != null)
{
objTracePoint.nTracePoint = 7;
if (objRemotePublicData.aBuild[0].hMachine[g_strRemoteMachineName] != null)
{
objTracePoint.nTracePoint = 8;
delete objRemotePublicData.aBuild[0].hMachine[g_strRemoteMachineName].strName;
delete objRemotePublicData.aBuild[0].hMachine[g_strRemoteMachineName].strStatus;
delete objRemotePublicData.aBuild[0].hMachine[g_strRemoteMachineName].strLog
delete objRemotePublicData.aBuild[0].hMachine[g_strRemoteMachineName].aEnlistment;
objTracePoint.nTracePoint = 9;
}
else
SPLogMsg("hMachine IS null");
}
PrivateData.hRemotePublicDataObj[g_strRemoteMachineName] = objRemotePublicData;
}
}
function SmartGetPublicWorker(objTracePoint, RemoteObj, fForceRoot)
{
objTracePoint.fnName = 'SmartGetPublicWorker';
if (fForceRoot ||
PrivateData.hRemotePublicDataObj[g_strRemoteMachineName] == null ||
PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0].hMachine == null ||
PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0].hMachine[g_strRemoteMachineName] == null)
{
GetPublicRoot(objTracePoint, RemoteObj);
}
else
{
var str = "";
var comma = "";
var i;
var aDepot;
if (PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0] != null)
{
aDepot = PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0].aDepot;
if (aDepot != null)
{
for(i = 0 ; i < aDepot.length; ++i)
{
/*
fDisconnected is never explicitly reset.
Once the connection to the remote machine is reestablished
the Depot object is simply replaced with the depot object from the
remote machine. Thus, "fDisconnected" disappears entirely.
Below, if "fDisconneced" is true we do not list this depot
in the list sent to "getdepotupdate". This forces getdepotupdate
to return status for this depot, since as far as it knows
we do not have any status information for this depot.
*/
if (aDepot[i].fDisconnected != true)
{
strDepotID = aDepot[i].strMachine + "," + aDepot[i].strName;
str += comma + "'" + strDepotID + "'" + ":" + aDepot[i].objUpdateCount.nCount;
comma = ",";
}
}
}
}
str = "var _o0 = {" + str + " }; _o0";
objTracePoint.nTracePoint = 1;
var aUpdateDepot = RemoteObj.Exec('getdepotupdate', str);
objTracePoint.nTracePoint = 2;
aUpdateDepot = PrivateData.objUtil.fnMyEval(aUpdateDepot);
objTracePoint.nTracePoint = 3;
for(i = 0; i < aUpdateDepot.length; ++i)
{
if (aUpdateDepot[i] != null)
aDepot[i] = aUpdateDepot[i];
}
var aThingsToFetch =
[
'PublicData.aBuild[0].objElapsedTimes',
'PublicData.objDialog',
'PublicData.aBuild[0].hMachine["' + g_strRemoteMachineName + '"].strBuildPassStatus',
'PublicData.aBuild[0].hMachine["' + g_strRemoteMachineName + '"].fSuccess'
];
objTracePoint.nTracePoint = 4;
var obj = RemoteObj.Exec('getpublic', '[' + aThingsToFetch.toString() + ']');
objTracePoint.nTracePoint = 5;
var obj = PrivateData.objUtil.fnMyEval(obj);
objTracePoint.nTracePoint = 6;
PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0].objElapsedTimes = obj[0];
objTracePoint.nTracePoint = 7;
PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].objDialog = obj[1];
objTracePoint.nTracePoint = 8;
if (PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0].hMachine != null &&
PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0].hMachine[g_strRemoteMachineName] != null)
{
PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0].hMachine[g_strRemoteMachineName].strBuildPassStatus = obj[2];
PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0].hMachine[g_strRemoteMachineName].fSuccess = obj[3];
}
}
}
/*
RefreshPublicData()
We have received notification that the remote machine public
data has changed. We need to grab a copy and place it in our
own public data.
The depot status information can be copied in its entirty, with
just a simple mapping of depot indices.
Each slave machine knows only about the depots its building.
(From enviro_templates\foo_env.xml)
The build machine (this machine) knows about all the depots
being built.
*/
function RefreshPublicData(fForceRoot)
{
var iRemoteDepot;
var dlg;
var Remote_aBuildZero;
var nTracePoint = 0;
try // BUGBUG remove the nTracePoint stuff when the cause of the exception here is determined.
{
if (PrivateData.hRemoteMachine[g_strRemoteMachineName] == null)
return;
nTracePoint = 1;
if (!SmartGetPublic(fForceRoot))
{
return;
}
var RemoteObj = PrivateData.hRemoteMachine[g_strRemoteMachineName].objRemote;
nTracePoint = 2;
if (PrivateData.hRemotePublicDataObj[g_strRemoteMachineName] != null)
{
delete PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].hRemotePublicDataObj;
// Before we update the depot info, first check to see that
// the remote machine has created aBuild[0], and that we have setup hMachine.
if (PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0] != null && PublicData.aBuild[0].hMachine[g_strRemoteMachineName] != null)
{
nTracePoint = 3;
Remote_aBuildZero = PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].aBuild[0];
for (iRemoteDepot = 0; iRemoteDepot < Remote_aBuildZero.aDepot.length; ++iRemoteDepot)
UpdatePublicDataDepot(Remote_aBuildZero.aDepot[iRemoteDepot]);
// now copy the status info stored in hMachine
nTracePoint = 4;
if (Remote_aBuildZero.hMachine[g_strRemoteMachineName] != null)
{
PublicData.aBuild[0].hMachine[g_strRemoteMachineName] = Remote_aBuildZero.hMachine[g_strRemoteMachineName];
}
nTracePoint = 5;
MergeDates(PublicData, PrivateData.hRemotePublicDataObj[g_strRemoteMachineName]);
nTracePoint = 6;
CheckBuildStatus();
nTracePoint = 7;
}
nTracePoint = 8;
if (PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].objDialog != null)
{
dlg = PrivateData.hRemotePublicDataObj[g_strRemoteMachineName].objDialog;
nTracePoint = 9;
DisplayDialog(dlg);
}
}
}
catch(ex)
{
SPLogMsg("RefreshPublicData caught an exception nTracePoint=" + nTracePoint + " " + ex);
}
}
function ReportError(strTitle, strMsg)
{
dlg = new Dialog();
dlg.fShowDialog = true;
dlg.cDialogIndex = 0;
dlg.strTitle = strTitle;
dlg.strMessage = strMsg;
dlg.aBtnText[0] = "OK";
g_MasterQueue.SendMessage('displaydialog',dlg);
}
function MergeDates(pd, rpd)
{
try
{
var objElapsedTimes;
var objRemoteElapsed;
var aDateMembers;
var i = -1;
var dlg;
var fLocked = false;
if (pd.aBuild[0].objElapsedTimes && rpd.aBuild[0].objElapsedTimes)
{
objElapsedTimes = pd.aBuild[0].objElapsedTimes;
objRemoteElapsed = rpd.aBuild[0].objElapsedTimes;
aDateMembers = ['dateScorch', 'dateSync', 'dateBuild', 'dateCopyFiles', 'datePost'];
TakeThreadLock("MergeDates");
fLocked = true;
for(i = 0; i < aDateMembers.length; ++i)
{
objElapsedTimes[aDateMembers[i] + "Start"] = DateCmp(objElapsedTimes, objRemoteElapsed, aDateMembers[i] + "Start", Math.min);
objElapsedTimes[aDateMembers[i] + "Finish"] = DateCmp(objElapsedTimes, objRemoteElapsed, aDateMembers[i] + "Finish", Math.max);
}
ReleaseThreadLock("MergeDates");
fLocked = false;
}
}
catch(ex)
{
JAssert(false, "(" + g_strRemoteMachineName + ") " + "MergeDates crashed, i = " + i + ", " + ex);
if (fLocked)
ReleaseThreadLock("MergeDates");
}
}
// Compare 2 dates from PublicData.
// Paramaters are: the 2 public data objElapsedTimes objects,
// the member name, and a comparision function (min or max).
//
// An empty time (null) is greater than any other time because an unspecified
// time is considered to mean "now". A value of 'unset' means the value has
// never been touched. For obj1, 'unset' is always replaced with the value
// of obj2, and for obj2 'unset' is treated the same as null.
//
// Boolean Matrix: (* = don't care, null = null or empty)
//
// fnCmp = Math.min: fnCmp = Math.max:
//
// obj1 obj2 result obj1 obj2 result
// --------------------------- --------------------------
// "unset" * obj2 "unset" * obj2
// * "unset" same as obj2=null * "unset" same as obj2=null
// null null null null null null
// null date date ####-> null date null <-####
// date null date date null null
// date1 date2 min(date1,date2) date1 date2 max(date1,date2)
//
// The above matrix can be accomplished by treating null as a time which is
// later than all other times (such as the current time or some always future
// date). Note that "unset" and null must be distiguishable due to the case
// marked with "####" above.
//
function DateCmp(obj1, obj2, member, fnCmp)
{
var t1 = obj1[member];
var t2 = obj2[member];
if (t1 == null || t1.length == 0)
t1 = "December 31 9999 23:59:59 UTC";
else if (t1 == 'unset')
return t2;
if (t2 == null || t2.length == 0 || t2 == 'unset')
t2 = "December 31 9999 23:59:59 UTC";
var delta = Date.parse(t1) - Date.parse(t2);
if (fnCmp(delta, 0) == delta)
return obj1[member];
return obj2[member];
}
function NotifyScriptError(RemoteObj, params)
{
var dlg;
var btn;
if (params != null)
{
dlg = PrivateData.objUtil.fnMyEval(params);
DisplayDialog(dlg);
}
}
function DisplayDialog(dlg)
{
if (dlg.cDialogIndex > g_cDialogIndex)
{
SPLogMsg("*** DisplayDialog " + dlg.cDialogIndex + " " + dlg.strTitle + ", " + dlg.strMessage);
g_cDialogIndex = dlg.cDialogIndex;
g_MasterQueue.SendMessage('displaydialog',dlg);
PrivateData.hRemoteMachine[g_strRemoteMachineName].objRemote.Exec('dialog', 'hide,' + dlg.cDialogIndex);
}
}
/*
Check to see if our slave machine has completed a pass
and is waiting for the "nextpass" command.
If it is waiting, then first publish the files in its
publish.log, then signal to harness that this slave is
ready to subscribe and continue to the next pass.
*/
function CheckBuildStatus()
{
var strPubLog;
var strStat;
var nPass;
var mach;
mach = PrivateData.hRemoteMachine[g_strRemoteMachineName];
strStat = PublicData.aBuild[0].hMachine[g_strRemoteMachineName].strBuildPassStatus.split(',');
nPass = strStat[1];
strStat = strStat[0];
switch(strStat)
{
case WAIT + SCORCH:
case WAIT + SYNC:
break;
case WAITBEFOREBUILDINGMERGED:
/*
First, get the publish.log
Then, remove build out our list of published files
and remove duplicates.
Then, tell slave to publish this list of file and change
its status to WAITCOPYTOPOSTBUILD
TODO: The slave currently doesn't actually do the file copies. It oughta.
*/
if (g_aPublishedEnlistments != null)
return;
SPLogMsg("strBuildPassStatus is " + PublicData.aBuild[0].hMachine[g_strRemoteMachineName].strBuildPassStatus + ", pass is " + g_nBuildPass);
strPubLog = mach.objRemote.Exec('GetPublishLog', 0);
g_aPublishedEnlistments = MyEval(strPubLog);
PreCopyFilesToPostBuild(g_aPublishedEnlistments);
break;
case WAITAFTERMERGED:
strPubLog = mach.objRemote.Exec('GetPublishLog', 0);
FakeCopyFilesToPostBuild(MyEval(strPubLog));
break;
case WAIT + BUILD:
case WAITCOPYTOPOSTBUILD:
case WAITNEXT: // impatiently waiting. Lets poke harness again it case it missed something!
case WAITPHASE:
break;
case WAIT + POSTBUILD:
case WAIT + COPYFILES:
case BUSY:
case "":
break;
case COMPLETED:
g_fOKToRestartLostMachine = true;
break;
default:
JAssert(false, "(" + g_strRemoteMachineName + ") " + "CheckBuildStatus failed: unknown status '" + PublicData.aBuild[0].hMachine[g_strRemoteMachineName].strBuildPassStatus + "'");
break;
}
}
// FakeCopyFilesToPostBuild()
// Called after the postbuild machine build mergedcomponents.
// no file copies need to happen here -- we just need to get the
// files onto the list of published files so that the other slaves
// will pick them up during CopyFilesToSlaves
function FakeCopyFilesToPostBuild(aPublishedEnlistments)
{
var aFiles;
var i;
for(i = 0; i < aPublishedEnlistments.length; ++i)
{
PublishFilesInEnlistment(aPublishedEnlistments[i]);
}
RemoveDuplicateFileNames(g_strRemoteMachineName);
JAssert(aPublishedEnlistments != null, "(" + g_strRemoteMachineName + ") ");
if (aPublishedEnlistments)
{
aFiles = CreateListOfPublishedFiles(FS_NOTYETCOPIED, FS_COPIEDTOMASTER);
vRet = SendCmdRemoteMachine("nextpass", 0);
}
}
// Initiate file copy from the slaves to post build machine
function PreCopyFilesToPostBuild(aPublishedEnlistments)
{
g_aFiles = null;
var i;
for(i = 0; i < aPublishedEnlistments.length; ++i)
{
PublishFilesInEnlistment(aPublishedEnlistments[i]);
}
RemoveDuplicateFileNames(g_strRemoteMachineName);
JAssert(aPublishedEnlistments != null, "(" + g_strRemoteMachineName + ") ");
if (aPublishedEnlistments)
{
g_aFiles = CreateListOfPublishedFiles(FS_NOTYETCOPIED, FS_COPIEDTOMASTER);
strNewStat = PrivateData.hRemoteMachine[g_strRemoteMachineName].objRemote.Exec('setbuildpassstatus', WAITCOPYTOPOSTBUILD);
SPLogMsg("setbuildpassstatus to '" + WAITCOPYTOPOSTBUILD + "' returned '" + strNewStat + "'");
PublicData.aBuild[0].hMachine[g_strRemoteMachineName].strBuildPassStatus = strNewStat;
}
}
function CopyFilesToPostBuild()
{
var strNewStat;
if (g_aFiles)
{
//SPLogMsg("CopyFilesToPostBuild " + PrivateData.objUtil.fnUneval(g_aFiles));
strNewStat = PrivateData.hRemoteMachine[g_strRemoteMachineName].objRemote.Exec('copyfilestopostbuild', PrivateData.objUtil.fnUneval(g_aFiles));
PublicData.aBuild[0].hMachine[g_strRemoteMachineName].strBuildPassStatus = strNewStat;
}
g_aPublishedEnlistments = null;
}
/*
Generate a merged publish.log file consisting of all the files published on all of the machines.
Publish.log file format is:
Full_Path_Of_file Original_File_path FileNameOnly
BC does not record "Original_File_path" information from the original publish log files
so it simply writes placeholder "BC_EmptyColumn" in this column.
*/
function CreateMergedPublishLog()
{
var strSrcName;
var strDest;
var strPostBuildMachineDir ;
var strLogPath;
var sdFile;
var aPartsTo;
var strFileName;
strPostBuildMachineDir = PrivateData.objEnviron.BuildManager.Enlistment;
if (strPostBuildMachineDir.charAt(strPostBuildMachineDir.length - 1) == '\\')
strPostBuildMachineDir = substr(0, strPostBuildMachineDir.length - 1);
strLogPath = "\\\\" +
PrivateData.objEnviron.BuildManager.PostBuildMachine + "\\" +
strPostBuildMachineDir.charAt(0) + "$" +
strPostBuildMachineDir.slice(2) +
PUBLISHLOGFILE;
SPLogMsg("Creating publish.log file " + strLogPath);
PrivateData.objUtil.fnDeleteFileNoThrow(strLogPath);
sdFile = LogCreateTextFile(g_FSObj, strLogPath, true);
for(strFileName in PrivateData.hPublishedFiles)
{
if (!PrivateData.hPublishedFiles.__isPublicMember(strFileName))
continue;
objFile = PrivateData.hPublishedFiles[strFileName];
if (objFile.PublishedFile.strPublishedStatus == FS_ADDTOPUBLISHLOG)
{
// The first reference is always the reference into the
// non-duplicate "hPublisher" entry for this particular file.
// Any other aReferences entries will be duplicates.
objFile.PublishedFile.strPublishedStatus = FS_COMPLETE;
nDirLength = objFile.aReferences[0].strDir.length; // For example: "C:\mt\nt";
if (nDirLength > 0)
{ // If strDir happened to include a trailing "\", remove it.
if (objFile.aReferences[0].strDir.charAt(nDirLength - 1) == '\\')
nDirLength--;
}
JAssert(objFile.aReferences[0].strDir.IsEqualNoCase(objFile.PublishedFile.strName.substr(0, nDirLength)));
strPostBuildFileName = strPostBuildMachineDir + // Example: "F:\nt"
objFile.PublishedFile.strName.substr(nDirLength); // Example: \public\sdk\lib\i386\uuid.lib
var aPartsTo = strPostBuildFileName.SplitFileName();
strSrcName = "\\\\" +
objFile.aReferences[0].strName + "\\" +
objFile.aReferences[0].strDir.charAt(0) + "$" +
objFile.PublishedFile.strName.slice(2);
sdFile.WriteLine(strPostBuildFileName + " " + strSrcName + " " + aPartsTo[1] + aPartsTo[2]);
}
}
sdFile.Close();
}
/*
PublishFilesInEnlistment
Called once for each enlistment on the remote machine.
*/
function PublishFilesInEnlistment(objPublishedFiles)
{
JAssert(g_strRemoteMachineName == objPublishedFiles.strLocalMachine, "(" + g_strRemoteMachineName + ") " + "PublishFilesInEnlistment - local machine name doesn't match!");
var PubData;
var publishEnlistment;
var i;
var nFileCount = objPublishedFiles.aNames.length;
var strSrcUNCPrefix = MakeUNCPath(objPublishedFiles.strLocalMachine,
objPublishedFiles.strRootDir,
"");
SPLogMsg("Publish files from host " +
objPublishedFiles.strLocalMachine +
", enlistment is " +
objPublishedFiles.strRootDir);
if (PrivateData.hPublisher[objPublishedFiles.strLocalMachine] == null)
{
PrivateData.hPublisher[objPublishedFiles.strLocalMachine] = new Publisher();
}
PubData = PrivateData.hPublisher[objPublishedFiles.strLocalMachine];
if (PubData.hPublishEnlistment[objPublishedFiles.strRootDir] == null)
PubData.hPublishEnlistment[objPublishedFiles.strRootDir] = new PublishEnlistment;
publishEnlistment = PubData.hPublishEnlistment[objPublishedFiles.strRootDir];
publishEnlistment.strSrcUNCPrefix = strSrcUNCPrefix;
for(i = 0; i < nFileCount; ++i)
{
var file = new PublishedFile();
SPLogMsg("Published file[" + i + "] " + objPublishedFiles.aNames[i]);
file.strPublishedStatus = FS_NOTYETCOPIED;
file.strName = objPublishedFiles.aNames[i];
publishEnlistment.aPublishedFile[publishEnlistment.aPublishedFile.length] = file;
}
}
function CreateListOfPublishedFiles(strOldPublishedStatus, strNewPublishedStatus)
{
try
{
var i;
var PubData = PrivateData.hPublisher[g_strRemoteMachineName];
var strSDRoot;
var publishEnlistment;
var aPublishedEnlistments = new Array();
var objFiles;
for (strSDRoot in PubData.hPublishEnlistment)
{
if (!PubData.hPublishEnlistment.__isPublicMember(strSDRoot))
continue;
publishEnlistment = PubData.hPublishEnlistment[strSDRoot];
objFiles = new Object();
objFiles.strLocalMachine = g_strRemoteMachineName;
objFiles.strRootDir = strSDRoot;
objFiles.aNames = new Array();
for (i = 0; i < publishEnlistment.aPublishedFile.length; ++i)
{
if (publishEnlistment.aPublishedFile[i].strPublishedStatus == strOldPublishedStatus)
{
SPLogMsg("Published file: " + publishEnlistment.aPublishedFile[i].strName);
objFiles.aNames[objFiles.aNames.length] = publishEnlistment.aPublishedFile[i].strName;
publishEnlistment.aPublishedFile[i].strPublishedStatus = strNewPublishedStatus;
}
}
aPublishedEnlistments[aPublishedEnlistments.length] = objFiles;
}
}
catch(ex)
{
SPLogMsg("an error occurred while executing 'CreateListOfPublishedFiles'\n" + ex);
throw ex;
}
return aPublishedEnlistments;
}
/*
Copy all Publushed files to the remote machines
*/
function CopyFilesToSlaves()
{
var strFileName;
var aStrSrcUNCPrefix = new Array(); // Array of enlistment UNCs for this machine
var hEnlistments = new Object();
var strSDRoot;
var i = 0;
var j;
var aReferences;
var aNames = new Array();
var nEnlistments = 0;
try
{
// First, make a list of my enlistments
for(i = 0; i < PrivateData.objEnviron.Machine.length; ++i)
{
if (PrivateData.objEnviron.Machine[i].Name.IsEqualNoCase(g_strRemoteMachineName))
{
// SPLogMsg("hEnlistments[" + PrivateData.objEnviron.Machine[i].Enlistment + "] = 1");
hEnlistments[PrivateData.objEnviron.Machine[i].Enlistment] = 1;
nEnlistments++;
aStrSrcUNCPrefix[aStrSrcUNCPrefix.length] = MakeUNCPath(g_strRemoteMachineName, PrivateData.objEnviron.Machine[i].Enlistment, "");
}
}
// Now for each file, add it to the list of files to copy.
for(strFileName in PrivateData.hPublishedFiles)
{
if (!PrivateData.hPublishedFiles.__isPublicMember(strFileName))
continue;
ScanEnlistments:
for(i = 0; i < aStrSrcUNCPrefix.length; ++i)
{
// Optimization: If a slave has only one enlistment, and
// the slave generated this file, do not copy it
SPLogMsg("File " + strFileName + " status is " + PrivateData.hPublishedFiles[strFileName].PublishedFile.strPublishedStatus);
if (PrivateData.hPublishedFiles[strFileName].PublishedFile.strPublishedStatus == FS_COPYTOSLAVE)
{
// SPLogMsg("nEnlistments = " + nEnlistments);
if (nEnlistments == 1)
{
aReferences = PrivateData.hPublishedFiles[strFileName].aReferences;
for(j = 0; j < aReferences.length; ++j)
{
// SPLogMsg("aReferences[" + j + "].strName = " + aReferences[j].strName + ", " + aReferences[j].strDir);
if (g_strRemoteMachineName == aReferences[j].strName)
{
if (hEnlistments[aReferences[j].strDir] != null)
{
SPLogMsg("Optimizing out copy of " + strFileName + " to " + aStrSrcUNCPrefix[i] + strFileName);
continue ScanEnlistments;
}
}
}
}
// BUGBUG: This is supposed to specify which enlistment on the slave machine to copy to.
// It does not. Thus the for "i" loop is irrelavent.
// If we ever support multiple enlistments on a machine, this will be a problem.
aNames[aNames.length] = strFileName;
}
}
}
return PrivateData.hRemoteMachine[g_strRemoteMachineName].objRemote.Exec('copyfilesfrompostbuildtoslave', PrivateData.objUtil.fnUneval(aNames));
}
catch(ex)
{
SPLogMsg("an error occurred while executing 'CopyFilesToSlaves'\n" + ex);
throw ex;
}
}
// This oughta be a member of PublishedFiles.
function PublishedFilesAddReference(obj, strMachineName, strSDRoot)
{
var nCount = obj.aReferences.length;
obj.aReferences[nCount] = new DepotInfo;
obj.aReferences[nCount].strName = strMachineName;
obj.aReferences[nCount].strDir = strSDRoot;
}
/*
This function gets called to merge each machines published files into the
global list of files.
When a file is published its status defaults to FS_NOTYETCOPIED. If a
FS_NOTYETCOPIED file is encountered, and it is found in the global
list of files (PrivateData.hPublishedFiles), then it is marked FS_DUPLICATE, and reported.
Otherwise it is added to PrivateData.hPublishedFiles.
*/
function RemoveDuplicateFileNames()
{
TakeThreadLock('RemoveDuplicates');
try
{
var i;
var PubData = PrivateData.hPublisher[g_strRemoteMachineName];
var strSDRoot;
var publishEnlistment;
var strFileName;
var objPublishedFiles;
var n;
var strSDRootPublic;
for (strSDRoot in PubData.hPublishEnlistment)
{
if (!PubData.hPublishEnlistment.__isPublicMember(strSDRoot))
continue;
strSDRootPublic = strSDRoot + "\\Public";
publishEnlistment = PubData.hPublishEnlistment[strSDRoot];
for (i = 0; i < publishEnlistment.aPublishedFile.length; ++i)
{
strFileName = publishEnlistment.aPublishedFile[i].strName.slice(strSDRootPublic.length).toLowerCase();
if (publishEnlistment.aPublishedFile[i].strPublishedStatus == FS_NOTYETCOPIED)
{
if (PrivateData.hPublishedFiles[strFileName] != null)
{
SPLogMsg("duplicate file eliminated: " + strFileName);
publishEnlistment.aPublishedFile[i].strPublishedStatus = FS_DUPLICATE;
}
else
{
objPublishedFiles = new PublishedFiles;
PrivateData.hPublishedFiles[strFileName] = objPublishedFiles;
PrivateData.hPublishedFiles[strFileName].PublishedFile = publishEnlistment.aPublishedFile[i];
}
// TODO: Place the enlistment name instead of strSDRoot.
PublishedFilesAddReference(PrivateData.hPublishedFiles[strFileName], g_strRemoteMachineName, strSDRoot);
}
else
{ // The file has already ben processed. Assert that we have an entry in hPublishedFiles.
JAssert(PrivateData.hPublishedFiles[strFileName] != null, "(" + g_strRemoteMachineName + ") ");
}
}
}
}
catch(ex)
{
ReleaseThreadLock('RemoveDuplicates');
SPLogMsg("an error occurred while executing 'RemoveDuplicateFileNames " + ex);
throw ex;
}
ReleaseThreadLock('RemoveDuplicates');
}
function RemoteWrapper(strMachineName)
{
RemoteWrapper.prototype.Exec = RemoteWrapperExec;
RemoteWrapper.prototype.StatusValue = RemoteWrapperStatusValue;
RemoteWrapper.prototype.Connect = RemoteWrapperConnect;
RemoteWrapper.prototype.Register = RemoteWrapperRegister;
RemoteWrapper.prototype.Unregister = RemoteWrapperUnregister;
RemoteWrapper.prototype.Reconnect = RemoteWrapperReconnect;
RemoteWrapper.prototype.VersionCheck = RemoteWrapperVersionCheck;
RemoteWrapper.prototype.RetryCmd = RemoteWrapperRetryCmd;
RemoteWrapper.strErrorMessage = "";
this.fRegistered = false;
this.strMachineName = strMachineName;
this.fMachineReset = false;
this.Connect(strMachineName, true);
this.ex = null;
}
function RemoteWrapperConnect(strMachineName, fThrow)
{
try
{
SPLogMsg("Attempting to connect to " + strMachineName);
this.obj = new ActiveXObject('MTScript.Remote', strMachineName);
this.strErrorMessage = "";
this.VersionCheck();
return true;
}
catch(ex)
{
SPLogMsg("CONNECTION TO " + strMachineName + " FAILED " + ex);
this.strErrorMessage = "" + ex;
if (fThrow)
throw ex;
return false;
}
}
function RemoteWrapperReconnect()
{
var Attempts = 1; // COM tries long and hard to make the connection. No need to prolong things.
var ex;
SPLogMsg("Attempting to reconnect");
while(Attempts > 0)
{
try
{
this.Connect(this.strMachineName, true);
if (this.fRegistered)
this.Register();
this.strErrorMessage = "";
SPLogMsg("RECONNECTED!");
return true;
}
catch(ex)
{
}
--Attempts;
if (Attempts)
{
SPLogMsg("Wait 1 sec then retry");
Sleep(1000);
}
}
SPLogMsg("Reconnect failed");
this.obj = null;
ResetSync(g_SlaveProxyWaitFor[2]);
return false;
}
function RemoteWrapperVersionCheck()
{
var nMajor = this.obj.HostMajorVer;
var nMinor = this.obj.HostMinorVer;
if (nMajor != HostMajorVer || nMinor != HostMinorVer)
{
throw Error(-1, "Host version does not match remote host. (" + HostMajorVer + "." + HostMinorVer + ") != (" + nMajor + "." + nMinor + ")");
}
}
function RemoteWrapperExec(msg,params)
{
return this.RetryCmd('exec', 'this.obj.Exec(' + UnevalString(msg) + ',' + UnevalString(params) + ')');
}
function RemoteWrapperStatusValue(nIndex)
{
return this.RetryCmd('StatusValue', 'this.obj.StatusValue(' + nIndex + ')');
}
function RemoteWrapperRetryCmd(strOp, strCmd)
{
var ex = this.ex;
var vRet;
var Attempts = 2;
var ConnectAttempts;
var objOld;
var strTmp;
try
{
do
{
if (!this.obj)
{
if (this.fMachineReset || !this.Reconnect())
break;
strTmp = MyEval(this.obj.Exec('getpublic', 'PublicData.strMode'));
if (strTmp == 'idle')
{
this.strErrorMessage = "Remote machine has reset -- ";
if (g_fOKToRestartLostMachine)
this.strErrorMessage += "attempting to reconnect";
else
this.strErrorMessage += "build failed";
this.fMachineReset = true;
ex = new Error(-1, this.strErrorMessage);
delete this.obj;
break;
}
}
if (this.obj)
{
try
{
vRet = eval(strCmd);
return vRet;
}
catch(ex)
{
this.strErrorMessage = "" + ex;
SPLogMsg(strOp + " " + strCmd + " FAILED, " + ex);
this.obj = null;
}
}
--Attempts;
}
while(Attempts > 0);
SetDisconnectedDepotStatus(this.strErrorMessage);
SPLogMsg("Unable to reestablish connection");
}
catch(ex2)
{
SPLogMsg("Unexpected exception " + ex2);
}
this.ex = ex;
throw ex;
}
function RemoteWrapperRegister()
{
SPLogMsg("Attempting to register");
RegisterEventSource(this.obj);
this.fRegistered = true;
SPLogMsg("Registered");
}
function RemoteWrapperUnregister()
{
if (this.fRegistered)
UnregisterEventSource(this.obj);
this.fRegistered = false;
}
function getspdata()
{
var pd1;
var pd2;
var o1;
var o2;
var nTracePoint = 0;
try
{
nTracePoint = 1;
nTracePoint = 2;
SPLogMsg("getspdata " + g_strRemoteMachineName);
nTracePoint = 3;
pd1 = PrivateData.objUtil.fnUneval(PublicData);
nTracePoint = 4;
pd1 = PrivateData.objUtil.fnUneval(PrivateData);
nTracePoint = 5;
debugger;
LogMsg(pd1);
LogMsg(pd2);
nTracePoint = 6;
o1 = MyEval(pd1);
nTracePoint = 7;
o2 = MyEval(pd2);
nTracePoint = 8;
}
catch(ex)
{
SPLogMsg("Exception at point " + nTracePoint + " thrown processing 'getspdata'" + ex);
debugger;
}
}