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];
~
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];