<<>> <> <> <> <> <> <> <> <> DIRECTORY CedarProcess USING [Process], Commander USING [CommandObject, Handle], FS USING [ComponentPositions, Error, ExpandName, StreamOpen], IO USING [Close, noInputStream, noWhereStream, PutF, PutFL, PutFR, PutRope, STREAM, Value], IOClasses USING [CreateDribbleOutputStream], List USING [AList, Assoc, DotCons, PutAssoc], MakeDo USING [ActionRep, EnumerateResults, NodeClassRep, NodeRep, PublicPartsOfNode, UncurrentProducer], MakeDoBasics USING [CheckIn, EndFork, Execution, InnerSuspectNodeChange, NeedToFinish, RegisterReporter, Reporter, ReporterRep, SetES], MakeDoPrivate USING [ActionRep, AddFailedCmd, NodeClassRep, NodeRep], MoreIOClasses USING [CreateBuffer, SendBuffer], Process USING [Abort, InvalidProcess], RefTab USING [Delete], Rope, SimpleFeedback USING [Append]; MakeDoReportOnFiles: CEDAR MONITOR IMPORTS FS, IO, IOClasses, List, MakeDo, MakeDoBasics, MakeDoPrivate, MoreIOClasses, Process, RefTab, Rope, SimpleFeedback <> EXPORTS MakeDo <> <> = BEGIN OPEN MakeDo, MakeDoPrivate, MakeDoBasics; ROPE: TYPE = Rope.ROPE; NodeRep: PUBLIC TYPE = MakeDoPrivate.NodeRep; ActionRep: PUBLIC TYPE = MakeDoPrivate.ActionRep; NodeClassRep: PUBLIC TYPE = MakeDoPrivate.NodeClassRep; <> reporterOnFiles: MakeDoBasics.Reporter ~ NEW [MakeDoBasics.ReporterRep ¬ [ destroyAuxBox: DestroyAuxBox, auxBoxDestroyed: AuxBoxDestroyed, buffer: Buffer, msg: Msg, flush: Flush ]]; AuxBox: TYPE ~ LIST OF FileExecutionViewer; auxBox: AuxBox ¬ NIL; FileExecutionViewer: TYPE ~ REF FileExecutionViewerRep; FileExecutionViewerRep: TYPE ~ RECORD [ logFileName: ROPE, logStream: IO.STREAM ]; bufKey: ATOM = $MakeDoBuffer; logFilePrefix: ROPE ¬ ".makeLog."; auxBoxOccupancy: INT ¬ 0; monitor: BOOL ¬ FALSE; DestroyAuxBox: -- PUBLIC -- PROC ~ { FOR auxRest: AuxBox ¬ auxBox, auxRest.rest WHILE auxRest # NIL DO exView: FileExecutionViewer ~ auxRest.first; exView.logStream.Close[]; ENDLOOP; auxBox ¬ NIL; }; AuxBoxDestroyed: -- PUBLIC -- PROC RETURNS [BOOL ¬ TRUE] ~ { RETURN [auxBox = NIL]; }; Buffer: -- PUBLIC -- ENTRY PROC [e: Execution] = { ENABLE UNWIND => NULL; InnerBuffer[e]; RETURN}; InnerBuffer: INTERNAL PROC [e: Execution] = {--structure contorted to avoid Cirio blind spots ch: Commander.Handle ~ e.ch; bufout: IO.STREAM = MoreIOClasses.CreateBuffer[]; gname, verless, logFileName, fmterr: ROPE; logStream: IO.STREAM; IF AuxBoxDestroyed[] THEN { auxBoxOccupancy ¬ 0; }; auxBoxOccupancy ¬ auxBoxOccupancy + 1; e.bch ¬ NEW [Commander.CommandObject ¬ [ commandLine: "Shouldn't care", propertyList: List.PutAssoc[bufKey, bufout, CopyAList[ch.propertyList]] ]]; gname ¬ MakeDo.PublicPartsOfNode[e.goal].name; {lgname: ROPE ~ gname; fullName: ROPE; cp: FS.ComponentPositions; [fullName, cp, ] ¬ FS.ExpandName[lgname !FS.Error => GOTO Genit]; verless ¬ Rope.Substr[base: fullName, start: 0, len: cp.ext.start+cp.ext.length]; logFileName ¬ Rope.Replace[verless, cp.base.start, 0, logFilePrefix]; EXITS Genit => { logFileName ¬ IO.PutFR["%gAction%g", [rope[logFilePrefix]], [integer[actionCount ¬ actionCount.SUCC]]]; ch.err.PutF["Log for making %g going to %g\n", [rope[gname]], [rope[logFileName]] ]}; }; e.bch.in ¬ IO.noInputStream; {llogFileName: ROPE ~ logFileName; llogStream: IO.STREAM; llogStream ¬ FS.StreamOpen[fileName: llogFileName, accessOptions: create !FS.Error => { fmterr ¬ IO.PutFR["FS.Error[%g, %g]", [atom[error.code]], [rope[error.explanation]] ]; GOTO Complain}]; logStream ¬ llogStream; EXITS Complain => { ch.err.PutF["%g when trying to create command log %g; output will not be logged.\n", [rope[fmterr]], [rope[logFileName]] ]; logStream ¬ IO.noWhereStream} }; {exView: FileExecutionViewer ~ NEW [FileExecutionViewerRep ¬ [logFileName: logFileName, logStream: logStream]]; this: LIST OF FileExecutionViewer ~ LIST[exView]; e.view ¬ exView; IF auxBox = NIL THEN auxBox ¬ this ELSE { this.rest ¬ auxBox; auxBox ¬ this }; }; e.bch.err ¬ e.bch.out ¬ IOClasses.CreateDribbleOutputStream[bufout, logStream]; e.es ¬ buffered; }; CopyAList: PUBLIC PROC [old: List.AList] RETURNS [new: List.AList] ~ { <> tail: List.AList ¬ NIL; new ¬ NIL; UNTIL old = NIL DO newItem: List.AList ¬ LIST[List.DotCons[key: old.first.key, val: old.first.val]]; IF tail = NIL THEN new ¬ newItem ELSE tail.rest ¬ newItem; old ¬ old.rest; tail ¬ newItem; ENDLOOP; <> }; <<>> actionCount: INT ¬ 0; Abandonit: PROC [e: Execution] ~ { {OPEN e; IF NeedToFinish[e] THEN { ENABLE UNWIND => { EndFork[e.resources]; Flush[e, TRUE, TRUE, a.cmd]; [] ¬ job.processes.Delete[process]; }; IF forked THEN Flush[e, TRUE, TRUE, a.cmd]; a.fails ¬ true; AddFailedCmd[job, a]; EnumerateResults[a, InnerSuspectNodeChange]; CheckIn[job, goal, a, e.process]; SetES[e, final]; UncurrentProducer[goal]; SimpleFeedback.Append[$MakeDo, oneLiner, $info, "command execution abandoned"]; } ELSE SimpleFeedback.Append[$MakeDo, oneLiner, $info, "command execution already finishing"]; }}; Stopit: PROC [e: Execution] = { message: ROPE ¬ "command execution ABORTed"; IF e.process # NIL AND e.process.status = busy THEN TRUSTED {Process.Abort[e.process.process !Process.InvalidProcess => { message ¬ IF process#e.process.process THEN "Zowie! Bug 6 encountered!" ELSE IF e.process.status=busy THEN "Wow! CedarProcess bug observed!" ELSE "Already gone!"; CONTINUE; }]} ELSE message ¬ IF e.process = NIL THEN "Can't ABORT because it's not gotten started yet" ELSE SELECT e.process.status FROM done => "Can't ABORT because it's already done", aborted => "Can't ABORT because it's already ABORTED", debugging => "Won't ABORT because it's being debugged", busy => "Wouldn't ABORT because it was not busy a few microseconds ago", invalid => "Won't ABORT because it's invalid", ENDCASE => "Won't ABORT because status unrecognized (I'm suffering software rot!)"; SimpleFeedback.Append[$MakeDo, oneLiner, $info, message]; RETURN}; Gushit: PROC [e: Execution] = { e.gushMe ¬ TRUE; }; Msg: -- PUBLIC -- ENTRY PROC [ch: Commander.Handle, format: ROPE, v1, v2, v3, v4, v5: IO.Value ¬ [null[]]] = { ENABLE UNWIND => NULL; ch.out.PutFL[format, LIST[v1, v2, v3, v4, v5]]; }; Flush: --PUBLIC-- ENTRY PROC [e: Execution, long, abandon: BOOL, asRope: ROPE] = { ENABLE UNWIND => NULL; exView: FileExecutionViewer ~ NARROW[e.view]; bch: Commander.Handle ~ e.bch; ch: Commander.Handle ~ e.ch; buffer: IO.STREAM = NARROW[List.Assoc[bufKey, bch.propertyList]]; last: LIST OF FileExecutionViewer ¬ NIL; IF abandon THEN { ch.out.PutF["%lAbandoning %g%l\n", [rope["be"]], [rope[asRope]], [rope["BE"]]]; MoreIOClasses.SendBuffer[buffer, ch.out, FALSE]; ch.out.PutRope["\n"]; } ELSE IF long THEN MoreIOClasses.SendBuffer[buffer, ch.out, TRUE] ELSE ch.out.PutF["%lDone with %g%l\n", [rope["e"]], [rope[asRope]], [rope["E"]]]; IF AuxBoxDestroyed[] THEN { auxBoxOccupancy ¬ 0; } ELSE FOR cur: LIST OF FileExecutionViewer ¬ auxBox, cur.rest WHILE cur # NIL DO IF cur.first = exView THEN { IF last # NIL THEN last.rest ¬ cur.rest ELSE auxBox ¬ cur.rest; cur.first.logStream.Close[]; auxBoxOccupancy ¬ auxBoxOccupancy - 1; EXIT; }; last ¬ cur; ENDLOOP; }; MakeDoBasics.RegisterReporter[$FILES, reporterOnFiles]; END.