<> <> <> DIRECTORY Basics USING [bytesPerWord], BasicTime USING [GMT, Now, nullGMT, ToPupTime], BcdDefs USING [BCD, NullVersion, VersionStamp], Commander USING [CommandProc, Register], DefaultRemoteNames USING [Get], DFUtilities USING [Date, RemoveVersionNumber], FS USING [Error, FileInfo, minimumStreamBufferParms, Open, OpenFile, StreamFromOpenFile, StreamOpen], FSBackdoor USING [EnumerateCacheForInfo, InfoProc], GenerateDFClosure USING [ActionProc, ClosureInfo, GenerateClosureToProc], IFSFile USING [CantOpen, Close, Completer, Error, FileHandle, Finalize, FSInstance, Initialize, Login, Logout, Open, Problem, StartRead, UnableToLogin], IO USING [Close, EndOfStream, GetIndex, GetTokenRope, IDProc, PutChar, PutF, PutFR, PutRope, RIS, SetIndex, SetLength, STREAM, UnsafeGetBlock], MessagesOut USING [PutRopes], PriorityQueue USING [Insert, Predict, Ref, Remove, Size, SortPred], Process USING [Pause, SecondsToTicks], ProcessExtras USING [CheckForAbort], Rope USING [Concat, Equal, Fetch, Find, Flatten, FromProc, Index, Length, Match, ROPE, Run, Size, SkipTo, Substr], UserCredentials USING [Get], VersionMap USING [FillInShortNames, Map, MapEntry, MapList, MapRep, MyStamp, Range, RangeList, RangeToEntry, RestoreMapFromFile, SaveMapToFile, ShortNameToRanges, VersionToName], ViewerIO USING [CreateViewerStreams]; VersionMapFromDFImpl: CEDAR MONITOR LOCKS myData USING myData: MyData IMPORTS BasicTime, Commander, DefaultRemoteNames, DFUtilities, FS, FSBackdoor, GenerateDFClosure, IFSFile, IO, MessagesOut, PriorityQueue, Process, ProcessExtras, Rope, UserCredentials, VersionMap, ViewerIO SHARES IO, VersionMap = BEGIN <> BCD: TYPE = BcdDefs.BCD; bytesPerWord: NAT = Basics.bytesPerWord; Date: TYPE = DFUtilities.Date; LORA: TYPE = LIST OF REF ANY; PQ: TYPE = PriorityQueue.Ref; GMT: TYPE = BasicTime.GMT; Map: TYPE = VersionMap.Map; MapList: TYPE = VersionMap.MapList; MapEntry: TYPE = VersionMap.MapEntry; MapRep: TYPE = VersionMap.MapRep; MyStamp: TYPE = VersionMap.MyStamp; NullStamp: MyStamp = LOOPHOLE[NullVersion]; MyStampAsHex: TYPE = PACKED ARRAY [0..12) OF [0..16); ROPE: TYPE = Rope.ROPE; RopeList: TYPE = LIST OF ROPE; STREAM: TYPE = IO.STREAM; VersionStamp: TYPE = BcdDefs.VersionStamp; NullVersion: VersionStamp = BcdDefs.NullVersion; FileEntry: TYPE = REF FileEntryRep; FileEntryRep: TYPE = RECORD [ name: ROPE, date: Date, version: VersionStamp, from: ROPE]; NameSeq: TYPE = REF NameSeqRep; NameSeqRep: TYPE = RECORD [ SEQUENCE len: NAT OF NameEntry]; NameEntry: TYPE = RECORD [hasPrefix: BOOL, name: ROPE]; MyData: TYPE = REF MyDataRep; MyDataRep: TYPE = MONITORED RECORD [ sourceQueue: PQ _ NIL, objectQueue: PQ _ NIL, objectFiles,sourceFiles: INT _ 0, oldObjectMap: MapList _ NIL, oldSourceMap: MapList _ NIL, prefixList: RopeList _ NIL, warningMatch: ROPE _ NIL, errs: STREAM _ NIL, remoteHandle: IFSFile.FSInstance _ NIL, remoteHandleServer: ROPE _ NIL, remoteHandleReleased: CONDITION, which: {source, object, both} _ both, checkRemote: BOOL _ TRUE, remoteHandleOwned: NAT _ 0, abortRequested: BOOL _ FALSE ]; <> pauseForServerGlitch: [0..3600] _ 20; -- seconds to pause if server busy triesForServerGlitch: NAT _ 20; -- times to retry if server busy <> <<>> EachFile: GenerateDFClosure.ActionProc = { <<[data: REF, kind: {file, notFound, syntaxError}, name: ROPE, date: Date, from: ROPE]>> myData: MyData _ NARROW[data]; CheckAbort[myData]; SELECT kind FROM file => { needsVersion: BOOL _ FALSE; isBcd: BOOL _ FALSE; entry: FileEntry _ NEW[FileEntryRep _ [ name: name, date: date, version: NullVersion, from: from]]; triesLeft: NAT _ triesForServerGlitch; IF Rope.Match[myData.warningMatch, name, FALSE] THEN MessagesOut.PutRopes[myData.errs, "Warning match\n for ", name, "\n from ", from]; IF Rope.Match["*!*", name] THEN isBcd _ Rope.Match["*.symbols!*", name, FALSE] OR Rope.Match["*.bcd!*", name, FALSE] ELSE isBcd _ Rope.Match["*.symbols", name, FALSE] OR Rope.Match["*.bcd", name, FALSE]; IF NOT Rope.Match["[]*", name] THEN { <> pos: INT _ Rope.Find[name, ">"]; prefix: ROPE _ Rope.Flatten[name, 0, pos+1]; lag: RopeList _ NIL; FOR each: RopeList _ myData.prefixList, each.rest WHILE each # NIL DO IF Rope.Equal[prefix, each.first, FALSE] THEN GO TO found; lag _ each; ENDLOOP; IF lag = NIL THEN myData.prefixList _ LIST[prefix] ELSE lag.rest _ LIST[prefix]; EXITS found => {}; }; DO ENABLE FS.Error => { SELECT error.code FROM $serverInaccessible => { MessagesOut.PutRopes[myData.errs, "Server glitch: ", name]; Process.Pause[Process.SecondsToTicks[pauseForServerGlitch]]; IF (triesLeft _ triesLeft - 1) # 0 THEN LOOP; }; ENDCASE; MessagesOut.PutRopes[ myData.errs, "File not found: ", name, IO.PutFR["\n from: %g\n reason: %g\n", [rope[from]], [rope[error.explanation]]]]; IF error.group # bug THEN EXIT ELSE REJECT; }; IF isBcd THEN SELECT myData.which FROM object,both => FillInObjectVersion[myData, entry, myData.checkRemote]; ENDCASE ELSE SELECT myData.which FROM source,both => FillInSourceVersion[myData, entry, myData.checkRemote]; ENDCASE; EXIT; ENDLOOP; }; ENDCASE; }; FillInSourceVersion: PROC [myData: MyData, entry: FileEntry, checkRemote: BOOL _ TRUE] = { created: BasicTime.GMT _ entry.date.gmt; initName: ROPE _ entry.name; full: ROPE _ initName; attached: ROPE _ NIL; version: VersionStamp; useFileSystem: BOOL _ FALSE; IF entry.date.format = explicit AND created # BasicTime.nullGMT THEN { <> version _ [0, 0, BasicTime.ToPupTime[created]]; IF checkRemote THEN { <> IF myData.oldSourceMap = NIL THEN useFileSystem _ TRUE ELSE { <> fromMap: ROPE _ VersionMap.VersionToName[myData.oldSourceMap, version].name; len: INT _ fromMap.Length[]; bang: INT _ ScanName[fromMap].bang; SELECT Rope.Run[fromMap, 0, full, 0, FALSE] FROM 0, < bang => useFileSystem _ TRUE; ENDCASE => full _ fromMap; }; }; } ELSE { <> useFileSystem _ TRUE; created _ BasicTime.nullGMT; checkRemote _ TRUE; }; <<>> <> IF useFileSystem THEN { IF created = BasicTime.nullGMT THEN full _ DFUtilities.RemoveVersionNumber[full]; [created: created, fullFName: full, attachedTo: attached] _ FS.FileInfo[ name: full, wantedCreatedTime: created, remoteCheck: checkRemote]; version _ [0, 0, BasicTime.ToPupTime[created]]; }; <<>> <> entry.date _ [format: explicit, gmt: created]; entry.version _ version; IF attached # NIL THEN entry.name _ attached ELSE entry.name _ full; IF Rope.Length[entry.name] = 0 THEN { <> MessagesOut.PutRopes[ myData.errs, "Warning, failed to get source version for ", initName]; } ELSE { <> PriorityQueue.Insert[myData.sourceQueue, entry]; myData.sourceFiles _ myData.sourceFiles + 1; }; }; FillInObjectVersion: PROC [myData: MyData, entry: FileEntry, checkRemote: BOOL _ TRUE] = { <> outerCreated: BasicTime.GMT _ entry.date.gmt; full: ROPE _ entry.name; attached: ROPE _ NIL; valid: BOOL _ FALSE; -- indicates validity of version stamp IF entry.date.format # explicit THEN { outerCreated _ BasicTime.nullGMT; full _ DFUtilities.RemoveVersionNumber[full]; }; <> [created: outerCreated, fullFName: full, attachedTo: attached] _ FS.FileInfo[ name: full, wantedCreatedTime: outerCreated, remoteCheck: checkRemote]; entry.date _ [format: explicit, gmt: outerCreated]; IF attached # NIL THEN full _ attached; entry.name _ full; [valid, entry.version] _ FindShortObjectName[myData, full]; IF NOT valid THEN { <> cacheChecker: FSBackdoor.InfoProc = { <<[fullGName: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL]>> <> IF outerCreated = created AND bytes > 0 THEN { full _ fullGName; inCache _ TRUE; RETURN [FALSE]; }; RETURN [TRUE]; }; inCache: BOOL _ FALSE; FSBackdoor.EnumerateCacheForInfo[cacheChecker, NIL, full]; IF inCache THEN { <> file: FS.OpenFile _ FS.Open[ name: full, lock: read, wantedCreatedTime: outerCreated, remoteCheck: FALSE]; stream: STREAM _ FS.StreamFromOpenFile[ openFile: file, streamBufferParms: FS.minimumStreamBufferParms]; TRUSTED { ENABLE UNWIND => IO.Close[stream]; versionOffset: NAT = bytesPerWord*SIZE[CARDINAL]; versionBytes: NAT = bytesPerWord*SIZE[VersionStamp]; IO.SetIndex[stream, versionOffset]; [] _ IO.UnsafeGetBlock[ stream, [LOOPHOLE[@entry.version], 0, versionBytes]]; }; IO.Close[stream]; } ELSE { <> serverPos: INT = Rope.SkipTo[full, 1, "]"]; server: ROPE = Rope.Flatten[full, 1, serverPos-1]; rest: ROPE = Rope.Flatten[full, serverPos+1]; IF AcquireRemoteHandle[myData, server] THEN { {ENABLE UNWIND => ReleaseRemoteHandle[myData]; [valid, entry.version] _ VersionStampFromRemoteHandle[ myData, server, rest, outerCreated]; }; ReleaseRemoteHandle[myData]; IF NOT valid THEN { <> MessagesOut.PutRopes[myData.errs, "File not found: ", full]; RETURN; }; } ELSE { <> RETURN; }; }; }; PriorityQueue.Insert[myData.objectQueue, entry]; myData.objectFiles _ myData.objectFiles + 1; }; EntrySortPred: PriorityQueue.SortPred = TRUSTED { <<[x: Item, y: Item, data: REF _ NIL] RETURNS [BOOL]>> xx: MyStamp = LOOPHOLE[LOOPHOLE[x, FileEntry].version]; yy: MyStamp = LOOPHOLE[LOOPHOLE[y, FileEntry].version]; IF xx.num # yy.num THEN RETURN [xx.num < yy.num]; IF xx.hi # yy.hi THEN RETURN [xx.hi < yy.hi]; RETURN [xx.lo < yy.lo]; }; VersionSortPred: PROC [xx,yy: MyStamp] RETURNS [BOOL] = TRUSTED { IF xx.num # yy.num THEN RETURN [xx.num < yy.num]; IF xx.hi # yy.hi THEN RETURN [xx.hi < yy.hi]; RETURN [xx.lo < yy.lo]; }; VersionMapFromPQ: PROC [pq: PQ, prefix: ROPE, myData: MyData] RETURNS [map: Map] = { currentName: ROPE _ prefix _ Rope.Flatten[prefix]; prefixLen: NAT = Rope.Size[prefix]; pos: INT _ prefixLen+1; entries: NAT = PriorityQueue.Size[pq]; seq: NameSeq _ NEW[NameSeqRep[entries]]; entryIndex: NAT _ 0; subPos: NAT _ 0; subLim: NAT _ prefixLen; lastPos: INT _ 0; lag: FileEntry _ NIL; getChar: PROC [] RETURNS [c: CHAR] = { IF subPos < subLim THEN { c _ currentName.Fetch[subPos]; subPos _ subPos + 1; RETURN; }; c _ '\n; IF entryIndex < entries THEN { nameEntry: NameEntry _ seq[entryIndex]; currentName _ nameEntry.name; subLim _ Rope.Length[currentName]; IF nameEntry.hasPrefix THEN subPos _ prefixLen ELSE subPos _ 0; entryIndex _ entryIndex + 1; }; }; ProcessExtras.CheckForAbort[]; map _ NEW[MapRep[entries]]; FOR i: NAT IN [0..entries) DO entry: FileEntry = NARROW[PriorityQueue.Remove[pq]]; name: ROPE = entry.name; hasPrefix: BOOL = Rope.Run[name, 0, prefix, 0, FALSE] = prefixLen; seq[i] _ [hasPrefix, name]; map[i] _ [stamp: LOOPHOLE[entry.version], index: pos]; pos _ pos + Rope.Length[name] + 1; IF hasPrefix THEN pos _ pos - prefixLen; IF lag # NIL AND lag.version = entry.version THEN { <> MessagesOut.PutRopes[myData.errs, "Warning, duplicate versions for", IO.PutFR["\n %g\n from: %g", [rope[lag.name]], [rope[lag.from]]], IO.PutFR["\n %g\n from: %g", [rope[entry.name]], [rope[entry.from]]] ]; }; lag _ entry; ENDLOOP; map.names _ Rope.FromProc[pos, getChar, 4040]; VersionMap.FillInShortNames[map]; }; WriteMapToFile: PROC [map: Map, name: ROPE] = { prefix: ROPE _ NIL; st: IO.STREAM _ FS.StreamOpen[name, create]; count: NAT _ map.len; names: ROPE _ map.names; firstCR: INT _ names.Index[0, "\n"]; ProcessExtras.CheckForAbort[]; prefix _ names.Flatten[0, firstCR]; IO.PutRope[st, prefix]; IO.PutRope[st, "\n"]; FOR i: NAT IN [0..map.len) DO <> entry: MapEntry _ map[i]; index: INT _ entry.index; stamp: MyStamp _ entry.stamp; PutStampAsHex[st, stamp]; IO.PutRope[st, " "]; DO c: CHAR _ names.Fetch[index]; index _ index + 1; IO.PutChar[st, c]; IF c = '\n THEN EXIT; ENDLOOP; ENDLOOP; IO.PutRope[st, "\n"]; IO.SetLength[st, IO.GetIndex[st]]; -- force goddamm truncation already!!! IO.Close[st]; }; IndexToShortName: PROC [map: Map, index: INT] RETURNS [ROPE] = { <> names: ROPE _ map.names; end: INT _ names.SkipTo[index, "!\n"]; pos: INT _ end; WHILE pos > index DO SELECT names.Fetch[pos] FROM '/, '], '> => EXIT; ENDCASE; pos _ pos - 1; ENDLOOP; RETURN [names.Substr[pos, end-pos]]; }; PutStampAsHex: PROC [st: IO.STREAM, stamp: MyStamp] = { hex: MyStampAsHex _ LOOPHOLE[stamp]; FOR index: CARDINAL IN [0..12) DO x: CARDINAL [0..15] _ hex[index]; c: CHAR _ IF x IN [0..9] THEN '0 + x ELSE 'A + (x-10); st.PutChar[c]; ENDLOOP; }; ScanName: PROC [name: ROPE] RETURNS [pos,bang,dot: INT] = { len: INT = Rope.Length[name]; pos _ bang _ dot _ len; WHILE pos > 0 DO posM: INT = pos-1; SELECT Rope.Fetch[name, posM] FROM '! => bang _ dot _ posM; '. => dot _ posM; '>, '/, '] => RETURN; ENDCASE; pos _ posM; ENDLOOP; }; CheckAbort: ENTRY PROC [myData: MyData] = { <<... puts out the given ropes to the MessageWindow. This is an entry procedure to keep the message in the MessageWindow consistent.>> ENABLE UNWIND => myData.abortRequested _ TRUE; IF myData.abortRequested THEN RETURN WITH ERROR ABORTED; ProcessExtras.CheckForAbort[]; }; CheckAbortInternal: INTERNAL PROC [myData: MyData] = { <<... puts out the given ropes to the MessageWindow. This is an entry procedure to keep the message in the MessageWindow consistent.>> ENABLE UNWIND => myData.abortRequested _ TRUE; IF myData.abortRequested THEN RETURN WITH ERROR ABORTED; ProcessExtras.CheckForAbort[]; }; <> AcquireRemoteHandle: ENTRY PROC [myData: MyData, server: ROPE] RETURNS [ok: BOOL _ TRUE] = { ENABLE UNWIND => myData.abortRequested _ TRUE; fs: IFSFile.FSInstance _ NIL; problem: IFSFile.Problem _ ok; CheckAbortInternal[myData]; IF myData.remoteHandle # NIL THEN IF NOT Rope.Equal[myData.remoteHandleServer, server, FALSE] THEN TRUSTED { <> WHILE myData.remoteHandleOwned # 0 DO CheckAbortInternal[myData]; WAIT myData.remoteHandleReleased; ENDLOOP; fs _ myData.remoteHandle; myData.remoteHandle _ NIL; IF fs # NIL THEN IFSFile.Logout[fs]; }; IF myData.remoteHandle = NIL THEN TRUSTED { <> userName,password: ROPE; [userName,password] _ UserCredentials.Get[]; fs _ IFSFile.Login[server, userName, password ! IFSFile.UnableToLogin => { why: ROPE _ "Remote access failed for "; SELECT problem FROM credentials => why _ "Invalid credentials for "; io => why _ "Server not found: "; ENDCASE; MessagesOut.PutRopes[myData.errs, why, server]; GO TO notGood; }]; myData.remoteHandle _ fs; myData.remoteHandleServer _ server; }; myData.remoteHandleOwned _ myData.remoteHandleOwned + 1; EXITS notGood => ok _ FALSE; }; NotOwned: ERROR = CODE; ReleaseRemoteHandle: ENTRY PROC [myData: MyData] = { ENABLE UNWIND => myData.abortRequested _ TRUE; IF myData.remoteHandleOwned = 0 THEN RETURN WITH ERROR NotOwned; myData.remoteHandleOwned _ myData.remoteHandleOwned - 1; IF myData.remoteHandleOwned = 0 THEN BROADCAST myData.remoteHandleReleased; CheckAbortInternal[myData]; }; FinalizeRemoteHandle: ENTRY PROC [myData: MyData] = TRUSTED { ENABLE UNWIND => myData.abortRequested _ TRUE; fs: IFSFile.FSInstance _ NIL; WHILE myData.remoteHandleOwned # 0 DO WAIT myData.remoteHandleReleased; ENDLOOP; fs _ myData.remoteHandle; myData.remoteHandle _ NIL; IF fs # NIL THEN IFSFile.Logout[fs]; IFSFile.Finalize[]; CheckAbortInternal[myData]; }; VersionStampFromRemoteHandle: PROC [myData: MyData, server,name: ROPE, created: GMT] RETURNS [valid: BOOL _ FALSE, stamp: VersionStamp] = TRUSTED { ENABLE UNWIND => myData.abortRequested _ TRUE; completed: CONDITION; problem: IFSFile.Problem _ ok; OnCompletion: IFSFile.Completer = TRUSTED { problem _ outcome; NoteCompleted[myData]; }; NoteCompleted: ENTRY PROC [myData: MyData] = TRUSTED { BROADCAST completed; }; WaitForCompleted: ENTRY PROC [myData: MyData] = TRUSTED { WAIT completed; }; bcd: BCD; ifsFile: IFSFile.FileHandle _ NIL; bcd.version _ NullVersion; ProcessExtras.CheckForAbort[]; FOR pause: NAT IN [2..5] DO ifsFile _ IFSFile.Open[myData.remoteHandle, name ! IFSFile.Error => {problem _ reason; CONTINUE}; IFSFile.CantOpen => SELECT reason FROM notFound => GO TO badNews; ENDCASE => {problem _ other; CONTINUE} ]; IF problem = ok THEN EXIT; MessagesOut.PutRopes[myData.errs, "File open glitch: [", server, "]", name]; Process.Pause[Process.SecondsToTicks[pause/2]]; ENDLOOP; IF problem = ok THEN { FOR pause: NAT IN [2..5] DO IFSFile.StartRead[ ifsFile, 0, SIZE[BCD]*bytesPerWord, LOOPHOLE[LONG[@bcd]], OnCompletion, NIL]; WaitForCompleted[myData]; IF problem = ok THEN EXIT; MessagesOut.PutRopes[myData.errs, "File access glitch: [", server, "]", name]; Process.Pause[Process.SecondsToTicks[pause/2]]; ENDLOOP; IFSFile.Close[ifsFile]; valid _ problem = ok; stamp _ bcd.version; }; EXITS badNews => {valid _ FALSE}; }; <> ShortName: PROC [full: ROPE] RETURNS [ROPE] = { pos: INT _ Rope.Length[full]; lim: INT _ pos; WHILE pos > 0 DO c: CHAR = Rope.Fetch[full, pos_pos-1]; SELECT c FROM '! => lim _ pos; '>, '] => {pos _ pos + 1; EXIT}; ENDCASE; ENDLOOP; RETURN [Rope.Flatten[full, pos, lim-pos]]; }; FindShortObjectName: PROC [myData: MyData, full: ROPE] RETURNS [valid: BOOL _ FALSE, stamp: VersionStamp] = { IF myData.oldObjectMap # NIL THEN { short: ROPE = ShortName[full]; rangeList: VersionMap.RangeList _ VersionMap.ShortNameToRanges[myData.oldObjectMap, short]; WHILE rangeList # NIL DO range: VersionMap.Range _ rangeList.first; rangeList _ rangeList.rest; WHILE range.len # 0 DO name: ROPE; stamp: VersionStamp; [name, stamp, range] _ VersionMap.RangeToEntry[range]; IF Rope.Equal[full, name, FALSE] THEN RETURN [TRUE, stamp]; ENDLOOP; ENDLOOP; <> valid _ FALSE; }; }; <
> warningList: RopeList _ LIST["[Indigo]*", "[Ivy]*"]; GenMap: Commander.CommandProc = { <<[cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL]>> ris: STREAM = IO.RIS[cmd.commandLine]; token: ROPE _ "CurrentCedar"; dump: BOOL _ TRUE; dumpDebug: BOOL _ TRUE; namesOnly: BOOL _ FALSE; remoteOpened: BOOL _ FALSE; pos,bang,dot: INT _ 0; inName,sourceName,objectName,outPrefix: ROPE _ NIL; command: ROPE _ cmd.command; forkers: NAT _ 0; results: GenerateDFClosure.ClosureInfo; myData: MyData; sourceMap: Map _ NIL; objectMap: Map _ NIL; checkRemote: BOOL _ TRUE; inLog,outLog: STREAM _ NIL; genMaps: BOOL _ FALSE; -- gen regular version maps if TRUE trustOld: BOOL _ FALSE; -- trust old version maps if TRUE prefix: ROPE _ NIL; -- the first prefix seen oldPath: ROPE _ DefaultRemoteNames.Get[].previous; -- the previous release token _ IO.GetTokenRope[ris, IO.IDProc ! IO.EndOfStream => CONTINUE].token; [pos,bang,dot] _ ScanName[inName _ token]; IF bang = Rope.Size[inName] -- no version stuff AND (bang-dot # 3 OR Rope.Run[inName, dot, ".df", 0, FALSE] # 3) -- no DF extension THEN inName _ Rope.Concat[token, ".df"]; inName _ FS.FileInfo[inName ! FS.Error => IF error.group # bug THEN { IO.PutF[ cmd.out, "\nCan't open %g\n %g\n", [rope[inName]], [rope[error.explanation]]]; GO TO quit; }; ].fullFName; [inLog,outLog] _ ViewerIO.CreateViewerStreams[ "VersionMapBuilder.log", NIL, "VersionMapBuilder.log", FALSE]; [pos,bang,dot] _ ScanName[inName]; outPrefix _ Rope.Flatten[inName, pos, dot-pos]; IO.PutF[outLog, "\nVersion Map Builder started at %g", [time[BasicTime.Now[]]]]; IO.PutF[outLog, "\n\nInput from: %g\n", [rope[inName]]]; sourceName _ Rope.Concat[outPrefix, ".sourceMap"]; objectName _ Rope.Concat[outPrefix, ".symbolsMap"]; TRUSTED {IFSFile.Initialize[]}; {ENABLE UNWIND => { FinalizeRemoteHandle[myData]; }; SELECT cmd.procData.clientData FROM $GenMap => { forkers _ 2; genMaps _ TRUE; }; $MergeMap => { forkers _ 2; trustOld _ genMaps _ TRUE; }; $GenCedarMap => { forkers _ 2; genMaps _ TRUE; outPrefix _ "Cedar"; }; $MergeCedarMap => { forkers _ 2; trustOld _ genMaps _ TRUE; outPrefix _ "Cedar"; }; ENDCASE; myData _ NEW[MyDataRep _ [ sourceQueue: PriorityQueue.Predict[2000, EntrySortPred], objectQueue: PriorityQueue.Predict[1500, EntrySortPred], errs: outLog, checkRemote: checkRemote ]]; SELECT cmd.procData.clientData FROM $GenCedarMap, $MergeCedarMap => myData.warningMatch _ Rope.Concat[oldPath, "*.df*"]; ENDCASE; IF genMaps THEN { sourceName _ Rope.Concat[outPrefix, "Source.VersionMap"]; objectName _ Rope.Concat[outPrefix, "Symbols.VersionMap"]; }; IF trustOld THEN { <> IO.PutRope[outLog, "\nReading old maps."]; myData.oldSourceMap _ LIST[ VersionMap.RestoreMapFromFile[sourceName ! FS.Error => { IO.PutRope[outLog, "\nWarning, can't read "]; IO.PutRope[outLog, sourceName]; CONTINUE}] ]; myData.oldObjectMap _ LIST[ VersionMap.RestoreMapFromFile[objectName ! FS.Error => { IO.PutRope[outLog, "\nWarning, can't read "]; IO.PutRope[outLog, objectName]; GO TO exit}] ]; EXITS exit => {}; }; CheckAbort[myData]; myData.which _ both; IO.PutRope[outLog, "\nGenerating DF closure."]; results _ GenerateDFClosure.GenerateClosureToProc[ inName, outLog, EachFile, myData, [toFork: forkers]]; }; FinalizeRemoteHandle[myData]; IO.PutF[outLog, "\n\n%g DF files, %g source files, %g object files.\n", [integer[results.dfFiles]], [integer[myData.sourceFiles]], [integer[myData.objectFiles]]]; IO.PutRope[outLog, "\nPrefixes seen:"]; FOR each: RopeList _ myData.prefixList, each.rest WHILE each # NIL DO IF prefix = NIL THEN prefix _ each.first; IO.PutF[outLog, "\n %g", [rope[each.first]]]; ENDLOOP; IO.PutRope[outLog, "\n\nMaking short name index for source map."]; sourceMap _ VersionMapFromPQ[myData.sourceQueue, prefix, myData]; CheckAbort[myData]; IO.PutRope[outLog, "\n\nWriting "]; IO.PutRope[outLog, sourceName]; IO.PutRope[outLog, "\n"]; IF genMaps THEN VersionMap.SaveMapToFile[sourceMap, sourceName] ELSE WriteMapToFile[sourceMap, sourceName]; IO.PutRope[outLog, "\nMaking short name index for object map."]; objectMap _ VersionMapFromPQ[myData.objectQueue, prefix, myData]; CheckAbort[myData]; IO.PutRope[outLog, "\n\nWriting "]; IO.PutRope[outLog, objectName]; IO.PutRope[outLog, "\n"]; IF genMaps THEN VersionMap.SaveMapToFile[objectMap, objectName] ELSE WriteMapToFile[objectMap, objectName]; IO.PutF[outLog, "\n\nVersion maps built at %g\n\n", [time[BasicTime.Now[]]]]; IO.Close[inLog]; IO.Close[outLog]; EXITS quit => {}; }; Commander.Register[ "GenMap", GenMap, "Generate version maps", $GenMap]; <> Commander.Register[ "MergeMap", GenMap, "Merge version maps", $MergeMap]; <> Commander.Register[ "GenCedarMap", GenMap, "Generate Cedar version maps", $GenCedarMap]; <> Commander.Register[ "MergeCedarMap", GenMap, "Merge Cedar version maps", $MergeCedarMap]; <> END.