<> <> <> DIRECTORY Basics, BasicTime, CedarProcess, Commander, CommandTool, Convert, FileNames, FileViewerOps, FS, IO, List, MakeDo, MakeDoPrivate, Process, ProcessProps, RedBlackTree, Rope, TimeStamp; MakeDoSimpleImpl: CEDAR PROGRAM IMPORTS CedarProcess, CommandTool, Convert, FS, IO, MakeDo, MakeDoPrivate, Process, RedBlackTree, Rope EXPORTS MakeDo, MakeDoPrivate = BEGIN OPEN MakeDo, MakeDoPrivate; Warning: PUBLIC SIGNAL [message: ROPE] = CODE; NodeRep: PUBLIC TYPE = MakeDoPrivate.NodeRep; CommandRep: PUBLIC TYPE = MakeDoPrivate.CommandRep; lastJob: Job _ NIL; debugging: PUBLIC BOOL _ FALSE; fileClass: PUBLIC NodeClass _ NEW [NodeClassRep _ [ CanonizeName: CannonizeFileName, GetTime: GetFileTime ]]; CannonizeFileName: PROC [random: ROPE] RETURNS [canonical: ROPE] = { full: ROPE; cp: FS.ComponentPositions; [full, cp] _ FS.ExpandName[random]; canonical _ full.Substr[len: cp.ext.start + cp.ext.length]; }; GetFileTime: PUBLIC PROC [n: Node] RETURNS [created: Time] --GetTimeProc-- = BEGIN <> [created: created] _ FS.FileInfo[n.name !FS.Error => {created _ notExistTime; CONTINUE}]; END; leafClass: CommandClass _ NEW [CommandClassRep _ [Explain: ExplainLeaf]]; leaf: PUBLIC Command _ NEW [CommandRep _ [cmd: "-- leaf", class: leafClass, down: NewMonitorLock[]]]; ExplainLeaf: ExplainProc = {to.PutRope[" OOPS! Internal inconsistency (#3)\n"]}; ConvertFromSlashFormat: PROC [slashy: ROPE] RETURNS [squigly: ROPE] = BEGIN cp: FS.ComponentPositions; full: ROPE; [fullFName: full, cp: cp] _ FS.ExpandName[slashy.Concat["foo"]]; squigly _ full.Substr[start: 0, len: cp.base.start]; END; EnglishList: PUBLIC PROC [nl: NodeList] RETURNS [el: ROPE, ec: CARDINAL] = BEGIN twoOfMany: ROPE; ec _ 0; FOR nl _ nl, nl.rest WHILE nl # NIL DO SELECT ec FROM =0 => el _ nl.first.name; =1 => { twoOfMany _ nl.first.name.Cat[", and ", el]; el _ nl.first.name.Cat[" and ", el]; }; =2 => el _ nl.first.name.Cat[", ", twoOfMany]; >2 => el _ nl.first.name.Cat[", ", el]; ENDCASE => ERROR; ec _ ec + 1; ENDLOOP; END; Ensure: PUBLIC PROC [ch: Commander.Handle, goals, modifiable: Table, guessBoundary, assumeAllInconsistent, suspectAll, do, record: BOOL] RETURNS [nFailed, nSucceeded, nSteps: NAT, failedSteps: CommandList, cmds: ROPE] = BEGIN job: Job _ lastJob _ NEW [JobRep _ [ wDir: CommandTool.CurrentWorkingDirectory[], visit: NewVisit[], goals: goals, modifiable: modifiable, boundaryKnown: NOT guessBoundary, assumeAllInconsistent: assumeAllInconsistent, do: do, record: record ]]; sg: Subgoal _ NEW [SubgoalRep _ [ job: job, toDo: NewWorkTable[], parent: NIL ]]; QueueGoal: PROC [data: REF ANY] RETURNS [stop: BOOL _ FALSE] --RedBlackTree.EachNode-- = { goal: Node _ NARROW[data]; nWork: WorkRef _ NEW [WorkRec _ [ job: job, subject: node[goal], depth: 0]]; CedarProcess.CheckAbort[]; InsertWork[sg.toDo, nWork]; }; CountGoal: PROC [data: REF ANY] RETURNS [stop: BOOL _ FALSE] --RedBlackTree.EachNode-- = { goal: Node _ NARROW[data]; SELECT Exists[goal] FROM FALSE => nFailed _ nFailed + 1; TRUE => nSucceeded _ nSucceeded + 1; ENDCASE => ERROR; }; IF assumeAllInconsistent THEN suspectAll _ TRUE; IF suspectAll THEN SuspectAll[change: FALSE, remake: TRUE]; nSucceeded _ nFailed _ 0; goals.EnumerateIncreasing[QueueGoal]; AchieveGoal[sg]; goals.EnumerateIncreasing[CountGoal]; RETURN [nFailed, nSucceeded, job.nSteps, job.failedSteps, job.cmds]; END; Explain: PUBLIC PROC [ch: Commander.Handle, nodes: Table, verbosely: BOOL] = { to: IO.STREAM = ch.out; ExplainNode: PROC [data: REF ANY] RETURNS [stop: BOOL _ FALSE] = { n: Node = NARROW[data]; created: Time = GetCreated[n]; ShowConsumer: PROC [e: Edge, which: CmdDep] = { c: Command = e.c; diff: ROPE = IF e.traverseCreated # created THEN "*" ELSE ""; to.PutF["\n%g\t\t%g", [rope[diff]], IO.rope[c.cmd]]; IF verbosely THEN to.PutF["\n\t\t\t%g", [rope[FmtTime[e.traverseCreated]]]]; }; to.PutF["%g\n\tneeded by: {", IO.rope[n.name]]; EnumerateConsumerEdges[n, data, ShowConsumer]; to.PutRope["}\n\tdetermines: {"]; EnumerateConsumerEdges[n, cmd, ShowConsumer]; to.PutRope["}\n"]; IF n.forceNotExist THEN to.PutRope["\tEffectively doesn't exist because producing command fails\n"] ELSE SELECT created FROM notExistTime => to.PutRope["\tDoesn't exist\n"]; unknownTime => to.PutRope["\tCreate time unavailable\n"]; ENDCASE => to.PutF["\tCreated at %g\n", IO.time[created]]; to.PutRope[IF n.suspect THEN "\tNeeds investigation\n" ELSE "\tDoes not need investigation\n"]; IF n.producer = NIL OR n.producer.c = leaf THEN to.PutRope["\tis a leaf\n"] ELSE ExplainCmd[n.producer.c]; }; ExplainCmd: PROC [c: Command] = { ShowResult: PROC [n: Node] = {to.PutF["\t\t%g\n", IO.rope[n.name]]}; ShowSource: PROC [n: Node, which: CmdDep, optional: BOOL] = {to.PutF["\t\t%g%g\n", IO.rope[IF optional THEN "?" ELSE ""], IO.rope[n.name]]}; missedResults: NodeList; needsToBeDone, outdated: BOOL; to.PutF["%g:\n\tAccording to:\n", IO.rope[c.cmd]]; EnumerateSources[c, cmd, ShowSource]; to.PutRope["\tMakes:\n"]; EnumerateResults[c, ShowResult]; to.PutRope["\tFrom:\n"]; EnumerateSources[c, data, ShowSource]; [missedResults, outdated] _ NeedsToBeDone[lastJob, c, TRUE]; needsToBeDone _ (missedResults#NIL) OR outdated; to.PutRope[IF c.suspect[cmd] THEN "\tMay need to be rederived\n" ELSE "\tDoes not need to be rederived\n"]; to.PutRope[IF c.suspect[data] THEN "\tMay need to be reexecuted\n" ELSE "\tDoes not need to be reexecuted\n"]; to.PutRope[IF c.suspectNeed THEN "\tMay have newly needed results\n" ELSE "\tDoes not have newly needed results\n"]; IF c.reasonWhyLastDone # NIL THEN to.PutF["\tLast executed because %g\n", [rope[c.reasonWhyLastDone]]]; IF c.failed THEN to.PutRope["\tFails\n"]; IF outdated THEN { to.PutRope["\tneeds to be executed because of inconsistency:\n"]; c.class.Explain[c, to]; }; IF missedResults # NIL THEN to.PutF["\tneeds to be executed because result(s) %g missing\n", IO.rope[EnglishList[missedResults].el]]; IF NOT needsToBeDone THEN { to.PutRope["\tdoes not need to be executed, because:\n"]; c.class.Explain[c, to]; }; IF NOT c.canBeDone THEN { to.PutF["\tcan't be executed because %g can't be made.\n", IO.rope[EnglishList[c.missedSources].el]]; }; }; IF lastJob = NIL THEN { to.PutRope["Explain may only be invoked after MakeDo\n"]; RETURN}; nodes.EnumerateIncreasing[ExplainNode]; }; IsLeaf: PUBLIC PROC [job: Job, n: Node] RETURNS [BOOL] = { isLeaf: BOOL _ n.producer = NIL OR n.producer.c = leaf OR (job.boundaryKnown AND NOT NodeInTable[n, job.modifiable]); RETURN [isLeaf]; }; FmtTime: PUBLIC PROC [t: Time] RETURNS [asRope: ROPE] = { asRope _ SELECT t FROM notExistTime => "never", unknownTime => "unknown", ENDCASE => Convert.RopeFromTime[from: t, end: seconds, useAMPM: FALSE, includeZone: FALSE]; }; mmlTimeout: Process.Ticks _ Process.SecondsToTicks[60]; NewMonitorLock: PUBLIC PROC RETURNS [mml: MyMonitorLock] = { mml.locked _ FALSE; TRUSTED { cp: Process.ConditionPointer = @mml.change; Process.InitializeCondition[cp, mmlTimeout]; Process.EnableAborts[cp]; }; }; END.