MakeDoCmds.Mesa
Copyright Ó 1990 by Xerox Corporation. All rights reserved.
Last Edited by: Spreitzer, June 16, 1986 10:59:30 pm PDT
Eduardo Pelegri-Llopart January 3, 1989 2:10:09 pm PST
Last tweaked by Mike Spreitzer on April 26, 1990 10:54:00 am PDT
Mike Spreitzer August 13, 1991 7:36 am PDT
Willie-s, March 5, 1990 1:18 pm PST
DIRECTORY
Atom USING [MakeAtom],
BasicTime USING [Now],
Commander USING [Handle, Register],
FS USING [Error, FileInfo, nullOpenFile, OpenFile, OpenFileFromStream, SetByteCountAndCreatedTime, StreamOpen],
IO USING [atom, CharClass, Close, EndOf, Flush, GetChar, GetRopeLiteral, GetTokenRope, IDProc, int, PeekChar, PutF, PutFR, PutRope, RIS, rope, SkipWhitespace, STREAM],
IOClasses USING [CreateDribbleOutputStream],
MakeDo,
MakeDoGrossHack,
Process USING [CheckForAbort],
RefTab,
Rope USING [Cat, Concat, Equal, Find, ROPE, Translate, TranslatorType];
MakeDoCmds:
CEDAR
PROGRAM
IMPORTS Atom, BasicTime, Commander, FS, IO, IOClasses, MakeDo, MakeDoGrossHack, Process, RefTab, Rope
=
BEGIN
ROPE: TYPE = Rope.ROPE;
GetObjectOrSwitch:
PROC [from:
IO.
STREAM]
RETURNS [asAny:
REF
ANY] = {
SELECT from.PeekChar[]
FROM
'- => {
IF from.GetChar[] # '- THEN ERROR;
RETURN[Atom.MakeAtom[from.GetTokenRope[Break].token]];
};
ENDCASE => RETURN [GetObject[from]];
};
GetObject:
PROC [from:
IO.
STREAM]
RETURNS [node: MakeDo.Node] = {
SELECT from.PeekChar[]
FROM
'( => {
className, objectName: ROPE;
class: MakeDo.NodeClass;
node: MakeDo.Node;
IF from.GetChar[] # '( THEN ERROR;
className ← from.GetRopeLiteral[];
objectName ← from.GetRopeLiteral[];
[] ← from.SkipWhitespace[];
IF from.GetChar[] # ')
THEN {
SIGNAL MakeDo.Warning["Syntax error, you fool"];
RETURN [NIL];
};
class ← MakeDo.LookupNodeClass[className];
IF class =
NIL
THEN {
SIGNAL MakeDo.Warning[
IO.PutFR[
"no such class as %g",
[refAny[className]]
]];
RETURN [NIL];
};
node ← MakeDo.FindNode[objectName, class];
RETURN [node];
};
ENDCASE => {
fileName: ROPE ← from.GetTokenRope[Break].token;
node: MakeDo.Node ← MakeDo.FindNode[fileName, MakeDo.fileClass];
RETURN [node];
};
};
Break:
PROC [char:
CHAR]
RETURNS [cc:
IO.CharClass] = {
cc ←
SELECT char
FROM
IN [0C .. ' ] => sepr,
ENDCASE => other;
};
DFDontExist: ERROR [fileName: ROPE] = CODE;
CmdMakeDo:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF
ANY ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- =
BEGIN
ENABLE DFDontExist => {msg ← fileName.Concat[" doesn't exist"]; result ← $Failure; CONTINUE};
goals: MakeDo.RefTable ← MakeDo.MakeRefTable[];
modifiable: MakeDo.RefTable ← MakeDo.MakeRefTable[];
supportFiles: MakeDo.RefTable ← MakeDo.MakeRefTable[];
specModifiable, specSupport: BOOL ← FALSE;
allDF: BOOL ← TRUE;
AddDF:
PROC [doToVerifyGoals, doToOwns, doToImports: MakeDo.DoToFile] =
BEGIN
dfIn: IO.STREAM ← NIL;
IF doToVerifyGoals=makeModifiable OR doToOwns=makeModifiable OR doToImports=makeModifiable THEN specModifiable ← TRUE;
IF doToVerifyGoals=makeSupport OR doToOwns=makeSupport OR doToImports=makeSupport THEN specSupport ← TRUE;
[] ← in.SkipWhitespace[];
IF in.EndOf[] THEN {AddMsg["No DF-file name after -whatever"]; RETURN};
dfName ← in.GetTokenRope[Break].token;
IF dfName.Find["."] < 0 THEN dfName ← dfName.Cat[".df"];
[] ← FS.FileInfo[dfName !FS.Error => IF error.group = user THEN DFDontExist[dfName]];
MakeDo.AnalyzeDFFile[dfName, goals, supportFiles, modifiable, doToVerifyGoals, doToOwns, doToImports];
END;
NodeAdd:
PROC [n: MakeDo.Node, goal, mod, supp:
BOOL] = {
IF mod THEN MakeDo.EnsureRefInTable[n, modifiable];
IF goal THEN MakeDo.EnsureRefInTable[n, goals];
IF supp AND n.PublicPartsOfNode[].class = MakeDo.fileClass THEN MakeDo.EnsureRefInTable[n, supportFiles];
};
AddObject:
PROC [goal, mod, supp:
BOOL] = {
n: MakeDo.Node;
IF mod THEN specModifiable ← TRUE;
IF supp THEN specSupport ← TRUE;
[] ← in.SkipWhitespace[];
IF in.EndOf[] THEN {AddMsg["No object after -nm"]; RETURN};
n ← GetObject[in];
NodeAdd[n, goal, mod, supp];
};
AddMsg: PROC [more: ROPE] = {msgout.PutRope[more]; msgout.PutRope["\n"]};
in: IO.STREAM ← IO.RIS[cmd.commandLine];
msgout, logfileStream: IO.STREAM ← NIL;
logFile: FS.OpenFile;
nArgs: INT ← 0;
dfd: BOOL ← FALSE;
dfName: ROPE ← NIL;
logfileStream ← FS.StreamOpen["MakeDo.log", create !FS.Error => {msg ← "Unable to create MakeDo.log"; GOTO Abort}];
logFile ← FS.OpenFileFromStream[logfileStream];
msgout ← IOClasses.CreateDribbleOutputStream[logfileStream, cmd.err];
{ENABLE MakeDo.Warning => {AddMsg[message]; RESUME};
MakeDoGrossHack.SetOLevel[TRUE];
FOR i:
INT ← in.SkipWhitespace[], in.SkipWhitespace[]
WHILE
NOT in.EndOf[]
DO
thing: REF ANY ← GetObjectOrSwitch[in];
nArgs ← nArgs + 1;
IF thing #
NIL
THEN
WITH thing
SELECT
FROM
a:
ATOM =>
SELECT a
FROM
$df, $dr, $rgomis => {AddDF[makeGoal, makeModifiable, makeSupport]; dfd ← TRUE};
$rg => AddDF[makeGoal, ignore, ignore];
$og => AddDF[makeGoal, makeGoal, ignore];
$om => AddDF[makeModifiable, makeModifiable, ignore];
$is => AddDF[ignore, ignore, makeSupport];
$omis => AddDF[makeModifiable, makeModifiable, makeSupport];
$ogis => AddDF[makeGoal, makeGoal, makeSupport];
$rgomns => AddDF[makeGoal, makeModifiable, ignore];
$nm => {AddObject[FALSE, TRUE, FALSE]; allDF ← FALSE};
$ns => {AddObject[FALSE, FALSE, TRUE]; allDF ← FALSE};
$p => {
parms: MakeDo.ForkParms ~ MakeDo.ForkParmsFromStream[in];
MakeDo.SetForkParms[parms]
};
$O2 => MakeDoGrossHack.SetOLevel[FALSE];
$O3 => MakeDoGrossHack.SetOLevel[TRUE];
ENDCASE => AddMsg[IO.PutFR["Bad switch [-%g]", IO.atom[a]]];
ENDCASE => {
n: MakeDo.Node ← MakeDo.NarrowToNode[thing];
NodeAdd[n, TRUE, TRUE, FALSE];
allDF ← FALSE};
Process.CheckForAbort[];
ENDLOOP;
IF NOT specModifiable THEN {modifiable.Erase[]; modifiable ← NIL};
IF NOT specSupport THEN {supportFiles.Erase[]; supportFiles ← NIL};
IF MakeDo.existsFSWatch THEN NULL
ELSE
IF specModifiable
AND specSupport
THEN {
MakeDo.SuspectNodesChange[modifiable];
MakeDo.SuspectNodesChange[supportFiles]}
ELSE MakeDo.ForAll[suspectChange: TRUE, uncurrent: FALSE];
SELECT cmd.procData.clientData
FROM
$MakeDo => {
okGoalCount, nonOKGoalCount, nSteps, nFailedSteps: NAT;
failedSteps: MakeDo.ActionList;
failedGoals: MakeDo.NodeList;
missedSupports: NAT ← 0;
PerMissedSupportFile:
PROC [n: MakeDo.Node] ~ {
msgout.PutRope["Missed support "];
msgout.PutRope[n.DescribeNode[]];
msgout.PutRope[".\n"];
missedSupports ← missedSupports.SUCC;
RETURN};
IF dfd
AND nArgs = 1
AND dfName #
NIL
THEN {
msgout.PutF["MakingDo package in %g.\n", [rope[dfName]]];
};
[okGoalCount:okGoalCount, nonOKGoalCount:nonOKGoalCount, nSteps:nSteps, failedSteps:failedSteps, nonOKGoalList:failedGoals] ← MakeDo.Ensure[goals, modifiable, supportFiles, PerMissedSupportFile, cmd];
nFailedSteps ← 0;
FOR failedSteps ← failedSteps, failedSteps.rest
WHILE failedSteps #
NIL
DO
msgout.PutF["%lFailed: %g%l\n", IO.rope["b"], IO.rope[failedSteps.first.PublicPartsOfAction[].cmd], IO.rope["B"]];
nFailedSteps ← nFailedSteps + 1;
ENDLOOP;
IF nFailedSteps > 0 THEN msgout.PutF["%g failed; %g ok.\n", IO.rope[Quantify[nFailedSteps, "step"]], IO.int[nSteps - nFailedSteps]];
msgout.PutF["%g OK; %g not.\n", IO.rope[Quantify[okGoalCount, "goal"]], IO.int[nonOKGoalCount]];
IF failedGoals #
NIL
THEN {
msgout.PutF["%lNot OK:", IO.rope["b"]];
FOR failedGoals ← failedGoals, failedGoals.rest
WHILE failedGoals #
NIL
DO
msgout.PutF[" %g", IO.rope[failedGoals.first.DescribeNode[]]];
ENDLOOP;
msgout.PutF["%l\n", IO.rope["B"]];
};
result ← IF nonOKGoalCount#0 OR missedSupports#0 THEN $Failure ELSE $Success;
};
$MakePrediction, $MakeCommandList => {
al: MakeDo.ActionList;
IF dfd
AND nArgs = 1
AND dfName #
NIL
THEN {
msgout.PutF["MakingDo package in %g.\n", [rope[dfName]]];
};
al ← MakeDo.GetActions[
goals,
modifiable,
SELECT cmd.procData.clientData
FROM
$MakePrediction => toBeDone,
$MakeCommandList => all,
ENDCASE => ERROR];
al ← MakeDo.DestructivelyReverseActionList[al];
msgout.PutRope["Commands:\n"];
FOR al ← al, al.rest
WHILE al #
NIL
DO
a: MakeDo.Action = al.first;
cmd: ROPE = a.PublicPartsOfAction[].cmd;
msgout.PutF["%g\n", [rope[cmd]] ];
ENDLOOP;
al ← al;
};
ENDCASE => ERROR;
};
msgout.Flush[];
logFile.SetByteCountAndCreatedTime[created: BasicTime.Now[]];
logFile ← FS.nullOpenFile;
logfileStream.Close[];
RETURN;
EXITS Abort => result ← $Failure;
END;
CmdVerify:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF
ANY ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- ~ {
in: IO.STREAM ~ IO.RIS[cmd.commandLine];
logfileStream: IO.STREAM ~ FS.StreamOpen["MakeVerify.log", create !FS.Error => {msg ← "Unable to create MakeVerify.log"; GOTO Abort}];
out: IO.STREAM ~ IOClasses.CreateDribbleOutputStream[logfileStream, cmd.err];
logFile: FS.OpenFile ← FS.OpenFileFromStream[logfileStream];
touchy: BOOL ← TRUE;
errs: INT ← 0;
argList: LIST OF ROPE ← NIL;
revList: LIST OF ROPE ← NIL;
ListToRope:
PROC [list:
LIST
OF
ROPE]
RETURNS [rope:
ROPE ←
NIL] ~ {
FOR rest:
LIST
OF
ROPE ← list, rest.rest
WHILE rest #
NIL
DO
first: ROPE ~ rest.first;
IF rope = NIL THEN rope ← first ELSE rope ← rope.Cat[" ", first];
ENDLOOP;
};
{
ENABLE MakeDo.Warning => {
out.PutRope[message]; out.PutRope["\n"];
errs ← errs + 1;
IF touchy THEN result ← $Failure;
RESUME};
IF
NOT MakeDo.existsFSWatch
THEN
MakeDo.ForAll[suspectChange: TRUE, uncurrent: FALSE];
FOR i:
INT ← in.SkipWhitespace[], in.SkipWhitespace[]
WHILE
NOT in.EndOf[]
DO
arg: ROPE ~ in.GetTokenRope[IO.IDProc].token;
SELECT
TRUE
FROM
arg.Equal["-t"] => touchy ← FALSE;
arg.Equal["-u"] => touchy ← TRUE;
ENDCASE => argList ← CONS[arg, argList];
ENDLOOP;
errs ← 0;
FOR rest:
LIST
OF
ROPE ← argList, rest.rest
WHILE rest #
NIL
DO
first: ROPE ~ rest.first;
revList ← CONS[first, revList];
ENDLOOP;
out.PutF["MakeVerifying %g.\n", [rope[ListToRope[revList]]]];
MakeDo.Verify[revList];
out.PutF["%g error(s) in %g\n", [integer[errs]], [rope[ListToRope[revList]]] ];
out.Flush[];
logFile.SetByteCountAndCreatedTime[created: BasicTime.Now[]];
logFile ← FS.nullOpenFile;
logfileStream.Close[];
};
RETURN;
EXITS Abort => result ← $Failure;
};
CmdListHids:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF
ANY ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- ~ {
in: IO.STREAM ~ IO.RIS[cmd.commandLine];
FOR i:
INT ← in.SkipWhitespace[], in.SkipWhitespace[]
WHILE
NOT in.EndOf[]
DO
n: MakeDo.Node ~ GetObject[in];
name: ROPE ~ MakeDo.PublicPartsOfNode[n].name;
a: MakeDo.Action ~ MakeDo.GetProducer[n];
IF a=
NIL
THEN cmd.out.PutF["%g is a leaf\n", [rope[name]] ]
ELSE {
ac: MakeDo.ActionClass ~ MakeDo.PublicPartsOfAction[a].class;
first: BOOL ← TRUE;
Print:
PROC [hid: MakeDo.Node] ~ {
hidName: ROPE ~ MakeDo.PublicPartsOfNode[hid].name;
IF first
THEN
{first ← FALSE; cmd.out.PutF["%g: ", [rope[name]] ]}
ELSE cmd.out.PutRope[", "];
cmd.out.PutRope[hidName];
RETURN};
IF ac.EnumHiddenDeps#NIL THEN ac.EnumHiddenDeps[a, Print];
IF first THEN cmd.out.PutF["No hidden dependencies for %g", [rope[name]] ];
cmd.out.PutRope["\n"];
};
ENDLOOP;
};
CmdExplain:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF
ANY ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- =
BEGIN
args: MakeDo.RefTable ← MakeDo.MakeRefTable[];
in: IO.STREAM ← IO.RIS[cmd.commandLine];
FOR i:
INT ← in.SkipWhitespace[], in.SkipWhitespace[]
WHILE
NOT in.EndOf[]
DO
ENABLE MakeDo.Warning => {
cmd.out.PutRope[message];
cmd.out.PutRope["\n"];
RESUME};
n: MakeDo.Node ← GetObject[in];
IF n # NIL THEN MakeDo.EnsureRefInTable[n, args];
ENDLOOP;
MakeDo.Explain[cmd, args];
END;
CmdProduce:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF
ANY ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- =
BEGIN
in: IO.STREAM ← IO.RIS[cmd.commandLine];
FOR i:
INT ← in.SkipWhitespace[], in.SkipWhitespace[]
WHILE
NOT in.EndOf[]
DO
ENABLE MakeDo.Warning => {
cmd.out.PutRope[message];
cmd.out.PutRope["\n"];
RESUME};
n: MakeDo.Node ← GetObject[in];
IF n # NIL THEN MakeDo.RetryToProduce[n];
ENDLOOP;
in.Close[];
END;
Bitch: ERROR [message: ROPE] = CODE;
CmdSuspect:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF
ANY ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- =
BEGIN ENABLE Bitch => {msg ← message; result ← $Failure; CONTINUE};
in: IO.STREAM ← IO.RIS[cmd.commandLine];
FOR i:
INT ← in.SkipWhitespace[], in.SkipWhitespace[]
WHILE
NOT in.EndOf[]
DO
ENABLE MakeDo.Warning => {
cmd.out.PutRope[message];
cmd.out.PutRope["\n"];
RESUME};
thing: REF ANY ← GetObjectOrSwitch[in];
DoObject:
PROC [change, current, producer:
BOOL] = {
n: MakeDo.Node;
[] ← in.SkipWhitespace[];
IF in.EndOf[] THEN Bitch["MakeDo ran off end of command line --- missing object"];
n ← GetObject[in];
Work[n, change, current, producer];
};
Work:
PROC [n: MakeDo.Node, change, current, producer:
BOOL] = {
IF change THEN MakeDo.SuspectNodeChange[n];
IF current THEN MakeDo.UncurrentNode[n];
IF producer THEN MakeDo.UncurrentProducer[n];
};
IF thing #
NIL
THEN
WITH thing
SELECT
FROM
a:
ATOM =>
SELECT a
FROM
$allCurrent => MakeDo.ForAll[FALSE, TRUE];
$allChange => MakeDo.ForAll[TRUE, FALSE];
$all => MakeDo.ForAll[TRUE, TRUE];
$change => DoObject[TRUE, FALSE, FALSE];
$current => DoObject[FALSE, TRUE, FALSE];
$producer => DoObject[FALSE, FALSE, TRUE];
ENDCASE => cmd.out.PutF["Unrecognized switch -%g\n", [atom[a]]];
ENDCASE => {
n: MakeDo.Node ← MakeDo.NarrowToNode[thing];
Work[n, TRUE, TRUE, TRUE];
};
ENDLOOP;
in.Close[];
END;
CmdDestroy:
PROC [cmd: Commander.Handle]
RETURNS [result:
REF
ANY ←
NIL, msg:
ROPE ←
NIL]
--Commander.CommandProc-- =
BEGIN
MakeDo.DestroyGraph[!
MakeDo.Warning => {
cmd.out.PutRope[message];
cmd.out.PutRope["\n"];
RESUME}
];
END;
Quantify:
PROC [n:
NAT, stuff:
ROPE]
RETURNS [quantity:
ROPE] =
{quantity ← IO.PutFR["%g %g%g", IO.int[n], IO.rope[stuff], IO.rope[IF n = 1 THEN "" ELSE "s"]]};
FixLines:
PROC [in:
ROPE]
RETURNS [out:
ROPE] ~ {
doIt: Rope.TranslatorType ~ {
SELECT old
FROM
'\r, '\l => RETURN ['\n];
ENDCASE => RETURN [old];
};
out ← Rope.Translate[base: in, translator: doIt];
Commander.Register[key: "MakeDo", proc: CmdMakeDo, clientData: $MakeDo,
doc: FixLines["Ensure that derived files are up to date. Syntax is
MakeDo <arg>*
<arg>:
<object> |
-df <DF file name> |
-dr <DF file name> |
-rg <DF file name> |
-og <DF file name> |
-om <DF file name> |
-is <DF file name> |
-omis <DF file name> |
-ogis <DF file name> |
-rgomis <DF file name> |
-rgomns <DF file name> |
-nm <object> |
-ns <object> |
-p <process limit> <MDS cost per new process> <MDS cost per old process> <minimum MDS requirement>
<object>:
<file name> |
(className:<ROPE> objectName:<ROPE>)"]];
Commander.Register[key: "MakePrediction", proc: CmdMakeDo, clientData: $MakePrediction,
doc: FixLines["Estimate what 'MakeDo' would execute. Syntax is
MakePrediction <arg>*"]];
Commander.Register[key: "MakeCommandList", proc: CmdMakeDo, clientData: $MakeCommandList, doc: FixLines["List all commands needed to make goals. Syntax is
MakeCommandList <arg>*"]];
Commander.Register[key: "MakeVerify", proc: CmdVerify,
doc: FixLines["Verify package(s). Syntax is
MakeVerify <arg>*
<arg>:
-t --tough: never fail
-u --restore defaults"]];
Commander.Register[key: "HiddenDependencies", proc: CmdListHids,
doc: FixLines["List hidden dependencies of objects. Syntax is
HiddenDependencies <object>*"]];
Commander.Register[key: "MakeExcuses", proc: CmdExplain,
doc: FixLines["Explain why MakeDo is misbehaving. Syntax is
MakeExcuses <object>*"]];
Commander.Register[key: "MakeSuspicion", proc: CmdSuspect,
doc: FixLines["Suspect cached information is out of synch with reality. Syntax is
MakeSuspicion <arg>*
<arg>:
-change <object> --suspect the named file of change
-current <object> --forget whether named file is current
-producer <object> --suspect that the next execution of the file's producer will be different from the last
<object> --all of the above
-allChange --suspect every object of change
-allCurrent --suspect every object of not being current and every action of behaving differently than last time
-all --all of the above"]];
Commander.Register[key: "MakeEmpty", proc: CmdDestroy,
doc: FixLines["Delete the entire dependency graph. No arguments"]];
Commander.Register[key: "MakeProducer", proc: CmdProduce,
doc: FixLines["For leaves, try again to find a producer. Syntax is
MakeProducer <object>*"]];
END.
Eduardo Pelegri-Llopart October 19, 1988 1:12:55 pm PDT
Added calls to MakeDo.ForAll[] to compensate for the lack of an FS watcher on PCedar
changes to: CmdMakeDo, CmdVerify, CmdListHids