GetFromReleaseImpl.mesa
Copyright Ó 1985, 1986, 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Michael Plass, March 2, 1990 9:42 am 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:03:50 pm PST
Eric Nickell, September 5, 1986 10:56:40 am PDT
Last tweaked by Mike Spreitzer on November 24, 1987 12:08:48 pm PST
Willie-sue, March 16, 1992 2:20 pm PST
Jules Bloomenthal December 8, 1992 12:32 pm PST
DIRECTORY
Basics USING [Comparison],
BasicTime USING [GMT, nullGMT],
DFUtilities USING [Date, ImportsItem, ParseFromStream, SearchUsingList, SortUsingList, UsingEntry, UsingList, WriteItemToStream],
FS USING [ComponentPositions, Copy, Error, ExpandName, StreamOpen],
GetFromRelease USING [Imports],
IO,
RedBlackTree USING [Create, Delete, Insert, Lookup, LookupNextLarger],
Rope,
VersionMap USING [MapAndNameList, MapList, ShortNameToNames],
VersionMapDefaults USING [GetMapList, WhichMapList];
GetFromReleaseImpl: CEDAR PROGRAM
IMPORTS DFUtilities, FS, IO, RedBlackTree, Rope, VersionMap, VersionMapDefaults
EXPORTS GetFromRelease
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
Imports: TYPE ~ GetFromRelease.Imports;
ROPEList: TYPE ~ LIST OF ROPE;
CreateImports: PUBLIC PROC RETURNS [imports: Imports] ~ {
imports ¬ RedBlackTree.Create[GetClauseKey, CompareClauses];
};
GetClauseKey: PROC [data: REF ANY] RETURNS [key: REF ANY] --RedBlackTree.GetKey-- = {
ii: REF DFUtilities.ImportsItem ¬ NARROW[data];
key ¬ ii.path1;
};
CompareClauses: PROC [k, data: REF ANY] RETURNS [c: Basics.Comparison] --RedBlackTree.Compare-- = {
k1: ROPE ¬ NARROW[k];
i2: REF DFUtilities.ImportsItem ¬ NARROW[data];
k2: ROPE ¬ i2.path1;
fn1, fn2: ROPE;
cp1, cp2: FS.ComponentPositions;
SELECT TRUE FROM
(k1=NIL) AND (k2#NIL) => RETURN [less];
(k1#NIL) AND (k2=NIL) => RETURN [greater];
(k1=NIL) AND (k2=NIL) => RETURN [equal];
ENDCASE;
[fn1, cp1] ¬ FS.ExpandName[k1];
[fn2, cp2] ¬ FS.ExpandName[k2];
IF (c ¬ fn1.Substr[start: cp1.base.start].Compare[fn2.Substr[start: cp2.base.start], FALSE]) # equal THEN RETURN;
c ¬ fn1.Substr[len: cp1.base.start].Compare[fn2.Substr[len: cp2.base.start], FALSE];
};
GetFile: PUBLIC PROC [fileName, self: ROPE, highest: BOOL, imports: Imports ¬ NIL, log: IO.STREAM ¬ NIL, mapAtom: ATOM, attach: BOOL ¬ TRUE] RETURNS [gotIt: BOOL] = {
Try: PROC [which: VersionMapDefaults.WhichMapList] RETURNS [gotIt: BOOL ¬ TRUE] ~ {
mapList: VersionMap.MapList ~ VersionMapDefaults.GetMapList[which];
list: VersionMap.MapAndNameList ~ VersionMap.ShortNameToNames[mapList, fileName];
FOR p: VersionMap.MapAndNameList ¬ list, p.rest UNTIL p=NIL DO
remoteFileName: ROPE ~ p.first.name;
fullFName, toFName, package, result, dfFile, src: ROPE ¬ NIL;
cp: FS.ComponentPositions;
shortFileName: ROPE;
[fullFName, cp] ¬ FS.ExpandName[remoteFileName];
IF cp.subDirs.length # 0 THEN-- check for new style pseudoServer
package ¬ Rope.Substr[fullFName, cp.subDirs.start, cp.subDirs.length]
ELSE package ¬ Rope.Substr[fullFName, cp.dir.start, cp.dir.length];
shortFileName ¬
Rope.Substr[fullFName, cp.base.start, cp.base.length + cp.ext.length + 1];
the + 1 is for the . between the base and the extension
IF log # NIL THEN log.PutF["\nfullFName: %g, package: %g, prefix: %g, shortFileName: %g\n",
[rope[fullFName]], [rope[package]], [rope[prefix]], [rope[shortFileName]] ];
IF package.Equal[self, FALSE] THEN --ain't this clever?-- {
IF log # NIL THEN log.PutF["I won't import %g from its own package (%g)\n", IO.rope[fileName], IO.rope[package]];
EXIT;
};
attach or copy the remote filename
src ¬ IF highest THEN fullFName.Substr[len: cp.ext.start+cp.ext.length] ELSE remoteFileName;
IF log # NIL THEN {
log.PutRope[src];
log.PutRope[" --> "];
};
toFName ¬ FS.Copy[from: src, to: shortFileName, remoteCheck: FALSE, attach: attach
! FS.Error => { result ¬ error.explanation; CONTINUE }];
IF log # NIL THEN {
log.PutRope[toFName];
log.PutRope[result];
log.PutRope["\n"];
};
IF NOT result.IsEmpty THEN LOOP; -- avoid attaching df file when failed to attach mob
IF imports # NIL THEN {
determine DF file from package directory name from the convention [Cedar10.1]<Package>Interface.mob
notFound: BOOL ¬ FALSE;
server: ROPE ¬ Rope.Substr[fullFName, cp.server.start, cp.server.length];
dfFile ¬ IO.PutFR["[%g]<Top>%g.df", [rope[server]], [rope[package]] ];
IF log # NIL THEN log.PutF["\ndfFile: %g\n", [rope[dfFile]] ];
[] ¬ FS.Copy[from: dfFile, to: Rope.Concat[package, ".df"], remoteCheck: TRUE, attach: attach
! FS.Error => {
notFound ¬ error.code = $unknownFile;
result ¬ error.explanation;
CONTINUE}];
IF notFound THEN {
result ¬ NIL;
dfFile ¬ IO.PutFR["[%g]<Top>%g-PCR.df", [rope[server]], [rope[package]] ];
[] ¬ FS.Copy[from: dfFile, to: Rope.Concat[package, "-PCR.df"], attach: attach
! FS.Error => { result ¬ error.explanation; CONTINUE }];
};
IF result.IsEmpty THEN {
EnsureFileImport[imports, dfFile, fileName];
EXIT;
}
ELSE IF log = NIL THEN NULL
ELSE {
log.PutF["DF file name guess %g for %g failed (%g)\n", IO.rope[dfFile], IO.rope[fileName], IO.rope[result]];
};
}
ELSE EXIT;
REPEAT
FINISHED => gotIt ¬ FALSE;
ENDLOOP;
RETURN};
gotIt ← Try[$Symbols] OR Try[$Source];
IF mapAtom = NIL THEN gotIt ¬ Try[$Source] OR Try[$Symbols]
ELSE gotIt ¬ Try[mapAtom];
IF (NOT gotIt) AND log # NIL THEN {
log.PutF1["Couldn't guess a DF-file for %g", [rope[fileName]]];
IF mapAtom # NIL THEN log.PutF1[" (using map %g)", [atom[mapAtom]] ];
log.PutChar['\n];
};
RETURN;
};
PackageNameFromDirPath: PROC[dirPath: DFS.DirList] RETURNS[package, prefix: ROPE] = {
easier: LIST OF ROPE ← RopeList.Reverse[dirPath];
reversePrefix: LIST OF ROPE;
IF ( easier.first.Equal["sun4", FALSE] ) OR ( easier.first.Equal["sun4-O3", FALSE] ) THEN {
package ← easier.rest.first;
reversePrefix ← easier.rest.rest;
}
ELSE {
package ← easier.first;
reversePrefix ← easier.rest;
};
FOR rp: LIST OF ROPE ← reversePrefix, rp.rest UNTIL rp = NIL DO
prefix ← Rope.Cat[rp.first, "/", prefix]
ENDLOOP;
};
EnsureFileImport: PROC [clauses: Imports, dfFileName, fileName: ROPE] = {
ii: REF DFUtilities.ImportsItem ¬ NARROW[clauses.Lookup[dfFileName]];
IF ii = NIL THEN {
clauses.Insert[
ii ¬ NEW [DFUtilities.ImportsItem ¬ [
path1: dfFileName,
date: [notEqual],
exported: FALSE,
form: list,
list: NEW [DFUtilities.UsingList[1]]
]],
dfFileName];
ii.list.nEntries ¬ 0;
};
EnsureFileInList[ii, [name: fileName]];
};
EnsureFileInList: PROC [ii: REF DFUtilities.ImportsItem, ue: DFUtilities.UsingEntry] = {
found: BOOL;
index: NAT;
[found, index] ¬ DFUtilities.SearchUsingList[ue.name, ii.list];
IF found THEN {
ii.list[index].verifyRoot ¬ ii.list[index].verifyRoot OR ue.verifyRoot;
RETURN;
};
IF ii.list.nEntries = ii.list.length THEN {
new: REF DFUtilities.UsingList ¬ NEW [DFUtilities.UsingList[ii.list.length*2]];
FOR i: NAT IN [0 .. ii.list.nEntries) DO
new[i] ¬ ii.list[i];
ENDLOOP;
new.nEntries ¬ ii.list.nEntries;
ii.list ¬ new;
};
ii.list[ii.list.nEntries] ¬ ue;
ii.list.nEntries ¬ ii.list.nEntries + 1;
DFUtilities.SortUsingList[ii.list, TRUE];
};
UpdateDFFile: PUBLIC PROC [log: IO.STREAM, dfFileName: ROPE, imports: Imports] RETURNS [success: BOOL] = {
oldin, newout: IO.STREAM ¬ NIL;
lastKey: ROPE ¬ NIL;
DoUpTo: PROC [limit: REF DFUtilities.ImportsItem] = {
FOR ti: REF DFUtilities.ImportsItem ¬ NARROW[imports.LookupNextLarger[lastKey]], NARROW[imports.LookupNextLarger[ti.path1]] WHILE ti # NIL AND (limit = NIL OR CompareClauses[ti.path1, limit] < equal) DO
DFUtilities.WriteItemToStream[newout, ti];
newout.PutRope["\n"];
lastKey ¬ ti.path1;
ENDLOOP;
};
PerItem: PROC [item: REF ANY] RETURNS [stop: BOOL ¬ FALSE] --DFUtilities.ProcessItemProc-- = {
WITH item SELECT FROM
ii: REF DFUtilities.ImportsItem => IF ~ii.exported THEN {
mergeable: BOOL ¬ Vanilla[ii];
IF mergeable THEN {
ti: REF DFUtilities.ImportsItem ¬ NARROW[imports.Lookup[ii.path1]];
IF ti # NIL AND CompareClauses[lastKey, ti] < equal THEN {
IF NOT Vanilla[ti] THEN ERROR;
FOR i: NAT IN [0 .. ti.list.nEntries) DO
EnsureFileInList[ii, ti.list[i]];
ENDLOOP;
IF imports.Delete[ti.path1].data # ti THEN ERROR;
};
};
DoUpTo[ii];
};
ENDCASE;
DFUtilities.WriteItemToStream[newout, item];
};
oldin ¬ FS.StreamOpen[dfFileName !FS.Error => {
log.PutF1["FS.Error %g --- DF file not updated\n", IO.rope[error.explanation]];
oldin ¬ NIL;
CONTINUE
}];
IF oldin = NIL THEN RETURN [FALSE];
newout ¬ FS.StreamOpen[dfFileName, create !FS.Error => {
log.PutF1["FS.Error %g --- DF file not updated\n", IO.rope[error.explanation]];
oldin ¬ NIL;
CONTINUE
}];
IF newout = NIL THEN RETURN [FALSE];
DFUtilities.ParseFromStream[oldin, PerItem, [comments: TRUE]];
newout.PutRope["\n"];
DoUpTo[NIL];
oldin.Close[];
newout.Close[];
success ¬ TRUE;
};
Vanilla: PROC [ii: REF DFUtilities.ImportsItem] RETURNS [vanilla: BOOL] =
{vanilla ¬ ii.date = [notEqual] AND ii.path2.Length[] = 0 AND (NOT ii.exported) AND ii.form = list AND ii.list # NIL};
END.