DIRECTORY Atom USING [MakeAtom], BasicTime USING [GMT, earliestGMT, Period], CedarProcess USING [CheckAbort], Commander USING [CommandProc, Handle, Register], CommanderOps USING [ArgumentVector, Failed, Parse], DFUtilities USING [WriteItemToStream], FileNames USING [GetShortName, ResolveRelativePath], FS USING [ComponentPositions, Copy, EnumerateForNames, Error, ExpandName, FileInfo, NameProc, tDirectory], GetFromRelease USING [CreateImports, GetFile, Imports, UpdateDFFile], IO USING [PutF, PutRope, rope, STREAM], PFS USING [Error, PathFromRope, RopeOpen], RedBlackTree USING [EnumerateIncreasing, Size], Rope USING [Cat, Concat, Equal, EqualSubstrs, Fetch, Find, Index, IsEmpty, Length, ROPE, SkipTo, Substr]; GetFromReleaseCmds: CEDAR PROGRAM IMPORTS Atom, BasicTime, CedarProcess, Commander, CommanderOps, DFUtilities, FileNames, FS, GetFromRelease, IO, PFS, RedBlackTree, Rope ~ BEGIN ROPE: TYPE ~ Rope.ROPE; ROPEList: TYPE ~ LIST OF ROPE; Imports: TYPE ~ GetFromRelease.Imports; Failed: ERROR [explanation: ROPE]; RopeFileCreate: PROC [filename: ROPE] RETURNS [ROPE] ~ { ENABLE PFS.Error => Failed[Rope.Cat["Failed in RopeFileCreate[", filename, "]: ", error.explanation]]; RETURN[PFS.RopeOpen[PFS.PathFromRope[filename]].rope] }; GetFromReleaseCommand: Commander.CommandProc ~ { ENABLE Failed => CommanderOps.Failed[explanation]; argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd]; dir, dfFileName, self, map: ROPE ¬ NIL; additions: Imports ¬ GetFromRelease.CreateImports[]; doMakeDo, dammit: BOOL ¬ FALSE; attach, highest: BOOL ¬ TRUE; toDo: {makeVerify, makeDo, compile, determine} ¬ determine; explicitGoals: ROPEList ¬ NIL; i: NAT ¬ 1; WHILE i < argv.argc DO SELECT TRUE FROM i+1 < argv.argc AND Rope.Equal[argv[i], "-dir"] => { dir ¬ FileNames.ResolveRelativePath[argv[i+1]]; i ¬ i+1; }; i+1 < argv.argc AND Rope.Equal[argv[i], "-here"] => { List: FS.NameProc ~ { IF FS.FileInfo[fullFName].fileType # FS.tDirectory THEN explicitGoals _ CONS[fullFName, explicitGoals]; RETURN[TRUE]; }; FS.EnumerateForNames[argv[i+1], List]; i _ i+1; }; i+1 < argv.argc AND Rope.Equal[argv[i], "-map"] => { map ¬ argv[i+1]; i ¬ i+1; }; argv[i].Equal["-md", FALSE] => toDo ¬ makeDo; argv[i].Equal["-mv", FALSE] => toDo ¬ makeVerify; argv[i].Equal["-c", FALSE] => toDo ¬ compile; argv[i].Equal["-f", FALSE] => attach ¬ FALSE; argv[i].Equal["-h", FALSE] => highest ¬ TRUE; argv[i].Equal["-~h", FALSE] => highest ¬ FALSE; argv[i].Equal["-d", FALSE] => dammit ¬ TRUE; argv[i].Equal["-~d", FALSE] => dammit ¬ FALSE; i+1 < argv.argc AND (argv[i+1].Equal["_"] OR argv[i+1].Equal["¬"]) => { [dfFileName, self] ¬ DefaultExtension[argv[i], "df"]; i ¬ i+1; }; argv[i].Equal[",", FALSE] => NULL; ENDCASE => explicitGoals ¬ CONS[IF dammit THEN argv[i] ELSE DefaultExtension[argv[i], "mob"].fileName, explicitGoals]; i ¬ i + 1; ENDLOOP; IF toDo = determine AND explicitGoals = NIL THEN { dv: INT = BasicTime.Period[BasicTime.earliestGMT, GetCreateDate["MakeVerify.log"]]; dm: INT = BasicTime.Period[BasicTime.earliestGMT, GetCreateDate["MakeDo.log"]]; dc: INT = BasicTime.Period[BasicTime.earliestGMT, GetCreateDate["Compiler.log"]]; latest: INT = MAX[dc, MAX[dv, dm]]; SELECT TRUE FROM latest=0 => RETURN [NIL, "must specify a goal"]; latest=dv => toDo ¬ makeVerify; latest=dm => toDo ¬ makeDo; latest=dc => toDo ¬ compile; ENDCASE => ERROR; }; SELECT TRUE FROM explicitGoals # NIL => { FOR egl: ROPEList ¬ explicitGoals, egl.rest WHILE egl # NIL DO [] ¬ GetFile[egl.first, self, highest, attach, additions, cmd.out, dir, map]; ENDLOOP; }; toDo = makeVerify => { dfFileName ¬ ParseMakeVerifyLog[cmd, self, RopeFileCreate["MakeVerify.log" ! Failed => CONTINUE], highest, attach, additions, dfFileName]; }; toDo = makeDo => { dfFileName ¬ ParseMakeDoLog[cmd, self, RopeFileCreate["MakeDo.log" ! Failed => CONTINUE], highest, attach, additions, dfFileName]; }; toDo = compile => { log: ROPE ~ RopeFileCreate["Mimosa.log"]; IF Rope.Find[s1: log, s2: "Command: ", case: TRUE] > 0 THEN ParseSeparateLogs[cmd, self, log, highest, attach, additions, dir] ELSE ParseCompilerLog[cmd, self, log, highest, attach, additions, dir]; }; ENDCASE => ERROR; WriteAdditions[cmd, dfFileName, additions]; }; GetCreateDate: PROC [fileName: ROPE] RETURNS [created: BasicTime.GMT] = { created ¬ BasicTime.earliestGMT; created ¬ FS.FileInfo[fileName ! FS.Error => CONTINUE].created; RETURN}; GetFile: PROC [ file, self: ROPE, highest, attach: BOOL, additions: Imports, log: IO.STREAM, dir, map: ROPE] ~ { IF Rope.IsEmpty[dir] THEN { mapAtom: ATOM; IF map # NIL THEN mapAtom ¬ Atom.MakeAtom[map]; [] ¬ GetFromRelease.GetFile[file, self, highest, additions, log, mapAtom, attach] } ELSE { ListFiles: FS.NameProc ~ {list ¬ CONS[fullFName, list]; RETURN[TRUE]}; list: ROPEList ¬ NIL; len: INT ¬ Rope.Length[dir]; IF Rope.Fetch[dir, len-1] = '/ THEN dir ¬ Rope.Substr[dir, 0, len-1]; FS.EnumerateForNames[file, ListFiles, dir]; FOR l: ROPEList ¬ list, l.rest WHILE l # NIL DO err, dst: ROPE ¬ NIL; short: ROPE ¬ FileNames.GetShortName[l.first]; src: ROPE ¬ Rope.Cat[dir, "/", short]; CedarProcess.CheckAbort[]; dst ¬ FS.Copy[from: src, to: short, remoteCheck: FALSE, attach: attach ! FS.Error => {err ¬ error.explanation; CONTINUE}]; IF log # NIL THEN IO.PutF[log, "%g --> %g%g\n", IO.rope[src], IO.rope[dst], IO.rope[err]]; ENDLOOP; }; }; ParseMakeVerifyLog: PROC [cmd: Commander.Handle, self, log: ROPE, highest, attach: BOOL, additions: Imports, inDFFileName: ROPE, dir: ROPE ¬ NIL] RETURNS [outDFFileName: ROPE] = { packageIntro: ROPE ~ "MakeVerifying "; packageExtro: ROPE ~ ".\n"; lineStart: ROPE ~ "File "; lineStartLen: INT ~ lineStart.Length[]; lineEnd: ROPE ~ " missing from DF(s)."; lineEndLen: INT ~ lineEnd.Length[]; logLen: INT ~ log.Length[]; introStart, pEnd: INT; outDFFileName ¬ inDFFileName; IF inDFFileName = NIL AND (introStart ¬ Rope.Find[s1: log, s2: packageIntro]) >= 0 THEN { pStart: INT = introStart + packageIntro.Length[]; IF inDFFileName # NIL THEN ERROR; pEnd ¬ Rope.Find[s1: log, s2: packageExtro, pos1: pStart]; IF pEnd <= pStart THEN ERROR; [outDFFileName, self] ¬ DefaultExtension[log.Substr[start: pStart, len: pEnd - pStart], "df"]; }; FOR i: INT ¬ log.Index[s2: "File ", pos1: 0, case: TRUE], log.Index[s2: lineStart, pos1: i+10, case: TRUE] WHILE i < logLen DO eol, eon: INT; raw, fullFName, fileName, ext: ROPE; cp: FS.ComponentPositions; IF i=0 OR (SELECT log.Fetch[i-1] FROM '\r, '\l => FALSE, ENDCASE => TRUE) THEN LOOP; eon ¬ log.SkipTo[i+lineStartLen, " "]; IF eon=logLen THEN EXIT; eol ¬ log.SkipTo[eon, "\r\l"]; IF NOT log.EqualSubstrs[start1: eol-lineEndLen, len1: lineEndLen, s2: lineEnd, case: TRUE] THEN LOOP; raw ¬ log.Substr[start: i+lineStartLen, len: eon-(i+lineStartLen)]; [fullFName, cp] ¬ FS.ExpandName[raw !FS.Error => EXIT]; ext ¬ fullFName.Substr[start: cp.ext.start, len: cp.ext.length]; IF NOT ext.Equal["mob", FALSE] THEN LOOP; fileName ¬ fullFName.Substr[start: cp.base.start, len: (cp.ext.start + cp.ext.length) - cp.base.start]; [] ¬ GetFile[fileName, self, highest, attach, additions, cmd.out, dir, NIL]; ENDLOOP; RETURN}; ParseMakeDoLog: PROC [cmd: Commander.Handle, self, log: ROPE, highest, attach: BOOL, additions: Imports, inDFFileName: ROPE, dir: ROPE ¬ NIL] RETURNS [outDFFileName: ROPE] ~ { packageIntro: ROPE ~ "MakingDo package in "; packageExtro: ROPE ~ ".\n"; tail1: ROPE = "don't exist"; tail2: ROPE = "doesn't exist"; supStart: ROPE ~ "Missed support "; supStartLen: INT ~ supStart.Length[]; logLen: INT ~ log.Length[]; introStart, pEnd: INT; ti1: INT ¬ Rope.Index[s1: log, s2: tail1, pos1: 0, case: FALSE]; ti2: INT ¬ Rope.Index[s1: log, s2: tail2, pos1: 0, case: FALSE]; FindTail: PROC [from: INT] RETURNS [INT] ~ { IF from > ti1 THEN ti1 ¬ Rope.Index[s1: log, s2: tail1, pos1: from, case: FALSE]; IF from > ti2 THEN ti2 ¬ Rope.Index[s1: log, s2: tail2, pos1: from, case: FALSE]; RETURN [MIN[ti1, ti2]]}; SearchBackward: PROC [from: INT] RETURNS [firstNonBlank: INT] = { FOR firstNonBlank ¬ from - 1, firstNonBlank-1 WHILE log.Fetch[firstNonBlank] IN [0C .. ' ] DO --skip trailing whitespace-- NULL ENDLOOP; FOR firstNonBlank ¬ firstNonBlank - 1, firstNonBlank-1 WHILE NOT log.Fetch[firstNonBlank] IN [0C .. ' ] DO --skip nonblanks-- NULL ENDLOOP; firstNonBlank ¬ firstNonBlank + 1; }; SearchForward: PROC [from: INT] RETURNS [firstPastName: INT] = { FOR firstPastName ¬ from, firstPastName+1 DO char: CHAR ¬ log.Fetch[firstPastName]; IF char IN [0C .. ' ] OR char = ', THEN EXIT; ENDLOOP; }; outDFFileName ¬ inDFFileName; IF inDFFileName = NIL AND (introStart ¬ Rope.Find[s1: log, s2: packageIntro]) >= 0 THEN { pStart: INT = introStart + packageIntro.Length[]; IF inDFFileName # NIL THEN ERROR; pEnd ¬ Rope.Find[s1: log, s2: packageExtro, pos1: pStart]; IF pEnd <= pStart THEN ERROR; [outDFFileName, self] ¬ DefaultExtension[log.Substr[start: pStart, len: pEnd - pStart], "df"]; }; FOR i: INT ¬ FindTail[0], FindTail[i+10] WHILE i < logLen DO FOR j: INT ¬ SearchBackward[i], SearchBackward[j] DO k: INT ¬ SearchForward[j]; raw, fullFName, fileName, ext: ROPE; cp: FS.ComponentPositions; raw ¬ log.Substr[start: j, len: k - j]; IF raw.Equal["because"] THEN EXIT; IF raw.Equal["and"] THEN LOOP; [fullFName, cp] ¬ FS.ExpandName[raw !FS.Error => EXIT]; ext ¬ fullFName.Substr[start: cp.ext.start, len: cp.ext.length]; IF NOT ext.Equal["mob", FALSE] THEN LOOP; fileName ¬ fullFName.Substr[start: cp.base.start, len: (cp.ext.start + cp.ext.length) - cp.base.start]; [] ¬ GetFile[fileName, self, highest, attach, additions, cmd.out, dir, NIL]; ENDLOOP; ENDLOOP; FOR i: INT ¬ log.Index[s2: supStart, pos1: 0, case: TRUE], log.Index[s2: supStart, pos1: i+10, case: TRUE] WHILE i < logLen DO eol: INT ~ log.SkipTo[i, "\r\l"]; raw, fullFName, fileName, ext: ROPE; cp: FS.ComponentPositions; IF i=0 OR (SELECT log.Fetch[i-1] FROM '\r, '\l => FALSE, ENDCASE => TRUE) THEN LOOP; IF log.Fetch[eol-1] # '. THEN LOOP; raw ¬ log.Substr[start: i+supStartLen, len: eol-1-(i+supStartLen)]; [fullFName, cp] ¬ FS.ExpandName[raw !FS.Error => EXIT]; ext ¬ fullFName.Substr[start: cp.ext.start, len: cp.ext.length]; IF NOT ext.Equal["mob", FALSE] THEN LOOP; fileName ¬ fullFName.Substr[start: cp.base.start, len: (cp.ext.start + cp.ext.length) - cp.base.start]; [] ¬ GetFile[fileName, self, highest, attach, additions, cmd.out, dir, NIL]; ENDLOOP; RETURN}; ParseSeparateLogs: PROC [cmd: Commander.Handle, self, log: ROPE, highest, attach: BOOL, additions: Imports, dir: ROPE ¬ NIL] ~ { FOR i: INT ¬ Rope.Find[s1: log, s2: " on ", pos1: 0, case: FALSE], Rope.Find[s1: log, s2: " on ", pos1: i+10, case: FALSE] UNTIL i < 0 DO j: INT ¬ Rope.Find[s1: log, s2: ", ", pos1: i, case: FALSE]; errlogName: ROPE ~ Rope.Substr[log, i+4, j-(i+4)]; errlog: ROPE ~ RopeFileCreate[errlogName ! Failed => { IO.PutRope[cmd.err, explanation]; IO.PutRope[cmd.err, "\n"]; LOOP; }; ]; ParseCompilerLog[cmd, self, errlog, highest, attach, additions, dir]; ENDLOOP; }; ParseCompilerLog: PROC [cmd: Commander.Handle, self, log: ROPE, highest, attach: BOOL, additions: Imports, dir: ROPE ¬ NIL] ~ { SearchBackForNewline: PROC [i: INT] RETURNS [INT] ~ { UNTIL SELECT log.Fetch[i] FROM '\l,'\r => TRUE, ENDCASE => FALSE DO i ¬ i - 1 ENDLOOP; RETURN [i] }; FOR i: INT ¬ Rope.Find[s1: log, s2: "cannot be opened", pos1: 0, case: FALSE], Rope.Find[s1: log, s2: "cannot be opened", pos1: i+10, case: FALSE] UNTIL i < 0 DO j: INT ¬ SearchBackForNewline[i]; symbolsName: ROPE ~ Rope.Substr[log, j+1, Rope.Find[log, " ", j+1]-(j+1)].Concat[".mob"]; [] ¬ GetFile[symbolsName, self, highest, attach, additions, cmd.out, dir, NIL]; ENDLOOP; }; WriteAdditions: PROC [cmd: Commander.Handle, dfFileName: ROPE, additions: Imports] = { PerDFFile: PROC [data: REF ANY] RETURNS [stop: BOOL ¬ FALSE] --RedBlackTree.EachNode-- = { DFUtilities.WriteItemToStream[cmd.out, data]; cmd.out.PutRope["\n"]; }; IF additions.Size[] = 0 THEN RETURN; IF dfFileName # NIL AND GetFromRelease.UpdateDFFile[cmd.out, dfFileName, additions] THEN RETURN; cmd.out.PutRope["\nAdd the following to your df file:\n\n"]; additions.EnumerateIncreasing[PerDFFile]; }; DefaultExtension: PROC [raw, ext: ROPE] RETURNS [fileName, base: ROPE] = { fullFName: ROPE; cp: FS.ComponentPositions; IF raw.Length[] = 0 THEN RETURN [NIL, NIL]; [fullFName, cp] ¬ FS.ExpandName[fileName ¬ raw]; base ¬ fullFName.Substr[start: cp.base.start, len: cp.base.length]; IF cp.ext.start = (cp.base.start+cp.base.length) THEN fileName ¬ fileName.Cat[".", ext]; }; usage: ROPE ¬ " GetFromRelease [ _ ] [ | ] [