<<>> <> <> <> <> <> <> <> <> 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 * : | -df | -dr | -rg | -og | -om | -is | -omis | -ogis | -rgomis | -rgomns | -nm | -ns | -p : | (className: objectName:)"]]; Commander.Register[key: "MakePrediction", proc: CmdMakeDo, clientData: $MakePrediction, doc: FixLines["Estimate what 'MakeDo' would execute. Syntax is MakePrediction *"]]; Commander.Register[key: "MakeCommandList", proc: CmdMakeDo, clientData: $MakeCommandList, doc: FixLines["List all commands needed to make goals. Syntax is MakeCommandList *"]]; Commander.Register[key: "MakeVerify", proc: CmdVerify, doc: FixLines["Verify package(s). Syntax is MakeVerify * : -t --tough: never fail -u --restore defaults"]]; Commander.Register[key: "HiddenDependencies", proc: CmdListHids, doc: FixLines["List hidden dependencies of objects. Syntax is HiddenDependencies *"]]; Commander.Register[key: "MakeExcuses", proc: CmdExplain, doc: FixLines["Explain why MakeDo is misbehaving. Syntax is MakeExcuses *"]]; Commander.Register[key: "MakeSuspicion", proc: CmdSuspect, doc: FixLines["Suspect cached information is out of synch with reality. Syntax is MakeSuspicion * : -change --suspect the named file of change -current --forget whether named file is current -producer --suspect that the next execution of the file's producer will be different from the last --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 *"]]; END. <> <> <> <<>>