DoIt:
PROC [out:
STREAM, dirToChange:
ROPE, changeList: PairList] = {
dfList: LIST OF FileEntry ¬ NIL;
errorsEncountered: BOOL ¬ FALSE;
CheckFile:
PROC [entry: FileEntry] = {
ENABLE FS.Error => GOTO failed;
srcStream: STREAM ¬ NIL;
retriedCount: NAT ¬ 0;
openName: ROPE ¬ NIL;
streamOptions: FS.StreamOptions ¬ FS.defaultStreamOptions;
streamOptions[tiogaRead] ¬
FALSE;
Force the transfers to happen on raw files
Process.CheckForAbort[];
entry.state ¬ fetching;
entry.localName ¬ "/tmp/ChangePS.temp$";
[] ¬ FS.Copy[from: entry.name, to: entry.localName, wantedCreatedTime: entry.oldDate];
entry.state ¬ editing;
CheckForEdit[out, entry, changeList];
IF entry.state = unchanged THEN RETURN;
[] ¬ FS.Copy[from: entry.localName, to: entry.name]; -- should do it all
entry.state ¬ done;
out.PutF1["Changed %g\n", [rope[entry.name]] ];
EXITS failed => { errorsEncountered ¬ TRUE };
};
EachDfFile:
FS.InfoProc = {
[fullFName: ROPE, attachedTo: ROPE, created: GMT, bytes: INT, keep: CARDINAL] RETURNS [continue: BOOL]
dstDate: GMT ¬ BasicTime.nullGMT;
doTheEnumerate: BOOL ¬ FALSE;
this: FileEntry ¬ NEW[FileEntryRep ¬ [name: FileNames.StripVersionNumber[fullFName], oldDate: created ] ];
Process.CheckForAbort[];
dfList ¬ CONS[this, dfList];
numDFFiles ¬ numDFFiles + 1;
continue ¬ TRUE;
};
The mainline of DoIt
filesChanged: INT ¬ 0;
numDFFiles: INT ¬ 0;
out.PutF["Changing df files on %g from using %g to using %g", [rope[dirToChange]], [rope[changeList.first.oldPS]], [rope[changeList.first.newPS]] ];
FOR pL: PairList ¬ changeList.rest, pL.rest
UNTIL pL =
NIL
DO
out.PutF[" & from using %g to using %g", [rope[pL.first.oldPS]], [rope[pL.first.newPS]] ];
ENDLOOP;
out.PutChar['\n] ;
Phase1, build up data base. Don't move any files.
out.PutF1["{Enumerating df Files at %g}\n", [time[BasicTime.Now[]]] ];
FS.EnumerateForInfo[Rope.Concat[dirToChange, "*.df!H"], EachDfFile];
Phase2, move files. Don't change the entries (except for the 'moved' field).
out.PutF1["{Editing & storing files at %g}\n", [time[BasicTime.Now[]]] ];
FOR entryList:
LIST
OF FileEntry ¬ dfList, entryList.rest
WHILE entryList #
NIL
DO
CheckFile[entryList.first];
ENDLOOP;
out.PutF1["{Done at %g}\n", [time[BasicTime.Now[]]] ];
out.PutF1["Files edited and rewritten: %g\n\n", [integer[filesChanged]] ];
};
CheckForEdit:
PROC[out:
STREAM, entry: FileEntry, changeList: PairList] = {
strm: STREAM ¬ FS.StreamOpen[entry.localName, $read];
this: ROPE ¬ strm.GetRope[];
strm.Close[];
entry.state ¬ unchanged;
FOR pL: PairList ¬ changeList, pL.rest
UNTIL pL =
NIL
DO
where: INT ¬ 0;
oldPS: ROPE = pL.first.oldPS;
newPS: ROPE = pL.first.newPS;
oldLen: INT = oldPS.Length[];
newLen: INT ¬ newPS.Length[];
DO
found: INT ¬ Rope.Find[this, pL.first.oldPS, where, FALSE];
IF found = -1 THEN EXIT;
this ¬ Rope.Replace[base: this, start: found, len: oldLen, with: newPS];
where ¬ found + newLen;
entry.state ¬ changed;
ENDLOOP;
ENDLOOP;
IF entry.state = unchanged THEN { this ¬ NIL; RETURN };
BEGIN
dateRope: ROPE = DFUtilities.DateToRope[[format: explicit, gmt: entry.oldDate]];
found: INT ¬ Rope.Find[this, dateRope, 0, FALSE];
IF found = -1 THEN {
out.PutF["\n *** Date %g not found in %g, checking ***\n",
[rope[dateRope]], [rope[entry.name]] ];
entry.state ← unchanged;
SIGNAL NoDate[entry.name];
IF entry.state = unchanged THEN { this ← NIL; RETURN};
};
IF found = -1
THEN {
out.PutF["\n *** Date %g not found in %g, skipping this file ***\n",
[rope[dateRope]], [rope[entry.name]] ];
entry.state ¬ unchanged;
this ¬ NIL;
RETURN;
};
strm ¬ FS.StreamOpen[entry.localName, $create];
entry.newDate ¬ FS.GetInfo[FS.OpenFileFromStream[strm]].created;
IF found # -1 THEN this ¬ Rope.Replace[base: this, start: found, len: dateRope.Length[], with: DFUtilities.DateToRope[[explicit, entry.newDate]] ];
END;
strm.PutRope[this];
strm.Close[];
this ¬ NIL; -- for good measure
};
ShowEntry:
PROC [out:
STREAM, entry: FileEntry] = {
IO.PutF[out, "[name: %g, oldDate: %g, newDate: %g, state: ",
[rope[entry.name]], [time[entry.oldDate]], [time[entry.newDate]] ];
SELECT entry.state
FROM
init => IO.PutRope[out, "init]\n"];
fetching => IO.PutRope[out, "fetching]\n"];
editing => IO.PutRope[out, "editing]\n"];
unchanged => IO.PutRope[out, "unchanged]\n"];
changed => IO.PutRope[out, "changed]\n"];
done => IO.PutRope[out, "done]\n"];
ENDCASE;
};
ChangeCommandProc: Commander.CommandProc = {
[cmd: Handle] RETURNS [result: REF ← NIL, msg: ROPE ← NIL]
CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...]
out: STREAM = cmd.out;
pairList: PairList ¬ NIL;
pairListTail: PairList ¬ NIL;
dirToChange: ROPE ¬ CommanderOps.NextArgument[cmd];
IF dirToChange =
NIL
THEN {
msg ¬ "No dirToChange given.\n";
RETURN;
};
DO
new: PairList;
newPS: ROPE;
oldPS: ROPE ¬ CommanderOps.NextArgument[cmd];
IF oldPS = NIL THEN EXIT;
newPS ¬ CommanderOps.NextArgument[cmd];
IF newPS =
NIL
THEN {
msg ¬ "Unmatched old/newPS pair.\n";
RETURN;
};
new ¬ LIST[[oldPS, newPS]];
IF pairListTail =
NIL
THEN
pairListTail ¬ pairList ¬ new ELSE pairListTail.rest ¬ new;
ENDLOOP;
IF pairList =
NIL
THEN {msg ¬ "No old/newPS pairs given.\n";
RETURN};
DoIt[cmd.out, dirToChange, pairList];
};