InstallImpl.Mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Spreitzer, June 19, 1986 3:59:08 pm PDT
Willie-Sue, June 18, 1986 4:52:09 pm PDT
Mike Spreitzer July 10, 1986 1:58:36 pm PDT
DIRECTORY AMModel, Atom, BasicTime, Commander, CommandTool, FS, HashTable, Install, InstallPrivate, IO, Process, ReadEvalPrint, Rope;
InstallImpl: CEDAR MONITOR
LOCKS d USING d: Data
IMPORTS AMModel, Atom, BasicTime, Commander, CommandTool, FS, HashTable, IO, Process, Rope
EXPORTS Install
= BEGIN OPEN Install, InstallPrivate;
LORA: TYPE = LIST OF REF ANY;
FileData: TYPE = RECORD [name: ROPE, created: BasicTime.GMT];
notFound: FileData = [NIL, BasicTime.nullGMT];
data: Data ← WITH Atom.GetProp[$InstallImplData, $InstallImplData] SELECT FROM
x: Data => x,
ENDCASE => NIL;
root: AMModel.Context = GetRoot[];
GetRoot: PROC RETURNS [AMModel.Context]
= TRUSTED {RETURN [AMModel.RootContext[]]};
InstallCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF ANYNIL, msg: ROPENIL] --Commander.CommandProc-- = {
from: IO.STREAM = IO.RIS[cmd.commandLine];
FOR i: INT ← from.SkipWhitespace[], from.SkipWhitespace[] WHILE NOT from.EndOf[] DO
subject: ROPE = from.GetTokenRope[IO.IDProc].token;
found, failed: BOOL;
[found, failed] ← Install[subject, cmd];
IF NOT failed THEN NULL
ELSE IF NOT found THEN {
result ← $Failure;
msg ← msg.Cat["Failed to find load file for ", subject, ".\n"];
}
ELSE {
result ← $Failure;
msg ← msg.Cat["Load file for ", subject, " fails.\n"];
};
ENDLOOP;
};
UnInstallCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF ANYNIL, msg: ROPENIL] --Commander.CommandProc-- = {
from: IO.STREAM = IO.RIS[cmd.commandLine];
FOR i: INT ← from.SkipWhitespace[], from.SkipWhitespace[] WHILE NOT from.EndOf[] DO
subject: ROPE = from.GetTokenRope[IO.IDProc].token;
UnInstall[subject, cmd];
ENDLOOP;
};
Install: PUBLIC PROC [subject: ROPE, parent: Commander.Handle] RETURNS [foundFile, failed: BOOL] = {
status: Status = Acquire[data, subject];
SELECT status.state FROM
notDone => ERROR;
inProgress => {
finalState: State ← done;
{ ENABLE UNWIND => SetState[data, status, notDone];
Already: PROC [suffix: ROPE] RETURNS [in: BOOL] = TRUSTED {
in ← AMModel.MostRecentNamedContext[subject.Concat[suffix], root] # NIL;
};
IF Already["Package"] OR Already[NIL] OR Already["Impl"] THEN {
status.usedFile ← FALSE;
failed ← status.failed ← FALSE;
foundFile ← FALSE;
}
ELSE {
fd: FileData = Find[subject, parent];
SELECT status.foundFile ← foundFile ← fd # notFound FROM
FALSE => {finalState ← notDone; failed ← TRUE};
TRUE => {
cp: FS.ComponentPositions;
full, dir: ROPE;
wDir: ROPE = CommandTool.CurrentWorkingDirectory[];
cd: BOOL;
status.usedFile ← TRUE;
[full, cp] ← FS.ExpandName[fd.name];
dir ← CommandTool.ConvertToSlashFormat[full.Substr[len: cp.base.start]];
cd ← NOT dir.Equal[wDir, FALSE];
IF cd THEN [] ← CommandTool.DoCommand[Rope.Cat["Push ", dir], parent];
failed ← status.failed ← CommandTool.DoCommand[Rope.Cat["SecondSource ", full], parent] = $Failure;
IF failed THEN finalState ← notDone;
IF cd THEN [] ← CommandTool.DoCommand["Pop", parent];
};
ENDCASE => ERROR;
};
};
SetState[data, status, finalState];
};
done => {foundFile ← status.foundFile; failed ← status.failed};
ENDCASE => ERROR;
};
UnInstall: PUBLIC PROC [subject: ROPE, parent: Commander.Handle] = {
SetState[data, Acquire[data, subject], notDone];
};
Acquire: ENTRY PROC [d: Data, subject: ROPE] RETURNS [sought: Status] = {
ENABLE UNWIND => {};
sought ← NARROW[d.statuses.Fetch[subject].value];
IF sought = NIL THEN {
sought ← NEW [StatusPrivate ← []];
IF NOT d.statuses.Insert[subject, sought] THEN ERROR;
};
WHILE sought.state = inProgress DO WAIT d.change ENDLOOP;
IF sought.state = notDone THEN sought.state ← inProgress;
};
SetState: ENTRY PROC [d: Data, status: Status, state: State] = {
ENABLE UNWIND => {};
status.state ← state;
BROADCAST d.change;
};
Find: PROC [subject: ROPE, parent: Commander.Handle] RETURNS [fd: FileData] = {
subjectDotLoad: ROPE = subject.Concat[".Load"];
loadSubjectCM: ROPE = Rope.Cat["Load", subject, ".cm"];
searchList: LORACONS[CommandTool.CurrentWorkingDirectory[], NARROW[CommandTool.GetProp[parent, $SearchRules]]];
FOR searchList ← searchList, searchList.rest WHILE searchList # NIL DO
wDir: ROPE = NARROW[searchList.first];
dotLoadData: FileData = GetFileData[subjectDotLoad, wDir];
loadCMData: FileData = GetFileData[loadSubjectCM, wDir];
dotLoadExists: BOOL = dotLoadData # notFound;
loadCMExists: BOOL = loadCMData # notFound;
IF dotLoadExists OR loadCMExists THEN {
RETURN [
IF NOT dotLoadExists THEN loadCMData ELSE
IF NOT loadCMExists THEN dotLoadData ELSE
IF BasicTime.Period[from: dotLoadData.created, to: loadCMData.created] >= 0 THEN loadCMData ELSE dotLoadData
]
};
ENDLOOP;
fd ← notFound;
};
GetFileData: PROC [short, wDir: ROPE] RETURNS [fd: FileData] = {
fd ← notFound;
[fullFName: fd.name, created: fd.created] ← FS.FileInfo[name: short, wDir: wDir, remoteCheck: FALSE !FS.Error => CONTINUE];
};
SecondSource: PROC [cmd: Commander.Handle] RETURNS [result: REF ANYNIL, msg: ROPENIL] --Commander.CommandProc-- = {
ENABLE CommandTool.Failed => {result ← $Failure; msg ← errorMsg; CONTINUE};
argv: CommandTool.ArgumentVector = CommandTool.Parse[cmd: cmd, starExpand: TRUE, switchChar: ' ];
FOR i: INT IN [1 .. argv.argc) DO
fileName: ROPE = argv[i];
in: IO.STREAM = FS.StreamOpen[fileName !FS.Error => {
msg ← IO.PutFR["Failed to open %g: %g %g\n", [rope[fileName]], [atom[error.code]], [rope[error.explanation]]];
result ← $Failure;
LOOP}];
DO
command: ROPE = in.GetLineRope[ !IO.EndOfStream => EXIT];
innerResult: REF ANY = CommandTool.DoCommand[command, cmd];
IF innerResult = $Failure THEN result ← $Failure;
ENDLOOP;
in.Close[];
ENDLOOP;
};
DoCommand: PROC [commandLine: ROPE, parent: Commander.Handle] RETURNS [result: REF ANY] = {
rep: ReadEvalPrint.Handle = NARROW[CommandTool.GetProp[parent, $ReadEvalPrintHandle]];
msg: ROPE = CommandTool.EachCommand[h: rep, command: commandLine];
parent.out.PutRope[msg];
IF msg.Length[] > 0 AND msg.Fetch[msg.Length[] - 1] # '\n THEN parent.out.PutRope["\n"];
result ← CommandTool.GetProp[parent, $Result];
};
Start: PROC = {
IF data = NIL THEN {
data ← NEW [DataPrivate ← [
statuses: HashTable.Create[equal: HashTable.RopeEqualModCase, hash: HashTable.HashRopeModCase]
]];
TRUSTED {
Process.InitializeCondition[@data.change, Process.SecondsToTicks[60]];
Process.EnableAborts[@data.change];
};
Atom.PutProp[$InstallImplData, $InstallImplData, data];
};
Commander.Register["Install", InstallCmd, "Do load file once"];
Commander.Register["UnInstall", UnInstallCmd, "Forget having done load file"];
Commander.Register["SecondSource", SecondSource, "Like Source, but stops on $Failure"];
};
Start[];
END.