MakeDoSimpleImpl.Mesa
Last Edited by: Spreitzer, September 4, 1985 10:59:31 pm PDT
Carl Hauser, April 11, 1985 3:43:34 pm PST
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 BOOLFALSE;
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
FileViewerOps.WaitUntilSaved[fileName: n.name, feedBack: GetCommanderHandle[].err];
[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: BOOLFALSE] --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: BOOLFALSE] --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: BOOLFALSE] = {
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.