ChangePseudoServersImpl.mesa
Copyright Ó 1988, 1991, 1992 by Xerox Corporation. All rights reserved.
Willie-Sue, November 25, 1988 11:57:34 am PST
Willie-s, January 23, 1992 2:19 pm PST
Taken from TrickleChargeSeverImpl
ChangePseudoServers switches dirToChange oldPS newPS
changes all the df files in dirToChange from using oldPS to using newPS.
DIRECTORY
BasicTime USING [GMT, Now, nullGMT],
Commander USING [CommandProc, Handle, Register],
CommanderOps USING [NextArgument],
DFUtilities USING [DateToRope],
FileNames USING [StripVersionNumber],
FS USING [Copy, defaultStreamOptions, EnumerateForInfo, Error, GetInfo, InfoProc, OpenFileFromStream, StreamOpen, StreamOptions],
IO,
Process USING [CheckForAbort],
Rope;
ChangePseudoServersImpl: CEDAR PROGRAM
IMPORTS BasicTime, Commander, CommanderOps, DFUtilities, FileNames, FS, IO, Process, Rope
= BEGIN
Types
GMT: TYPE = BasicTime.GMT;
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
NoDate: SIGNAL[msg: ROPE] = CODE;
PairList: TYPE = LIST OF Pair;
Pair: TYPE = RECORD[oldPS, newPS: ROPE];
FileEntry: TYPE = REF FileEntryRep;
FileEntryRep: TYPE = RECORD [
name: ROPE,
full path name without version
localName: ROPE,
///temp/ChangePS.temp$ plus version number
oldDate: GMT,
date of old df file
newDate: GMT ¬ BasicTime.nullGMT,
date of new df file
state: FileEntryState ¬ init
indicates the state of the file (obvious)
];
FileEntryState: TYPE = {init, fetching, editing, unchanged, changed, done};
Documentation
doc: ROPE = "dirToChange oldPS newPS {oldPS1 newPS1}*
changed oldPS to newPS in df files on dirToChange
";
Example
ChangePseudoServers [NewCedar10.0]<Top> [NewCedar10.0] [Cedar10.0]
All occurrences of [NewCedar10.0] were replaced by [Cedar10.0].
Option variables
maxRetries: NAT ¬ 10;
# of times to retry connectionRejected from STP
retrySeconds: NAT ¬ 20;
# of seconds between retry attemps
Command Procedures
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: REFNIL, msg: ROPENIL]
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];
};
Initialization
Commander.Register[
key: "ChangePseudoServers",
proc: ChangeCommandProc,
doc: doc
];
END.