<> <> <> <> DIRECTORY BasicTime USING [Period], Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Failed, Parse], CopyFromVersionMap, FS USING [Copy, Error, ExpandName], FSBackdoor USING [Entry, EntryPtr, Enumerate, highestVersion, TextRep], IO USING [PutF, PutF1, PutRope, STREAM], Process USING [CheckForAbort], RefText USING [TrustTextAsRope], Rope USING [AppendChars, Concat, Fetch, Flatten, FromRefText, Length, ROPE], UserProfile USING [Token], VersionMap USING [FetchName, GetPrefix, Map, MapEntry, RestoreMapFromFile]; CopyFromVersionMapImpl: CEDAR PROGRAM IMPORTS BasicTime, Commander, CommandTool, FS, FSBackdoor, IO, Process, RefText, Rope, UserProfile, VersionMap EXPORTS CopyFromVersionMap SHARES VersionMap = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Switches: TYPE = PACKED ARRAY CHAR['a..'z] OF BOOL; cedarPrefix: PUBLIC ROPE _ "[Cedar]VersionMap>Cedar"; cedarChestPrefix: PUBLIC ROPE _ "[Cedar]VersionMap>CedarChest"; daToolsPrefix: PUBLIC ROPE _ "[DATools]DAWorldAdministration>DAWorldMap"; CopyCommandProc: Commander.CommandProc = { <<[cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL]>> <> out: STREAM = cmd.out; switches: Switches _ ALL[FALSE]; 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; }; ProcessArgument: PROC [arg: ROPE] = { mapPrefix: ROPE _ arg; Process.CheckForAbort[]; IF mapPrefix = NIL THEN <> SELECT TRUE FROM switches['c] => mapPrefix _ UserProfile.Token["CopyFromVersionMap.CedarChestPrefix", cedarChestPrefix]; switches['d] => mapPrefix _ UserProfile.Token["CopyFromVersionMap.DAToolsPrefix", daToolsPrefix]; switches['r] => mapPrefix _ UserProfile.Token["CopyFromVersionMap.CedarPrefix", cedarPrefix]; switches['u] => mapPrefix _ UserProfile.Token["CopyFromVersionMap.DefaultPrefix"]; ENDCASE; IF mapPrefix = NIL THEN {msg _ "No map prefix seen."; RETURN}; argsProcessed _ argsProcessed + 1; IF switches['w] THEN IO.PutRope[cmd.out, "-- Warnings only, no files to be attached.\n"]; Copy[log: cmd.out, mapPrefix: mapPrefix, verbose: switches['v], doit: NOT switches['w], zapOlder: switches['z]]; }; argsProcessed: NAT _ 0; <<# of arguments processed>> argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd, starExpand: FALSE ! CommandTool.Failed => {msg _ errorMsg; GO TO failed}]; <> ProcessSwitches[UserProfile.Token["CopyFromVersionMap.DefaultSwitches"]]; <> FOR i: NAT IN [1..argv.argc) DO <> arg: ROPE = argv[i]; Process.CheckForAbort[]; <> IF Rope.Length[arg] = 0 THEN LOOP; <> IF Rope.Fetch[arg, 0] = '- THEN { <> ProcessSwitches[arg]; LOOP; }; ProcessArgument[arg ! FS.Error => {msg _ error.explanation; GO TO failed}]; <> ENDLOOP; IF argsProcessed = 0 THEN <> ProcessArgument[NIL ! FS.Error => {msg _ error.explanation; GO TO failed}]; IF argsProcessed = 0 THEN GO TO failed; EXITS failed => {result _ $Failure}; }; Copy: PUBLIC PROC [log: IO.STREAM, mapPrefix: ROPE, verbose: BOOL _ FALSE, doit: BOOL _ TRUE, zapOlder: BOOL _ FALSE] = { EnumerateVersionMap[Rope.Concat[mapPrefix, "Source.VersionMap"], log, verbose, doit, zapOlder]; EnumerateVersionMap[Rope.Concat[mapPrefix, "Symbols.VersionMap"], log, verbose, doit, zapOlder]; }; EnumerateVersionMap: PROC [mapName: ROPE, st: STREAM _ NIL, verbose, doit, zapOlder: BOOL] = { foundFiles: INT _ 0; attachedFiles: INT _ 0; map: VersionMap.Map _ NIL; maxNameLen: NAT = 128; nameText: REF TEXT _ NEW[TEXT[maxNameLen]]; fullNameText: REF TEXT _ NEW[TEXT[maxNameLen]]; mapPrefix: ROPE _ NIL; prefix: ROPE _ FS.ExpandName["$"].fullFName; dstInit: NAT = Rope.Length[prefix]-5; <<(don't count the "[]<>" or the "$")>> nameText.length _ 0; <> fullNameText.length _ 0; <> [] _ Rope.AppendChars[nameText, prefix, 4, dstInit]; <> IO.PutF1[st, "Working on %g ", [rope[mapName]] ]; map _ VersionMap.RestoreMapFromFile[mapName]; IO.PutF1[st, " (files: %g)\n", [integer[map.len]] ]; mapPrefix _ VersionMap.GetPrefix[map]; FOR mapIndex: NAT IN [0..map.len) DO mapEntry: VersionMap.MapEntry = map[mapIndex]; mapVersion: NAT _ 0; inVersion: BOOL _ FALSE; dst: NAT _ dstInit; FOR pos: INT _ mapEntry.index, pos+1 DO c: CHAR _ Rope.Fetch[map.names, pos]; SELECT c FROM '/, '> => {dst _ dstInit; LOOP}; '! => {inVersion _ TRUE; LOOP}; '\n => EXIT; ENDCASE; SELECT TRUE FROM inVersion => IF c IN ['0..'9] AND mapVersion <= (LAST[NAT]-9)/10 THEN { mapVersion _ mapVersion*10 + (c-'0); LOOP; }; dst < maxNameLen => {nameText[dst] _ c; dst _ dst + 1}; ENDCASE; ENDLOOP; nameText.length _ dst; IF dst # dstInit THEN { <> matchProc: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept: BOOL _ FALSE, stop: BOOL _ TRUE] = TRUSTED { WITH entry SELECT FROM attached: LONG POINTER TO attached FSBackdoor.Entry => { IF attached.created = mapEntry.created THEN { <> attachedText: LONG POINTER TO FSBackdoor.TextRep = @entry[attached.attachedTo]; fDst: NAT _ 0; IF NOT zapOlder THEN <> IF BasicTime.Period[from: attached.created, to: mapEntry.created] < 0 THEN { <> found _ dateWarning _ TRUE; RETURN; }; fullNameText.length _ 0; <> IF Rope.Fetch[map.names, mapEntry.index] # '[ THEN { [] _ Rope.AppendChars[fullNameText, mapPrefix]; fDst _ fullNameText.length; }; FOR pos: INT _ mapEntry.index, pos+1 DO c: CHAR _ Rope.Fetch[map.names, pos]; SELECT c FROM '! => IF mapVersion = 0 THEN EXIT; '\n => EXIT; ENDCASE; IF fDst < maxNameLen THEN {fullNameText[fDst] _ c; fDst _ fDst+1}; ENDLOOP; fullNameText.length _ fDst; FOR i: NAT IN [0..fDst) DO IF attachedText[i] # fullNameText[i] THEN RETURN; ENDLOOP; found _ TRUE; }; RETURN; }; ENDCASE; <> IF NOT zapOlder THEN { <> found _ localWarning _ TRUE; RETURN; }; }; found: BOOL _ FALSE; dateWarning: BOOL _ FALSE; localWarning: BOOL _ FALSE; Process.CheckForAbort[]; FSBackdoor.Enumerate[volName: NIL, nameBodyPattern: RefText.TrustTextAsRope[nameText], localOnly: TRUE, allVersions: FALSE, version: FSBackdoor.highestVersion, matchProc: matchProc, acceptProc: NIL]; SELECT TRUE FROM dateWarning => { IO.PutF1[st, "File not attached, local version more recent.\n %g\n", [rope[VersionMap.FetchName[map, mapIndex]]]]; }; localWarning => IO.PutF1[st, "File not attached, unattached local version exists.\n %g\n", [rope[VersionMap.FetchName[map, mapIndex]]]]; found => foundFiles _ foundFiles + 1; (NOT doit) AND NOT verbose => { <> }; ENDCASE => { fullName: ROPE _ VersionMap.FetchName[map, mapIndex]; shortName: ROPE _ Rope.Flatten[Rope.FromRefText[nameText], dstInit]; IF verbose THEN { <> IO.PutF1[st, "%g\n", [rope[fullName]] ]; }; IF doit THEN { [] _ FS.Copy[from: fullName, to: shortName, wantedCreatedTime: mapEntry.created, remoteCheck: FALSE, attach: TRUE]; attachedFiles _ attachedFiles + 1; }; }; }; ENDLOOP; IO.PutF[st, " foundFiles: %g, attachedFiles: %g\n", [integer[foundFiles]], [integer[attachedFiles]] ]; }; doc: ROPE = "copy files from version maps -c: CedarChest prefix default -d: DATools prefix default -n: NCP prefix default -r: Cedar release prefix default -v: verbose (list files to be attached) -w: warning only (no files attached) -z: zap files regardless of date "; Commander.Register[ key: "///Commands/CopyFromVersionMap", proc: CopyCommandProc, doc: doc, clientData: NIL, interpreted: TRUE ]; END. <<>>