DIRECTORY Commander, CommanderBackdoor, CommanderOps, IO, PFS, Process, Rope, RopeList, SymTab, InstallationComforts, InstallationSupportPrivate, MesaLoadState; CommanderInstallCommandsImpl: CEDAR MONITOR IMPORTS Commander, CommanderBackdoor, CommanderOps, IO, PFS, Process, Rope, RopeList, SymTab, InstallationComforts, MesaLoadState EXPORTS MesaLoadState -- Opaque type ~ BEGIN PATH: TYPE ~ PFS.PATH; ROPE: TYPE ~ Rope.ROPE; ConfigRep: PUBLIC TYPE ~ InstallationSupportPrivate.ConfigRep; IsExported: PROC [qualifiedName: ROPE] RETURNS [BOOL] ~ { global: REF ConfigRep = MesaLoadState.GlobalConfig[]; dot: INT ~ Rope.Find[qualifiedName, "."]; IF dot >= 0 THEN { interface: ROPE ~ Rope.Substr[qualifiedName, 0, dot]; item: ROPE ~ Rope.Substr[qualifiedName, dot+1]; a: PROCEDURE ANY RETURNS ANY ~ InstallationComforts.ProcFromNamedInterface[interface, item, global]; RETURN [a # NIL] } ELSE { RETURN [FALSE] -- might want to test for existence of the interface record }; }; InstallData: TYPE = REF InstallDataPrivate; InstallDataPrivate: TYPE = RECORD [ statuses: SymTab.Ref, change: CONDITION ]; InstallStatus: TYPE = REF InstallStatusPrivate; InstallStatusPrivate: TYPE = RECORD [ state: InstallState ฌ notDone, foundFile: BOOL ฌ FALSE, failed: BOOL ฌ TRUE ]; InstallState: TYPE = {notDone, inProgress, done}; installData: InstallData ฌ InitInstallData[]; InitInstallData: PROC RETURNS [installData: InstallData] ~ { installData ฌ NEW [InstallDataPrivate ฌ [ statuses: SymTab.Create[case: FALSE] ]]; TRUSTED { Process.InitializeCondition[@installData.change, Process.SecondsToTicks[60]]; Process.EnableAborts[@installData.change]; }; }; ForgetInstallationCommand: Commander.CommandProc = { from: IO.STREAM = IO.RIS[cmd.commandLine]; FOR i: INT ฌ from.SkipWhitespace[], from.SkipWhitespace[] WHILE NOT from.EndOf[] DO packageName: ROPE = from.GetTokenRope[IO.IDProc].token; ForgetInstallation[packageName]; ENDLOOP; }; ForgetInstallation: PUBLIC PROC [packageName: ROPE] = { SetInstallState[installData, AcquireInstallStatus[installData, packageName], notDone]; }; Installed: PUBLIC PROC [packageName: ROPE] = { status: InstallStatus ~ AcquireInstallStatus[installData, packageName]; status.failed ฌ FALSE; SetInstallState[installData, status, done]; }; GetInstalled: PUBLIC ENTRY PROC RETURNS [LIST OF ROPE] = { list: LIST OF ROPE ฌ NIL; EachPair: PROC [key: ROPE, val: REF] RETURNS [quit: BOOL ฌ FALSE] ~ { WITH val SELECT FROM status: InstallStatus => { IF status.state = done THEN list ฌ CONS[key, list]; }; ENDCASE => NULL; }; [] ฌ SymTab.Pairs[installData.statuses, EachPair]; RETURN [RopeList.Sort[list, RopeList.IgnoreCase]] }; IsInstalled: PUBLIC ENTRY PROC [key: ROPE] RETURNS [BOOL] = { ENABLE UNWIND => NULL; sought: InstallStatus ฌ NARROW[installData.statuses.Fetch[key].val]; RETURN [IF sought = NIL OR sought.state = notDone THEN FALSE ELSE TRUE]; }; IfInstalledCommand: Commander.CommandProc = { ris: IO.STREAM ~ IO.RIS[cmd.commandLine]; resource: ROPE ~ CommanderOps.GetCmdToken[ris].value; IF resource = NIL THEN CommanderOps.Failed[cmd.procData.doc]; IF (cmd.procData.clientData=$NOT) # IsInstalled[resource] THEN RETURN CommanderOps.ExecuteCommand[cmd, IO.GetRope[ris]]; }; IfProcExportedCommand: Commander.CommandProc = { ris: IO.STREAM ~ IO.RIS[cmd.commandLine]; resource: ROPE ~ CommanderOps.GetCmdToken[ris].value; IF resource = NIL THEN CommanderOps.Failed[cmd.procData.doc]; IF (cmd.procData.clientData=$NOT) # IsExported[resource] THEN RETURN CommanderOps.ExecuteCommand[cmd, IO.GetRope[ris]]; }; whenInstalled: SymTab.Ref ฌ SymTab.Create[case: FALSE]; WhenInstalled: PUBLIC ENTRY PROC [key: ROPE, commandLine: ROPE] RETURNS [doItNow: BOOL ฌ FALSE] = { ENABLE UNWIND => NULL; sought: InstallStatus ฌ NARROW[installData.statuses.Fetch[key].val]; doItNow ฌ NOT (sought = NIL OR sought.state = notDone); IF NOT doItNow THEN { Update: SymTab.UpdateAction ~ { actions: LIST OF ROPE ฌ NARROW[val]; IF actions = NIL THEN actions ฌ LIST[commandLine] ELSE FOR tail: LIST OF ROPE ฌ actions, tail.rest DO IF tail.rest = NIL THEN {tail.rest ฌ LIST[commandLine]; EXIT}; ENDLOOP; RETURN [op: store, new: actions]; }; SymTab.Update[whenInstalled, key, Update]; }; }; WhenInstalledCommand: Commander.CommandProc = { ris: IO.STREAM ~ IO.RIS[cmd.commandLine]; resource: ROPE ~ CommanderOps.GetCmdToken[ris].value; IF resource = NIL THEN { PrintEachPair: SymTab.EachPairAction ~ { FOR tail: LIST OF ROPE ฌ NARROW[val], tail.rest UNTIL tail = NIL DO IO.PutRope[cmd.out, "WhenInstalled "]; IO.PutRope[cmd.out, key]; IO.PutRope[cmd.out, " "]; IO.PutRope[cmd.out, tail.first]; ENDLOOP; }; [] ฌ SymTab.Pairs[whenInstalled, PrintEachPair]; } ELSE { commandLine: ROPE ~ Rope.Cat["From ", PFS.RopeFromPath[PFS.GetWDir[]], IO.GetRope[ris]]; doItNow: BOOL ~ WhenInstalled[resource, commandLine]; IF doItNow THEN RETURN CommanderOps.ExecuteCommand[cmd, commandLine]; }; }; RequireCommand: Commander.CommandProc = { ENABLE PFS.Error => { IF error.group=user THEN ERROR CommanderOps.Failed[error.explanation] }; world: ROPE ~ CommanderOps.NextArgument[cmd]; component: ROPE ~ CommanderOps.NextArgument[cmd]; resource: ROPE ~ CommanderOps.NextArgument[cmd]; found, failed: BOOL; IF CommanderOps.NextArgument[cmd] # NIL OR resource = NIL THEN CommanderOps.Failed[cmd.procData.doc]; [found, failed] ฌ Require[world: world, component: component, resource: resource, parent: cmd]; SELECT TRUE FROM NOT failed => { NULL }; NOT found => { result ฌ $Failure; msg ฌ msg.Cat["Failed to find ", resource, ".require file.\n"]; }; ENDCASE => { result ฌ $Failure; msg ฌ msg.Cat[resource, ".require file ", " failed.\n"]; }; }; InstallCommand: Commander.CommandProc = { ENABLE PFS.Error => { IF error.group=user THEN ERROR CommanderOps.Failed[error.explanation] }; again: BOOL ฌ FALSE; n: NAT ฌ 0; FOR resource: ROPE ฌ CommanderOps.NextArgument[cmd], CommanderOps.NextArgument[cmd] UNTIL resource = NIL DO n ฌ n + 1; SELECT TRUE FROM resource.Equal["-a", FALSE] => again ฌ TRUE; resource.Equal["-~a", FALSE] => again ฌ FALSE; ENDCASE => { found, failed: BOOL; IF again THEN ForgetInstallation[resource]; [found, failed] ฌ Install[resource, cmd]; SELECT TRUE FROM NOT failed => { NULL }; NOT found => { result ฌ $Failure; msg ฌ msg.Cat["Failed to find ", resource, ".require file.\n"]; }; ENDCASE => { result ฌ $Failure; msg ฌ msg.Cat[resource, ".require file ", " failed.\n"]; }; }; ENDLOOP; IF n = 0 THEN RETURN [$Failure, "Install (-a|-~a|packageName)* - Ensure the installation of one or more packages. -a => install again, even if already installed"]; }; InstalledCommand: Commander.CommandProc = { n: NAT ฌ 0; FOR arg: ROPE ฌ CommanderOps.NextArgument[cmd], CommanderOps.NextArgument[cmd] UNTIL arg = NIL DO Installed[arg]; n ฌ n + 1; ENDLOOP; IF n = 0 THEN { FOR tail: LIST OF ROPE ฌ GetInstalled[], tail.rest UNTIL tail = NIL DO IO.PutRope[cmd.out, tail.first]; IO.PutRope[cmd.out, IF tail.rest = NIL THEN "\n" ELSE " "]; ENDLOOP; }; }; SecondSource: PUBLIC PROC [fileName: ROPE, parent: Commander.Handle, stopOnFailure: BOOL ฌ FALSE] RETURNS [allOK: BOOL ฌ FALSE] = { fileStream: IO.STREAM ~ PFS.StreamOpen[PFS.PathFromRope[fileName]]; BEGIN ENABLE UNWIND => { IO.Close[fileStream, TRUE] }; child: Commander.Handle ~ CommanderOps.CreateFromStreams[in: fileStream, parentCommander: parent]; data: CommanderBackdoor.CommandToolData ~ CommanderBackdoor.GetCommandToolData[child]; data.stopOnFailure ฌ stopOnFailure; allOK ฌ NOT CommanderOps.ReadEvalPrintLoop[child].hadFailure; END; IO.Close[fileStream, TRUE]; }; Install: PUBLIC PROC [packageName: ROPE, parent: Commander.Handle] RETURNS [foundFile, failed: BOOL] = { status: InstallStatus = AcquireInstallStatus[installData, packageName]; SELECT status.state FROM notDone => ERROR; inProgress => { finalState: InstallState ฌ done; { ENABLE UNWIND => { SetInstallState[installData, status, notDone] }; installFileName: ROPE = packageName.Concat[".require"]; foundFile ฌ TRUE; [] ฌ PFS.FileInfo[PFS.PathFromRope[installFileName] ! PFS.Error => IF error.group = user THEN { foundFile ฌ FALSE; CONTINUE } ]; SELECT status.foundFile ฌ foundFile FROM FALSE => { finalState ฌ notDone; failed ฌ TRUE }; TRUE => { status.failed ฌ failed ฌ NOT SecondSource[installFileName, parent, stopOnFailureDuringInstall]; IF failed THEN finalState ฌ notDone; }; ENDCASE => ERROR; }; SetInstallState[installData, status, finalState]; }; done => { foundFile ฌ status.foundFile; failed ฌ status.failed }; ENDCASE => ERROR; IF NOT failed THEN { commandLines: LIST OF ROPE ฌ NIL; Update: SymTab.UpdateAction ~ { IF found THEN { commandLines ฌ NARROW[val]; RETURN [op: delete] }; }; SymTab.Update[whenInstalled, packageName, Update]; FOR tail: LIST OF ROPE ฌ commandLines, tail.rest UNTIL tail = NIL DO [] ฌ CommanderOps.DoCommand[tail.first, parent]; ENDLOOP; }; }; stopOnFailureDuringInstall: BOOL ฌ TRUE; Require: --PUBLIC-- PROC [world, component, resource: ROPE, parent: Commander.Handle] RETURNS [foundFile, failed: BOOL ฌ FALSE] = { RequireInner: PROC ~ { [foundFile, failed] ฌ Install[resource, parent]; }; path: PATH ~ PFS.PathFromRope[Rope.Cat["/", world, "/", component, "/"]]; PFS.DoInWDir[path, RequireInner]; }; AcquireInstallStatus: ENTRY PROC [d: InstallData, packageName: ROPE] RETURNS [sought: InstallStatus] = { ENABLE UNWIND => {}; sought ฌ NARROW[d.statuses.Fetch[packageName].val]; IF sought = NIL THEN { sought ฌ NEW [InstallStatusPrivate ฌ []]; IF NOT d.statuses.Insert[packageName, sought] THEN ERROR; }; WHILE sought.state = inProgress DO WAIT d.change ENDLOOP; IF sought.state = notDone THEN sought.state ฌ inProgress; }; SetInstallState: ENTRY PROC [d: InstallData, status: InstallStatus, state: InstallState] = { ENABLE UNWIND => {}; status.state ฌ state; BROADCAST d.change; }; Commander.Register[key: "ForgetInstallation", proc: ForgetInstallationCommand, doc: "ForgetInstallation packageName* - Forget that one or more packages are installed", clientData: NIL]; Commander.Register[key: "IfInstalled", proc: IfInstalledCommand, doc: "packageName commandLine\ndo the commandLine if the named package has been installed", clientData: NIL]; Commander.Register[key: "IfNotInstalled", proc: IfInstalledCommand, doc: "packageName commandLine\ndo the commandLine if the named package has not been installed", clientData: $NOT]; Commander.Register[key: "IfProcExported", proc: IfProcExportedCommand, doc: "interface.procedure commandLine\ndo the commandLine if the named procedure is exported", clientData: NIL]; Commander.Register[key: "IfProcNotExported", proc: IfProcExportedCommand, doc: "interface.procedure commandLine\ndo the commandLine if the named procedure is not exported", clientData: $NOT]; Commander.Register[key: "Install", proc: InstallCommand, doc: "Install (-a|-~a|packageName)* - Ensure the installation of one or more packages. -a => install again, even if already installed", clientData: NIL]; Commander.Register[key: "Installed", proc: InstalledCommand, doc: "packageName ... - Record the named packages as having been installed\n (no args tells you what has been installed)", clientData: NIL]; Commander.Register[key: "Require", proc: RequireCommand, doc: "Usage: Require - Ensure the installation of a resource", clientData: NIL]; Commander.Register[key: "WhenInstalled", proc: WhenInstalledCommand, doc: "packageName commandLine\ndo the commandLine as soon as the named package becomes installed\n(no arguments => print the pending commands)", clientData: $NOT]; Installed["BasicCedar"]; Installed["CedarCore"]; Installed["Commander"]; IF IsExported["BootTime.Get"] THEN Installed["DebugNubCedarParts"]; IF IsExported["Feedback.Append"] THEN Installed["Feedback"]; IF IsExported["LocalRegistryAgent.MaintainService"] THEN Installed["LocalRegistryAgent"]; IF IsExported["LocalRegistryClient.Register"] THEN Installed["LocalRegistryClient"]; IF IsExported["PFS.FileInfo"] THEN Installed["PFS"]; IF IsExported["SunPMapClient.CallWithMultipleReplies"] THEN Installed["SunPMapClient"]; IF IsExported["SunRPC.StartCall"] THEN Installed["SunRPCRuntime"]; IF IsExported["SystemNames.UserName"] THEN Installed["SystemNames"]; END. l CommanderInstallCommandsImpl.mesa Copyright ำ 1989, 1990, 1991 by Xerox Corporation. All rights reserved. Michael Plass, January 14, 1992 10:25 am PST Chauser, July 31, 1990 1:26 pm PDT Willie-s, July 23, 1991 10:23 am PDT Christian Jacobi, July 21, 1992 5:20 pm PDT Load state inquiry Install Commands Returns TRUE if it needs to be done right away. PROC [found: BOOL, val: Val] RETURNS [op: UpdateOperation _ none, new: Val _ NIL] PROC [key: Key, val: Val] RETURNS [quit: BOOL _ FALSE] PROC [found: BOOL, val: Val] RETURNS [op: UpdateOperation _ none, new: Val _ NIL] Registration What's already running... ส•NewlineDelimiter –(cedarcode) style™codešœ!™!Kšœ ฯeœ=™HK™,K™"K™$K™+K™—šฯk œ-žœžœc˜ K˜—Kšฯnœžœž˜+Kšžœ-žœžœF˜Kšžœฯc˜$šœž˜K˜Kšžœžœžœžœ˜Kšžœžœžœ˜—head™K˜Kšœ žœžœ(˜>š Ÿ œžœžœžœžœ˜9Kšœžœ*˜5Kšœžœ!˜)šžœ ˜ šžœ˜Kšœ žœ&˜5Kšœžœ%˜/Kš œž œžœžœžœH˜dKšžœžœ˜Kšœ˜—šžœ˜Kšžœžœ ;˜JKšœ˜——Kšœ˜—K˜—™Kšœ žœžœ˜+šœžœžœ˜#K˜Kšœž ˜K˜—K˜Kšœžœžœ˜/šœžœžœ˜%Kšœ˜Kšœ žœžœ˜Kšœžœž˜K˜—K˜Kšœžœ˜1K˜šœ-˜-šŸœžœžœ˜<šœžœ˜)Kšœžœ˜$K˜—šžœ˜ KšœM˜MKšœ*˜*K˜—K˜K˜——šŸœ˜4Kš œžœžœžœžœ˜*š žœžœ0žœžœž˜SKšœ žœžœ˜7Kšœ ˜ Kšžœ˜—K˜—K˜šŸœžœžœžœ˜7KšœV˜VK˜—K˜šŸ œžœžœžœ˜.KšœG˜GKšœžœ˜Kšœ+˜+K˜K˜—šŸ œžœžœžœžœžœžœžœ˜:Kš œžœžœžœžœ˜šŸœžœžœžœžœžœžœ˜Ešžœžœž˜šœ˜Kšžœžœžœ ˜3Kšœ˜—Kšžœžœ˜—Kšœ˜—Kšœ2˜2Kšžœ+˜1K˜K˜—šŸ œžœžœžœžœžœžœ˜=Kšžœžœžœ˜Kšœžœ&˜DKšžœžœ žœžœžœžœžœžœ˜HK˜K˜—šŸœ˜-Kš œžœžœžœžœ˜)Kšœ žœ'˜5Kšžœ žœžœ'˜=Kšžœ8žœžœ"žœ˜xKšœ˜K˜—šŸœ˜0Kš œžœžœžœžœ˜)Kšœ žœ'˜5Kšžœ žœžœ'˜=Kšžœ7žœžœ"žœ˜wKšœ˜K˜—Kšœ0žœ˜7šŸ œžœžœžœžœžœžœ žœžœ˜cJ™/Kšžœžœžœ˜Kšœžœ&˜DKšœ žœ žœžœ˜7šžœžœ žœ˜šŸœ˜Kšžœ žœ žœ)žœ™RKš œ žœžœžœžœ˜$šžœ ž˜Kšžœ žœ ˜ š žœžœžœžœžœž˜3Kš žœ žœžœžœžœ˜>Kšžœ˜——Kšžœ˜!Kšœ˜—Kšœ*˜*Kšœ˜—Kšœ˜K˜—šŸœ˜/Kš œžœžœžœžœ˜)Kšœ žœ'˜5šžœ ž˜šžœ˜šŸ œ˜(Kšžœžœžœžœ™6šžœžœžœžœžœžœžœž˜CKšžœ$˜&Kšžœ˜Kšžœ˜Kšžœ˜ Kšžœ˜—Kšœ˜—Kšœ0˜0Kšœ˜—šžœ˜Kš œ žœžœžœ žœ˜XKšœ žœ(˜5Kšžœ žœžœ/˜EKšœ˜——Kšœ˜K˜—šŸœ˜)Kš žœžœ žœžœžœ*˜^Kšœžœ"˜-Kšœ žœ"˜1Kšœ žœ"˜0Kšœžœ˜Kš žœ"žœžœ žœžœ'˜eKšœ_˜_šžœžœž˜Kšžœ žœ˜šžœ ˜Kšœ˜Kšœ?˜?K˜—šžœ˜ K˜Kšœ8˜8K˜——K˜K˜—šŸœ˜)Kš žœžœ žœžœžœ*˜^Kšœžœžœ˜Kšœžœ˜ š žœ žœBžœ žœž˜kK˜ šžœžœž˜Kšœžœ žœ˜,Kšœžœ žœ˜.šžœ˜ Kšœžœ˜Kšžœžœ˜+Kšœ)˜)šžœžœž˜Kšžœ žœ˜šžœ ˜Kšœ˜Kšœ?˜?K˜—šžœ˜ K˜Kšœ8˜8K˜——Kšœ˜——Kšžœ˜—Kšžœžœžœ˜ฃK˜K˜—šŸœ˜+Kšœžœ˜ š žœžœBžœžœž˜aKšœ˜K˜ Kšžœ˜—šžœžœ˜š žœžœžœžœžœžœž˜FKšžœ˜ Kš žœžœ žœžœžœ˜;Kšžœ˜—Kšœ˜—K˜—K˜šŸ œžœžœ žœ+žœžœžœ žœžœ˜ƒKš œ žœžœžœ žœ˜Cš žœžœžœžœžœ˜6Kšœb˜bKšœV˜VKšœ#˜#Kšœžœ2˜=Kšžœ˜—Kšžœžœ˜K˜K˜—š Ÿœžœžœžœžœžœ˜hKšœG˜Gšžœž˜Kšœ žœ˜˜K˜ šœžœžœ6˜EKšœžœ"˜7Kšœ žœ˜Kšœžœ žœ!žœ žœžœžœžœ˜€šžœž˜(Kšžœžœžœ˜1šžœ˜ KšœžœC˜_Kšžœžœ˜$K˜—Kšžœžœ˜—K˜—Kšœ1˜1K˜—KšœA˜AKšžœžœ˜—šžœžœžœ˜Kšœž œžœ˜!šŸœ˜Kšžœ žœ žœ)žœ™RKšžœžœžœžœ˜BKšœ˜—Kšœ2˜2š žœžœžœžœžœžœž˜DKšœ0˜0Kšžœ˜—Kšœ˜—K˜Kšœžœžœ˜(—K˜š Ÿœ  œžœžœžœž œ˜ƒšŸ œžœ˜Kšœ0˜0Kšœ˜—Kšœžœžœ9˜IKšžœ˜!K˜K˜—š Ÿœžœžœžœžœ˜hKšžœžœ˜Kšœ žœ$˜3šžœ žœžœ˜Kšœ žœ˜)Kšžœžœ(žœžœ˜9K˜—Kšžœžœžœ žœ˜9Kšžœžœ˜9K˜—K˜šŸœžœžœA˜\Kšžœžœ˜K˜Kšž œ ˜K˜——™ Kšœดžœ˜นKšœฉžœ˜ฎKšœฐžœ˜ถKšœฒžœ˜ทKšœนžœ˜ฟKšœอžœ˜าKšœลžœ˜สKšœฃžœ˜จKšœโžœ˜่—™Kšœ˜Kšœ˜Kšœ˜šžœ˜Kšžœ!˜%—šžœ˜ Kšžœ˜—šžœ1˜3Kšžœ!˜%—šžœ+˜-Kšžœ"˜&—šžœ˜Kšžœ˜—šžœ4˜6Kšžœ˜ —šžœ˜!Kšžœ˜ —šžœ#˜%Kšžœ˜——K˜Kšžœ˜—…—/j@U