GetFromReleaseCmds.mesa
Copyright Ó 1985, 1986, 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Michael Plass, February 24, 1992 2:59 pm PST
Rick Beach, June 15, 1985 4:43:22 pm PDT
Spreitzer, September 17, 1985 9:52:39 pm PDT
Mike Spreitzer February 28, 1987 4:05:57 pm PST
Eric Nickell, September 5, 1986 10:56:40 am PDT
Last tweaked by Mike Spreitzer on May 14, 1992 6:26 pm PDT
Willie-Sue, September 26, 1989 4:47:56 pm PDT
Jules Bloomenthal April 19, 1993 8:02 pm PDT
Willie-s, June 1, 1992 9:35 am PDT
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] = {
expect the MakeVerify.log to contain entries like this
MakeVerifying GetFromRelease.DF.
File Rope.bcd (needed by RCompile GetFromReleaseImpl; RCompile GetFromReleaseCmds; RCompile GetFromRelease) missing from DF(s).
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] ~ {
expect the MakeDo.log to contain entries like this
MakingDo package in GetFromRelease.DF.
Can't Compile []<>Users>Spreitzer.pa>Gr>GetFromReleaseImpl.Mesa because []<>Users>Spreitzer.pa>Gr>Foo.BCD, []<>Users>Spreitzer.pa>Gr>Bar.BCD, and []<>Users>Spreitzer.pa>Gr>Gronk.BCD don't exist.
Missed support []<>Users>Spreitzer.pa>GFR>Rope.bcd.
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] ~ {
expect the Mimosa.log to contain entries like this
Command: GetFromReleaseImpl.mesa
GetFromReleaseImpl.mesa -- aborted, 1 errors on GetFromReleaseImpl.errlog, seconds: 6
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"];
[] ← GetFromRelease.GetFile[symbolsName, self, highest, additions, cmd.out];
[] ¬ 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 [<DFFileName> ← ] [<list of file names> | <pattern>] [<option>]
Attach (or copy) from the release directory those files specfied in list.
If no such files, parse MakeDo, MakeVerify, or Compiler error log for errors
about missing files and attach (or copy) the requisite files.
<DFFileName>, if specified, is updated.
Log options:
 -md: use MakeDo log
 -mv: use MakeVerify log
 -c: use Compiler log
 if no log option specified, use the most recent log.
Other options:
 -~h\t\t\t\tuse version specified in the version maps
 -h\t\t\t\t\tuse highest extant version (default)
 -~d\t\t\t\texplicit goals get extension .mob (default)
 -d\t\t\t\t\t'do what I said, darn it!'
 -dir <directory>\tfetch files from named directory (else, use version maps)
 -here <pattern>\tfetch files found in current directory according to pattern
 -map <map>\t\tuse named version map (else use default version maps)
 -f\t\t\t\t\tforce copy rather than attachment (attachment is the default).";
Commander.Register["GetFromRelease", GetFromReleaseCommand, usage];
END.