<> <> <> DIRECTORY Atom, BasicTime, Commander, CommandTool, FS, HashTable, Install, InstallPrivate, IO, Process, Rope; InstallImpl: CEDAR MONITOR LOCKS d USING d: Data IMPORTS 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; InstallCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] --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: BOOL; [found, result] _ Install[subject, cmd]; IF NOT found THEN RETURN[$Failure, Rope.Cat["Failed to find load file for ", subject]]; ENDLOOP; }; UnInstallCmd: PROC [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] --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: BOOL, result: REF ANY] = { status: Status = Acquire[data, subject]; SELECT status.state FROM notDone => ERROR; inProgress => { finalState: State _ done; { ENABLE UNWIND => SetState[data, status, notDone]; fd: FileData = Find[subject, parent]; foundFile _ fd # notFound; SELECT foundFile _ fd # notFound FROM FALSE => {finalState _ notDone; result _ NIL}; TRUE => { cp: FS.ComponentPositions; full, dir: ROPE; wDir: ROPE = CommandTool.CurrentWorkingDirectory[]; cd: BOOL; [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]; result _ status.result _ CommandTool.DoCommand[Rope.Cat["Source ", full], parent]; IF cd THEN [] _ CommandTool.DoCommand["Pop", parent]; }; ENDCASE => ERROR; }; SetState[data, status, finalState]; }; done => {foundFile _ TRUE; result _ status.result}; 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: LORA _ CONS[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]; }; 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"]; }; Start[]; END.