DIRECTORY Basics, BasicTime USING [GMT, Now, nullGMT, ToNSTime], CedarProcess, Commander USING [CommandProc, Handle, Register], CommanderOps, DFUtilities USING [Date, RemoveVersionNumber], FS, GenerateDFClosure USING [ActionProc, ClosureInfo, GenerateClosureToProc], GenMapIO USING [CreateOutputStreams, CloseTeeStream, PutRopes], IO, MobDefs, PFS, Process USING [CheckForAbort, Pause, SecondsToTicks], Rope, SystemNames USING [CedarDir], VersionMap, VersionMapBuilding, VersionMapClassify; VersionMapFromDFImpl: CEDAR MONITOR LOCKS myData USING myData: MyData IMPORTS BasicTime, CedarProcess, Commander, CommanderOps, DFUtilities, FS, GenerateDFClosure, GenMapIO, IO, PFS, Process, Rope, SystemNames, VersionMap, VersionMapBuilding, VersionMapClassify SHARES IO, VersionMap = BEGIN Date: TYPE = DFUtilities.Date; LORA: TYPE = LIST OF REF ANY; 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 = VersionMap.nullStamp; MyStampAsHex: TYPE = PACKED ARRAY [0..2*BYTES[MyStamp]) OF [0..16); ROPE: TYPE = Rope.ROPE; RopeList: TYPE = LIST OF ROPE; STREAM: TYPE = IO.STREAM; VersionStamp: TYPE = VersionMap.VersionStamp; NullVersion: VersionStamp = VersionMapClassify.NullVersion; BadVersion: VersionStamp = VersionMapClassify.BadVersion; 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]; WhichMap: TYPE ~ VersionMapClassify.KindSet; WhichMapData: TYPE = RECORD[ muc: VersionMapBuilding.MapUnderConstruction ฌ NIL, numFiles, numOld: INT ฌ 0, mapName: PFS.PATH, oldMap: MapList ฌ NIL]; WhichMapArray: TYPE = ARRAY WhichMap OF WhichMapData; MyData: TYPE = REF MyDataRep; MyDataRep: TYPE = MONITORED RECORD [ mapData: WhichMapArray ฌ ALL[], prefixList: RopeList ฌ NIL, warningMatch: ROPE ฌ NIL, errs: STREAM ฌ NIL, totalFiles, totalOld: INT ฌ 0, checkRemote: BOOL ฌ TRUE, abortRequested, mobStamps: BOOL ฌ FALSE ]; pauseForServerGlitch: [0..3600] ฌ 90; -- seconds to pause if server busy triesForServerGlitch: NAT ฌ 12; -- times to retry if server busy forkers: NAT ฌ 2; -- # of processes to fork veryVerbose: BOOL ฌ FALSE; outLog: IO.STREAM ฌ NIL; pacifyPeriod: INTEGER ฌ 250; EachFile: GenerateDFClosure.ActionProc = { myData: MyData ฌ NARROW[data]; which: WhichMap ฌ unknown; CheckAbort[myData]; SELECT kind FROM file => { needsVersion: BOOL ฌ FALSE; entry: FileEntryRep ฌ [ name: name, date: date, version: NullVersion, from: from]; triesLeft: NAT ฌ triesForServerGlitch; which ฌ unknown; IF Rope.Match[myData.warningMatch, name, FALSE] THEN GenMapIO.PutRopes[myData.errs, "Warning match\n for ", name, "\n from ", from]; which ฌ VersionMapClassify.Classify[name]; 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 => { GenMapIO.PutRopes[myData.errs, "Server glitch: ", name]; Process.Pause[Process.SecondsToTicks[pauseForServerGlitch]]; IF (triesLeft ฌ triesLeft - 1) # 0 THEN LOOP; }; ENDCASE; GenMapIO.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 myData.mobStamps THEN SELECT which FROM unknown, source => FillInSourceVersion[which, myData, entry, myData.checkRemote]; intermediate, sparc, sparcOpt => FillInObjectVersion[which, myData, entry, myData.checkRemote]; ENDCASE => ERROR ELSE FillInSourceVersion[which, myData, entry, myData.checkRemote]; EXIT; ENDLOOP; }; ENDCASE; }; FillInSourceVersion: PROC [which: WhichMap, myData: MyData, entry: FileEntryRep, 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 ฌ CreatedToMimosaVersionStamp[created]; IF checkRemote THEN { IF myData.mapData[which].oldMap = NIL THEN useFileSystem ฌ TRUE ELSE { valid: BOOL; fromMap: ROPE; [valid, fromMap, ] ฌ VersionMapClassify.MapListLookup[myData.mapData[which].oldMap, full, created, TRUE, FALSE, TRUE]; IF valid THEN full ฌ fromMap ELSE useFileSystem ฌ TRUE; }; }; } 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 ฌ CreatedToMimosaVersionStamp[created]; }; IF attached # NIL THEN entry.name ฌ attached ELSE entry.name ฌ full; IF Rope.Length[entry.name] = 0 THEN { GenMapIO.PutRopes[ myData.errs, "Warning, failed to get source version for ", initName]; } ELSE { myData.mapData[which].muc.AddFile[[entry.name, entry.from, created, version]]; IncCount[which, myData, NOT useFileSystem]; }; }; IncCount: PROC [which: WhichMap, myData: MyData, old: BOOL] ~ { myData.mapData[which].numFiles ฌ myData.mapData[which].numFiles + 1; IF old THEN { myData.mapData[which].numOld ฌ myData.mapData[which].numOld + 1; myData.totalOld ฌ myData.totalOld.SUCC}; IF (myData.totalFiles ฌ myData.totalFiles + 1) MOD pacifyPeriod = 0 THEN GenMapIO.PutRopes[myData.errs, IO.PutFR["%g'th file (%g old) processed at %g.", [integer[myData.totalFiles]], [integer[myData.totalOld]], [time[BasicTime.Now[]]] ]]; RETURN}; FillInObjectVersion: PROC [which: WhichMap, myData: MyData, entry: FileEntryRep, checkRemote: BOOL ฌ TRUE] = { outerCreated: BasicTime.GMT ฌ entry.date.gmt; full: ROPE ฌ entry.name; attached, whyNot, warning: ROPE ฌ NIL; valid: BOOL ฌ FALSE; -- indicates validity of version stamp { SELECT TRUE FROM Rope.SkipTo[full, 0, "!"] = Rope.Length[full] => { valid ฌ FALSE; }; entry.date.format # explicit OR outerCreated = BasicTime.nullGMT => { valid ฌ FALSE; }; myData.mapData[which].oldMap # NIL => { [valid, , entry.version] ฌ VersionMapClassify.MapListLookup[myData.mapData[which].oldMap, full, outerCreated, FALSE, TRUE, FALSE]; IF valid THEN GOTO enter; }; ENDCASE => { valid ฌ FALSE; }; 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] ฌ VersionMapClassify.MapListLookup[myData.mapData[which].oldMap, full, BasicTime.nullGMT, FALSE, FALSE, TRUE]; IF NOT valid THEN [entry.version, whyNot, warning] ฌ VersionMapClassify.ReadVersionStamp[which, full, outerCreated, TRUE]; IF warning#NIL THEN GenMapIO.PutRopes[myData.errs, "Note: ", warning, "."]; IF whyNot#NIL THEN GenMapIO.PutRopes[myData.errs, "Warning: can't read version stamp because ", whyNot, "."]; EXITS enter => valid ฌ valid; }; myData.mapData[which].muc.AddFile[[entry.name, entry.from, entry.date.gmt, entry.version]]; IncCount[which, myData, valid]; RETURN}; VsToMs: PROC [vs: VersionStamp] RETURNS [MyStamp] = { l0: Basics.LongNumber ~ [card[vs[0]]]; l1: Basics.LongNumber ~ [card[vs[1]]]; RETURN [[lo: l1.hi, num: l0.lo, hi: l0.hi, extra: l1.lo]]}; MsToVs: PROC [ms: MyStamp] RETURNS [VersionStamp] = { l0: Basics.LongNumber ~ [pair[lo: ms.num, hi: ms.hi]]; l1: Basics.LongNumber ~ [pair[lo: ms.extra, hi: ms.lo]]; RETURN [[l0.card, l1.card]]}; CreatedToMimosaVersionStamp: PUBLIC PROC [created: BasicTime.GMT] RETURNS [VersionStamp] = { RETURN [[BasicTime.ToNSTime[created], 0]]}; WriteMapToFile: PROC [lm: VersionMapBuilding.LimitedMap, name: ROPE] = { map: Map ~ lm.map; prefix: ROPE ฌ NIL; st: IO.STREAM ฌ FS.StreamOpen[name, create]; count: NAT ฌ lm.limit; names: ROPE ฌ map.names; firstCR: INT ฌ names.Index[0, "\n"]; Process.CheckForAbort[]; prefix ฌ names.Flatten[0, firstCR]; st.PutRope[prefix]; st.PutRope["\n"]; FOR i: NAT IN [0..count) DO entry: MapEntry ฌ map[i]; index: INT ฌ entry.index; stamp: MyStamp ฌ entry.stamp; PutStampAsHex[st, stamp]; st.PutRope[" "]; DO c: CHAR ฌ names.Fetch[index]; index ฌ index + 1; st.PutChar[c]; IF c = '\n THEN EXIT; ENDLOOP; ENDLOOP; st.PutRope["\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..2*BYTES[MyStamp]) 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] = { ENABLE UNWIND => myData.abortRequested ฌ TRUE; IF myData.abortRequested THEN RETURN WITH ERROR ABORTED; Process.CheckForAbort[]; }; CheckAbortInternal: INTERNAL PROC [myData: MyData] = { ENABLE UNWIND => myData.abortRequested ฌ TRUE; IF myData.abortRequested THEN RETURN WITH ERROR ABORTED; Process.CheckForAbort[]; }; hashMark: ROPE = Rope.Cat["@(", "#)mob", "_version ["]; --broken up to avoid spurrious one sourceStampByteLimit: INT ฌ 8000; headerBytes: INT = 4+4*7; -- size of header for .o files textSizeOffset: INT = 4; -- byte offset of text size field in .o files 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]]; }; RopeFromWhich: PROC[which: WhichMap] RETURNS[ROPE] = { RETURN[SELECT which FROM source => "Source", intermediate => "Intermediate", sparc => "SparcExecutable", sparcOpt => "SparcOptExecutable", ENDCASE => "Unknown" ]; }; Quit: ERROR = CODE; GenMap: Commander.CommandProc = { dump: BOOL ฌ TRUE; dumpDebug: BOOL ฌ TRUE; namesOnly: BOOL ฌ FALSE; remoteOpened: BOOL ฌ FALSE; pos, bang, dot: INT ฌ 0; inName, sourceName, derivedName, outPrefix: ROPE ฌ NIL; command: ROPE ฌ cmd.command; results: GenerateDFClosure.ClosureInfo; myData: MyData; newMaps: ARRAY WhichMap OF VersionMapBuilding.LimitedMap ฌ ALL[[NIL,0]]; checkRemote: BOOL ฌ TRUE; 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 ฌ SystemNames.CedarDir[release: previous]; -- the previous release switches: PACKED ARRAY CHAR['a..'z] OF BOOL ฌ ALL[FALSE]; logFileName: ROPE ฌ "VersionMapBuilder.log"; ProcessArgument: PROC = { [pos,bang,dot] ฌ ScanName[inName]; 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[inName, ".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]]]; ERROR Quit; }; ].fullFName; outLog ฌ GenMapIO.CreateOutputStreams[logFileName, IF switches['t] THEN cmd.out ELSE NIL]; [pos,bang,dot] ฌ ScanName[inName]; outPrefix ฌ Rope.Flatten[inName, pos, dot-pos]; outLog.PutF1["\nVersion Maps for Cedar Builder started at %g", [time[BasicTime.Now[]]]]; outLog.PutF1["\n\nInput from: %g\n", [rope[inName]]]; { SELECT cmd.procData.clientData FROM $GenMap => { genMaps ฌ TRUE; }; $GenMapX => { genMaps ฌ TRUE; veryVerbose ฌ TRUE; }; $MergeMap => { trustOld ฌ genMaps ฌ TRUE; }; $GenCedarMap => { genMaps ฌ TRUE; outPrefix ฌ "Cedar"; }; $MergeCedarMap => { trustOld ฌ genMaps ฌ TRUE; outPrefix ฌ "Cedar"; }; ENDCASE; myData ฌ NEW[MyDataRep ฌ [ errs: outLog, checkRemote: checkRemote, mobStamps: switches['l] ]]; IF myData.mobStamps THEN outLog.PutRope["\nExtracting Mimosa-style version stamps, and writing 64-bit-version-format files."] ELSE outLog.PutRope["\nUsing create dates as version stamps, and writing 48-bit-version-format files."]; IF switches['d] THEN outLog.PutRope["\nAllowing duplicates."] ELSE outLog.PutRope["\nSuppressing duplicates."]; FOR i: WhichMap IN [source .. sparcOpt] DO myData.mapData[i].muc ฌ VersionMapBuilding.StartConstruction[2000]; myData.mapData[i].mapName ฌ PFS.PathFromRope[IO.PutFR["%g%g.VersionMap", [rope[outPrefix]], [rope[RopeFromWhich[i]]]] ]; ENDLOOP; SELECT cmd.procData.clientData FROM $GenCedarMap, $MergeCedarMap => myData.warningMatch ฌ Rope.Concat[oldPath, "*.df*"]; ENDCASE; IF trustOld THEN { outLog.PutRope["\nReading old maps."]; FOR i: WhichMap IN [source .. sparcOpt] DO myData.mapData[i].oldMap ฌ LIST[ VersionMap.RestoreMapFromFile[myData.mapData[i].mapName, ! FS.Error => { outLog.PutRope["\nWarning, can't read "]; outLog.PutRope[ PFS.RopeFromPath[myData.mapData[i].mapName] ]; CONTINUE}] ] ENDLOOP; }; CheckAbort[myData]; outLog.PutRope["\nGenerating DF closure."]; results ฌ GenerateDFClosure.GenerateClosureToProc[ inName, outLog, EachFile, myData, [toFork: forkers, followImports: NOT switches['s]]]; }; { outLog.PutF1["\n\n%g DF files", [integer[results.dfFiles]] ]; FOR which: WhichMap IN [source .. sparcOpt] DO num: INT = myData.mapData[which].numFiles; IF num = 0 THEN LOOP; outLog.PutF[", %g %g files (%g from old map)", [integer[num]], [rope[RopeFromWhich[which]]], [integer[myData.mapData[which].numOld]] ]; ENDLOOP; outLog.PutRope["\nPrefixes seen:"]; FOR each: RopeList ฌ myData.prefixList, each.rest WHILE each # NIL DO IF prefix = NIL THEN prefix ฌ each.first; outLog.PutF1["\n %g", [rope[each.first]]]; ENDLOOP; FOR which: WhichMap IN [source .. sparcOpt] DO ReportDuplicate: PROC [a, b: VersionMapBuilding.ConsTuple] ~ { dc: VersionMapBuilding.DifferenceClass ~ VersionMapBuilding.ClassifyDifference[a, b]; IF dc#identicalModExtensionAndCreated THEN IO.PutFL[outLog, "\n%g, duplicate versions for\n %g\n from: %g\n %g\n from: %g", LIST[ [rope[IF dc=identical THEN "Note" ELSE "Warning"]], [rope[a.name]], [rope[a.from]], [rope[b.name]], [rope[b.from]]] ]; RETURN}; thisName: ROPE ~ RopeFromWhich[which]; thisFile: ROPE; IF myData.mapData[which].numFiles = 0 THEN { outLog.PutF1["\n\nWarning: %gMap empty\n", [rope[thisName]] ]; LOOP; }; outLog.PutF1["\n\nMaking short name index for %g map.", [rope[RopeFromWhich[which]]] ]; newMaps[which] ฌ VersionMapBuilding.FinishLimitedConstruction[myData.mapData[which].muc, prefix, ReportDuplicate, NOT switches['d]]; CheckAbort[myData]; thisFile ฌ IO.PutFR["%g%g.VersionMap", [rope[outPrefix]], [rope[thisName]] ]; outLog.PutRope["\n\nWriting "]; outLog.PutRope[thisFile]; outLog.PutRope["\n"]; IF genMaps THEN VersionMapBuilding.LimitedSave[newMaps[which], PFS.PathFromRope[thisFile], switches['l]] ELSE WriteMapToFile[newMaps[which], thisFile]; ENDLOOP; outLog.PutF1["\n\nVersion maps built at %g\n\n", [time[BasicTime.Now[]]]]; IF NOT switches['t] THEN outLog.Close[] ELSE GenMapIO.CloseTeeStream[]; }; }; ProcessSwitches: PROC [arg: ROPE] = { sense: BOOL ฌ TRUE; FOR index: INT IN [0..Rope.Length[arg]) DO char: CHAR ฌ Rope.Fetch[arg, index]; SELECT char FROM '- => LOOP; '~ => {sense ฌ NOT sense; LOOP}; IN ['a..'z] => switches[char] ฌ sense; IN ['A..'Z] => switches[char + ('a-'A)] ฌ sense; ENDCASE; sense ฌ TRUE; ENDLOOP; }; argv: CommanderOps.ArgumentVector ฌ CommanderOps.Parse[cmd: cmd ! CommanderOps.Failed => {msg ฌ errorMsg; GO TO failed}]; veryVerbose ฌ FALSE; FOR i: NAT IN [1..argv.argc) DO arg: ROPE = argv[i]; IF Rope.Length[arg] = 0 THEN LOOP; IF Rope.Fetch[arg, 0] = '- THEN { ProcessSwitches[arg]; LOOP; }; inName ฌ arg; CedarProcess.DoWithPriority[background, ProcessArgument ! Quit, ABORTED => GO TO quit]; ENDLOOP; IF inName = NIL THEN { inName ฌ "Cedar.df"; CedarProcess.DoWithPriority[background, ProcessArgument ! Quit, ABORTED => GO TO quit]; }; EXITS quit => {}; failed => result ฌ $Failed; }; GenMapFromPatterns: Commander.CommandProc = { dump: BOOL ฌ TRUE; dumpDebug: BOOL ฌ TRUE; namesOnly: BOOL ฌ FALSE; remoteOpened: BOOL ฌ FALSE; pos, bang, dot: INT ฌ 0; startName, sourceName, derivedName, outPrefix: ROPE ฌ NIL; command: ROPE ฌ cmd.command; npats: INT ฌ 0; myData: MyData; newMaps: ARRAY WhichMap OF VersionMapBuilding.LimitedMap ฌ ALL[[NIL,0]]; checkRemote: BOOL ฌ TRUE; genMaps: BOOL ฌ TRUE; -- gen regular version maps if TRUE trustOld: BOOL ฌ FALSE; -- trust old version maps if TRUE long: BOOL ฌ FALSE; -- use mob stamps, and write long suppressDuplicates: BOOL ฌ TRUE; toTypescript: BOOL ฌ FALSE; -- output to ts instead of viewer prefix: ROPE ฌ NIL; -- the first prefix seen logFileName: ROPE ฌ "VersionMapBuilder.log"; oldPath: ROPE ฌ SystemNames.CedarDir[release: previous]; -- the previous release recursive: BOOL ฌ FALSE; Setup: PROC = { outLog ฌ GenMapIO.CreateOutputStreams[logFileName, IF toTypescript THEN cmd.out ELSE NIL]; outLog.PutF1["\nVersion Maps for Cedar Builder started at %g", [time[BasicTime.Now[]]]]; myData ฌ NEW[MyDataRep ฌ [ errs: outLog, checkRemote: checkRemote, mobStamps: long ]]; IF myData.mobStamps THEN outLog.PutRope["\nExtracting Mimosa-style version stamps, and writing 64-bit-version-format files."] ELSE outLog.PutRope["\nUsing create dates as version stamps, and writing 48-bit-version-format files."]; IF suppressDuplicates THEN outLog.PutRope["\nSuppressing duplicates."] ELSE outLog.PutRope["\nAllowing duplicates."]; FOR i: WhichMap IN [source .. sparcOpt] DO myData.mapData[i].muc ฌ VersionMapBuilding.StartConstruction[2000]; myData.mapData[i].mapName ฌ PFS.PathFromRope[IO.PutFR["%g%g.VersionMap", [rope[outPrefix]], [rope[RopeFromWhich[i]]]] ]; ENDLOOP; IF trustOld THEN { outLog.PutRope["\nReading old maps."]; FOR i: WhichMap IN [source .. sparcOpt] DO myData.mapData[i].oldMap ฌ LIST[ VersionMap.RestoreMapFromFile[myData.mapData[i].mapName, ! FS.Error => { outLog.PutRope["\nWarning, can't read "]; outLog.PutRope[ PFS.RopeFromPath[myData.mapData[i].mapName] ]; CONTINUE}] ] ENDLOOP; }; }; ProcessArgument: PROC = { DoProcessArgument[startName] }; DoProcessArgument: PROC[inName: ROPE] = { PassInfo: PROC [fullFName, attachedTo: ROPE, created: BasicTime.GMT, bytes: INT, keep: CARDINAL, fileType: FS.FileType] RETURNS [continue: BOOL] --FS.InfoProc-- ~ { CheckAbort[myData]; SELECT TRUE FROM ( fileType = FS.tDirectory ) AND recursive => DoProcessArgument[Rope.Concat[fullFName, ">*"]]; ( bytes>=0 ) => EachFile[myData, file, fullFName, [explicit, created], inName]; ENDCASE; RETURN [TRUE] }; CheckAbort[myData]; outLog.PutF1["\n\nEnumerating %g\n", [rope[inName]]]; FS.EnumerateForInfo[inName, PassInfo !FS.Error => { outLog.PutF["\nFS.Error[%g, %g] while enumerating %g; enumeration aborted.\n", [atom[error.code]], [rope[error.explanation]], [rope[inName]] ]; CONTINUE}]; npats ฌ npats + 1}; WriteResults: PROC = { outLog.PutF1["\n\n%g patterns", [integer[npats]] ]; FOR which: WhichMap IN [source .. sparcOpt] DO num: INT = myData.mapData[which].numFiles; IF num = 0 THEN LOOP; outLog.PutF[", %g %g files (%g from old map)", [integer[num]], [rope[RopeFromWhich[which]]], [integer[myData.mapData[which].numOld]] ]; ENDLOOP; outLog.PutRope["\nPrefixes seen:"]; FOR each: RopeList ฌ myData.prefixList, each.rest WHILE each # NIL DO IF prefix = NIL THEN prefix ฌ each.first; outLog.PutF1["\n %g", [rope[each.first]]]; ENDLOOP; FOR which: WhichMap IN [source .. sparcOpt] DO ReportDuplicate: PROC [a, b: VersionMapBuilding.ConsTuple] ~ { dc: VersionMapBuilding.DifferenceClass ~ VersionMapBuilding.ClassifyDifference[a, b]; IF dc#identicalModExtensionAndCreated THEN IO.PutFL[outLog, "%g, duplicate versions for\n %g\n from: %g\n %g\n from: %g\n", LIST[ [rope[IF dc=identical THEN "Note" ELSE "Warning"]], [rope[a.name]], [rope[a.from]], [rope[b.name]], [rope[b.from]]] ]; RETURN}; thisName: ROPE ~ RopeFromWhich[which]; thisFile: ROPE; IF myData.mapData[which].numFiles = 0 THEN { outLog.PutF1["\n\nWarning: %gMap empty\n", [rope[thisName]] ]; LOOP; }; outLog.PutF1["\n\nMaking short name index for %g map.", [rope[RopeFromWhich[which]]] ]; newMaps[which] ฌ VersionMapBuilding.FinishLimitedConstruction[myData.mapData[which].muc, prefix, ReportDuplicate, suppressDuplicates]; CheckAbort[myData]; thisFile ฌ IO.PutFR["%g%g.VersionMap", [rope[outPrefix]], [rope[thisName]] ]; outLog.PutRope["\n\nWriting "]; outLog.PutRope[thisFile]; outLog.PutRope["\n"]; IF genMaps THEN VersionMapBuilding.LimitedSave[newMaps[which], PFS.PathFromRope[thisFile], long] ELSE WriteMapToFile[newMaps[which], thisFile]; ENDLOOP; outLog.PutF1["\n\nVersion maps built at %g\n\n", [time[BasicTime.Now[]]]]; IF NOT toTypescript THEN outLog.Close[] ELSE GenMapIO.CloseTeeStream[]; }; ProcessSwitches: PROC [arg: ROPE] = { sense: BOOL ฌ TRUE; FOR index: INT IN [0..Rope.Length[arg]) DO char: CHAR ฌ Rope.Fetch[arg, index]; SELECT char FROM '- => LOOP; '~ => {sense ฌ NOT sense; LOOP}; 'd, 'D => suppressDuplicates ฌ NOT sense; 'l, 'L => long ฌ sense; 'm, 'M => trustOld ฌ sense; 'r, 'R => recursive ฌ sense; 't, 'T => toTypescript ฌ sense; 'x, 'X => veryVerbose ฌ sense; ENDCASE; sense ฌ TRUE; ENDLOOP; }; argv: CommanderOps.ArgumentVector ฌ CommanderOps.Parse[cmd: cmd ! CommanderOps.Failed => {msg ฌ errorMsg; GO TO failed}]; committed: BOOL ฌ FALSE; IF argv.argc < 3 THEN RETURN [$Failed, "Usage: GenMapFromPatterns Root (-(d|l|m|t|x)*)* pattern+"]; outPrefix ฌ argv[1]; veryVerbose ฌ FALSE; FOR i: NAT IN [2..argv.argc) DO arg: ROPE = argv[i]; IF Rope.Length[arg] = 0 THEN LOOP; IF Rope.Fetch[arg, 0] = '- THEN { IF committed THEN cmd.err.PutF1["Don't give switches (like %g) after patterns.\n", [rope[arg]]] ELSE ProcessSwitches[arg]; LOOP; }; IF NOT committed THEN { CedarProcess.DoWithPriority[background, Setup ! Quit, ABORTED => GO TO quit]; committed ฌ TRUE; }; startName ฌ arg; CedarProcess.DoWithPriority[background, ProcessArgument ! Quit, ABORTED => GO TO quit]; ENDLOOP; IF committed THEN CedarProcess.DoWithPriority[background, WriteResults ! Quit, ABORTED => GO TO quit] ELSE cmd.err.PutRope["No work to do!\n"]; EXITS quit => {}; failed => result ฌ $Failed; }; ReadVersionStampCommand: PROC [cmd: Commander.Handle] RETURNS [result: REF ANY ฌ NIL, msg: ROPE ฌ NIL] --Commander.CommandProc-- ~ { argv: CommanderOps.ArgumentVector ~ CommanderOps.Parse[cmd]; FOR i: NAT IN (0 .. argv.argc) DO name: ROPE ~ argv[i]; kind: VersionMapClassify.Kind ~ VersionMapClassify.Classify[name]; created: BasicTime.GMT; stamp: VersionStamp; whyNot, warning: ROPE; created ฌ FS.FileInfo[name !FS.Error => {cmd.err.PutF["FS.FileInfo[%g] => FS.Error[%g, %g]\n", [rope[name]], [atom[error.code]], [rope[error.explanation]] ]; LOOP}].created; [stamp, whyNot, warning] ฌ VersionMapClassify.ReadVersionStamp[kind, name, created, FALSE]; IO.PutFL[cmd.out, "ReadVersionStamp[%g] => (%g) %08x%08x", LIST[ [rope[name]], [rope[VersionMapClassify.KindName[kind]]], [cardinal[stamp[0]]], [cardinal[stamp[1]]]] ]; IF whyNot#NIL THEN IO.PutF1[cmd.out, ", whyNot: %g", [rope[whyNot]] ]; IF warning#NIL THEN IO.PutF1[cmd.out, ", warning: %g", [rope[warning]] ]; IO.PutRope[cmd.out, ".\n"]; ENDLOOP; RETURN}; Commander.Register[ "ReadVersionStamp", ReadVersionStampCommand, "reads version stamp from given files"]; Commander.Register[ "GenMap", GenMap, "Generate version maps", $GenMap]; Commander.Register[ "GenMapX", GenMap, "Generate version maps", $GenMapX]; 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]; Commander.Register[ "GenMapFromPatterns", GenMapFromPatterns, "Root (-(d|l|m|r|t|x)*)* pattern+ --- generates version maps from file name patterns"]; END. VersionMapFromDFImpl.mesa Copyright ำ 1984, 1985, 1986, 1987, 1990, 1992 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) June 25, 1985 7:23:40 pm PDT Doug Wyatt, January 26, 1987 2:46:58 pm PST Bill Jackson (bj) August 16, 1988 4:40:15 pm PDT Willie-Sue, February 9, 1990 1:01:47 pm PST Willie-s, March 16, 1992 2:37 pm PST Spreitze, August 17, 1990 2:55 pm PDT Mna, October 25, 1990 4:13 pm PDT Laurie Horton, November 1, 1990 9:53 am PST T Y P E S Global variables Single file processing [data: REF, kind: {file, notFound, syntaxError}, name: ROPE, date: Date, from: ROPE] We need to merge this prefix in with the rest There is an explicit date in the DF file We have been instructed to verify the DF file date, either through the remote server OR through the old source version map. We have been instructed to TRUST the old map (if the file is present). However, to guard against bogus matches for names that have the same versions, we also check the name for agreement up to the version. For a non-explicit date, we can't trust anything. At this point, created = BasicTime.nullGMT if we are supposed to check the remote file server. If this check fails, it is the caller's responsibility to handle the error. At this point, created # BasicTime.nullGMT, and the full name is presumed correct (although attached may take precedence as the 'real' name). So it is time to insert this file entry into the priority queue. I wonder how this happened? Put the entry into the priority queue for later handling Read the version number from the .mob, .c, or .o. Too bad we have to get the whole file (in DCedar) ! How did this happen? Don't trust the version map, we have to look at the server. We have an explicit date with which we can check the existing version map For object files we are not sure whether we can trust the version number, so we MUST ask the file system. We use the resulting full file name as the truth when searching the old object map. As a side effect, the date in the entry is now explicit. Display the entry. Return the name without the prefix or version Routines to use the old maps for verification of names Main command routine [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] Setup the old maps (if any); also make an index for the derived map. When parsing the command line, be prepared for failure. The error is reported to the user Each argument can either be a switch specification or a genuine argument to be processed. The first argument (argv[0]) is not examined, because by convention it is the name of the command as given by the user. Ignore null arguments (it is not easy to generate them, even). This argument sets switches for the remaining patterns. By convention, switches are normally "sticky", in that they stay set until explicitly changed. [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL] Setup the old maps (if any); also make an index for the derived map. When parsing the command line, be prepared for failure. The error is reported to the user Each argument can either be a switch specification or a genuine argument to be processed. The first argument (argv[0]) is not examined, because by convention it is the name of the command as given by the user. Ignore null arguments (it is not easy to generate them, even). This argument sets switches for the remaining patterns. By convention, switches are normally "sticky", in that they stay set until explicitly changed. stores to *Source.VersionMap, *Intermediate.VersionMap, *SparcExecutable.VersionMap , & *SparcOptExecutable.VersionMap stores to *Source.VersionMap, *Intermediate.VersionMap, *SparcExecutable.VersionMap , & *SparcOptExecutable.VersionMap stores to *Source.VersionMap, *Intermediate.VersionMap, *SparcExecutable.VersionMap , & *SparcOptExecutable.VersionMap stores to CedarSource.VersionMap, CedarIntermediate.VersionMap, CedarSparcExecutable.VersionMap, & CedarSparcOptExecutable.VersionMap stores to CedarSource.VersionMap, CedarIntermediate.VersionMap, CedarSparcExecutable.VersionMap, & CedarSparcOptExecutable.VersionMap สz•NewlineDelimiter –(cedarcode) style˜code™Kšœ ฯeœO™ZK™0K™+K™0K™+K™$K™%K™!K™+—K˜šฯk ˜ K˜Kšœ žœžœ˜.Kšœ ˜ Kšœ žœ!˜0K˜ Kšœ žœ˜.Kšžœ˜Kšœžœ2˜IKšœ žœ1˜?Kšžœ˜K˜Kšžœ˜Kšœžœ(˜5Kšœ˜Kšœ žœ ˜Kšœ ˜ K˜K˜K˜—šฯnœžœž˜#Kšžœžœ˜!Kšžœ@žœžœžœP˜ฟKšžœžœ ˜Kšœž˜K˜—šœ ™ K˜Kšœžœ˜Kš žœžœžœžœžœžœ˜Kšžœžœ žœ˜Kšœžœ˜Kšœ žœ˜#Kšœ žœ˜%Kšœžœ˜!šœ žœ˜#KšŸ œ!˜*—Kš œžœžœžœžœ žœ ˜CKšžœžœžœ˜Kš œ žœžœžœžœ˜Kšžœžœžœžœ˜šœžœ˜-KšŸ œ0˜;KšŸ œ/˜9—K˜Kšœ žœžœ˜#šœžœžœ˜Kšœžœ+žœ˜;K˜—Kšœ žœžœ ˜šœ žœžœ˜Kšžœžœžœ ˜ —š œ žœžœ žœžœ˜7K˜—Kšœ žœ˜,šœžœžœ˜Kšœ/žœ˜3Kšœžœ˜Kšœ žœžœ˜Kšœžœ˜—Kšœžœžœ žœ˜5K˜Kšœžœžœ ˜šœ žœž œžœ˜$Kšœžœ˜Kšœžœ˜Kšœžœžœ˜Kšœžœžœ˜Kšœžœ˜Kšœ žœžœ˜Kšœžœž˜'Kšœ˜K˜——šœ™K˜Kšœ&ฯc"˜HKšœžœ  ˜@Kšœ žœ ˜+Kšœ žœžœ˜Kšœžœžœžœ˜Kšœžœ˜K˜—™K™šŸœ"˜*Kšœžœ-žœžœ™TKšœžœ˜K˜Kšœ˜šžœž˜šœ ˜ Kšœžœžœ˜˜Kšœ:˜:—Kšœ žœ˜&K˜šžœ'žœž˜4˜Kšœ2˜2——K˜*K˜šžœžœžœ˜%Kšœ-™-Kšœžœ˜ Kšœžœ ˜,Kšœžœ˜šžœ/žœžœž˜EKš žœ žœžœžœžœ˜:K˜ Kšžœ˜—Kš žœžœžœžœ žœ žœ ˜PKšžœ ˜K˜—šž˜šž˜šžœ ˜ šžœ ž˜šœ˜K˜8Kšœ<˜Kšžœ˜ ———Kšžœ˜—K˜—K˜Kšœ˜Kšœ+˜+˜2KšœCžœ˜V—K˜—˜K˜=šžœžœž˜.Kšœžœ"˜*Kšžœ žœžœ˜Kšœ‡˜‡Kšžœ˜—Kšœ#˜#šžœ/žœžœž˜EKšžœ žœžœ˜)K˜+Kšžœ˜—šžœžœž˜.šŸœžœ)˜>KšœU˜Ušžœ$žœžœ˜;KšœG˜GKšžœžœžœžœP˜|—Kšžœ˜—Kšœ žœ˜&Kšœ žœ˜šžœ$žœ˜,K˜>Kšžœ˜K˜—K˜WKšœržœ˜„Kšœ˜Kšœ žœ@˜MKšœ˜Kšœ˜Kšœ˜šžœ˜ šžœ0žœ&˜]Kšžœ*˜.——Kšžœ˜—K˜JKšžœžœžœžœ˜GK˜—K˜—šŸœžœžœ˜%Kšœžœžœ˜šžœžœžœž˜*Kšœžœ˜$šžœž˜Kšœžœ˜ Kšœžœžœ˜ Kšžœ$˜&Kšžœ.˜0Kšžœ˜—Kšœžœ˜ Kšžœ˜—K˜—•StartOfExpansionI[cmd: Commander.Handle, starExpand: BOOL _ FALSE, switchChar: CHAR]˜?Kšœ*žœžœ ˜9KšœZ™Z—K˜Kšœžœ˜šžœžœžœž˜Kšœา™าKšœžœ ˜šžœžœžœ˜"Kšœ>™>—šžœžœ˜!Kšœ—™—Kšœ˜Kšžœ˜Kšœ˜—K˜ ˜7Kšœžœžœžœ˜—Kšžœ˜K˜—šžœ žœžœ˜K˜˜7Kšœžœžœžœ˜—K˜—šž˜Kšœ ˜ K˜—Kšœ˜K˜—šŸœ˜-Kš œžœ žœžœžœžœ™:Kšœžœžœ˜Kšœ žœžœ˜Kšœ žœžœ˜Kšœžœžœ˜Kšœžœ˜Kšœ/žœžœ˜:Kšœ žœ˜Kšœžœ˜K˜Kš œ žœ žœ!žœžœ˜HKšœ žœžœ˜Kšœ žœžœ #˜:Kšœ žœžœ !˜:Kšœžœžœ !˜6Kšœžœžœ˜ Kšœžœžœ !˜=Kšœžœžœ ˜-Kšœ žœ˜,Kšœ žœ, ˜PKšœ žœžœ˜šŸœžœ˜Kšœ3žœ žœž ˜ZK˜K˜XK˜šœ žœ˜Kšœ ˜ K˜Kšœ˜Kšœ˜K˜—šžœ˜Kšžœe˜iKšžœd˜h—šžœ˜Kšžœ,˜0Kšžœ*˜.—K˜šžœ žœž˜*K˜CKšœžœžœI˜xKšžœ˜—K˜šžœ žœ˜KšœD™DKšœ&˜&šžœ žœž˜*šœžœ˜ šœ8˜8šœžœ ˜Kšœ)˜)Kšœžœ+˜>Kšžœ˜ ———Kšžœ˜—K˜—K˜—K˜KšŸœžœ$˜9šŸœžœ žœ˜)šŸœžœžœžœ žœžœ žœ žœ žœ œ˜คKšœ˜šžœžœž˜Kšœ žœžœ>˜^KšœO˜OKšžœ˜—Kšžœžœ˜ Kšœ˜—Kšœ˜K˜5šžœ$žœ ˜3K˜Kšžœ˜ —K˜—šŸ œžœ˜K˜3šžœžœž˜.Kšœžœ"˜*Kšžœ žœžœ˜Kšœ‡˜‡Kšžœ˜—Kšœ#˜#šžœ/žœžœž˜EKšžœ žœžœ˜)K˜+Kšžœ˜—šžœžœž˜.šŸœžœ)˜>KšœU˜Ušžœ$žœžœ˜;KšœG˜GKšžœžœžœžœP˜|—Kšžœ˜—Kšœ žœ˜&Kšœ žœ˜šžœ$žœ˜,K˜>Kšžœ˜K˜—K˜WK˜†Kšœ˜Kšœ žœ@˜MKšœ˜Kšœ˜Kšœ˜šžœ˜ Kšžœ0žœ˜UKšžœ*˜.—Kšžœ˜—K˜JKšžœžœžœžœ˜GK˜—šŸœžœžœ˜%Kšœžœžœ˜šžœžœžœž˜*Kšœžœ˜$šžœž˜Kšœžœ˜ Kšœžœžœ˜ Kšœžœ˜)K˜K˜K˜K˜K˜Kšžœ˜—Kšœžœ˜ Kšžœ˜—K˜—–I[cmd: Commander.Handle, starExpand: BOOL _ FALSE, switchChar: CHAR]˜?Kšœ*žœžœ ˜9KšœZ™Z—Kšœ žœžœ˜K˜KšžœžœžœH˜dK˜K˜Kšœžœ˜K˜šžœžœžœž˜Kšœา™าKšœžœ ˜šžœžœžœ˜"Kšœ>™>—šžœžœ˜!Kšœ—™—šžœ ˜ KšžœNžœ˜m—Kšžœ˜Kšœ˜—šžœžœ žœ˜šœ-˜-Kšœžœžœžœ˜—Kšœ žœ˜K˜—K˜˜7Kšœžœžœžœ˜—Kšžœ˜K˜—šžœ ˜ šžœ5˜9Kšœžœžœžœ˜—Kšžœ%˜)—K˜šž˜Kšœ ˜ K˜—Kšœ˜K˜—šŸœžœžœ žœžœžœžœžœ œ˜„K˜<šžœžœžœž˜!Kšœžœ ˜KšœB˜BKšœžœ˜Kšœ˜Kšœžœ˜Kšœ žœžœ€žœ ˜ญKšœTžœ˜[Kšžœ9žœi˜จKšžœžœžœžœ1˜FKšžœ žœžœžœ3˜IKšžœ˜Kšžœ˜—Kšžœ˜—K˜šœ˜KšœU˜U—K˜šœ˜K˜4K™v—šœ˜K˜6K™v—šœ˜K˜5K™v—šœ˜K˜DK™…—šœ˜K˜EK™…—K˜šœ˜K˜——K˜Kšžœ˜—…—`VŽะ