MakeDoCmds.mesa
Copyright Ó 1990, 1991, 1993 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 March 19, 1992 10:40 am PST
Willie-s, April 27, 1993 11:20 am PDT
Michael Plass, November 27, 1991 10:51 am 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, PutF1, PutFR, PutFR1, 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.PutFR1[
"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 ¬ Rope.Concat[dfName, ".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]
};
$OL => MakeDoGrossHack.SetOLevel[FALSE];
$ON => MakeDoGrossHack.SetOLevel[TRUE];
$O2 => MakeDoGrossHack.SetOLevel[FALSE];
$O3 => MakeDoGrossHack.SetOLevel[TRUE];
ENDCASE => AddMsg[IO.PutFR1["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.PutF1["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]];
IF dfName = NIL THEN msgout.PutF["%g OK; %g not.\n", IO.rope[Quantify[okGoalCount, "goal"]], IO.int[nonOKGoalCount]]
ELSE msgout.PutF["%g OK; %g not in %g.\n", IO.rope[Quantify[okGoalCount, "goal"]], IO.int[nonOKGoalCount], IO.rope[dfName] ];
IF failedGoals # NIL THEN {
msgout.PutF1["%lNot OK:", IO.rope["b"]];
FOR failedGoals ¬ failedGoals, failedGoals.rest WHILE failedGoals # NIL DO
msgout.PutF1[" %g", IO.rope[failedGoals.first.DescribeNode[]]];
ENDLOOP;
msgout.PutF1["%l\n", IO.rope["B"]];
};
result ¬ IF nonOKGoalCount#0 OR missedSupports#0 THEN $Failure ELSE $Success;
};
$MakePrediction, $MakeCommandList => {
out: IO.STREAM ~ cmd.out;
al: MakeDo.ActionList;
IF dfd AND nArgs = 1 AND dfName # NIL THEN {
msgout.PutF1["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];
out.PutRope["Commands:\n"];
FOR al ¬ al, al.rest WHILE al # NIL DO
a: MakeDo.Action = al.first;
cmd: ROPE = a.PublicPartsOfAction[].cmd;
out.PutF1["%g\n", [rope[cmd]] ];
ENDLOOP;
out.Flush[];  -- in case to file by redirection
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.PutF1["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.PutF1["%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.PutF1["%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.PutF1["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.PutF1["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