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 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
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:
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.