<> <> <> <> <> DIRECTORY BasicTime USING [GMT, nullGMT], DFInternal USING [Client, LocalFileInfo, RemoteFileInfo], DFOperations USING [AbortInteraction, DFInfoInteraction, FileInteraction, InfoClass, InfoInteraction, InteractionProc, YesNoInteraction, YesNoResponse], DFUtilities USING [Date, DateToRope, RemoveVersionNumber], FS USING [ComponentPositions, Error, ErrorDesc, ExpandName, FileInfo], IO USING [PutF, PutFR, rope, STREAM], Process USING [CheckForAbort, Pause, SecondsToTicks, Ticks], Rope USING [Concat, Flatten, Fetch, Length, ROPE]; DFInternalImpl: CEDAR PROGRAM IMPORTS DFUtilities, FS, IO, Process, Rope EXPORTS DFInternal = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; <> <<>> retryInterval: Process.Ticks _ Process.SecondsToTicks[5]; abort: REF DFOperations.AbortInteraction _ NIL; <> <<>> <<>> <> AbortDF: PUBLIC ERROR = CODE; SimpleInteraction: PUBLIC PROC [client: DFInternal.Client, interaction: REF ANY] = { abort: BOOL; message: ROPE; IF client = NIL THEN RETURN; DoLogging[interaction, client.log]; [abort: abort, abortMessageForLog: message] _ client.proc[interaction, client.data]; IF abort THEN { [] _ client.proc[NEW[DFOperations.InfoInteraction _ [class: $abort, message: message]], client.data]; DoAbort[client.log, message]; }; }; YesOrNo: PUBLIC PROC [client: DFInternal.Client, message: ROPE, default: BOOL, blunder: BOOL _ FALSE] RETURNS [choice: BOOL] = { response: REF ANY = DoInteraction[ client, NEW[DFOperations.YesNoInteraction _ [ message: message, blunder: blunder, default: default ]] ]; choice _ default; WITH response SELECT FROM r: REF DFOperations.YesNoResponse => choice _ r^; ENDCASE; }; DoInteraction: PUBLIC PROC [client: DFInternal.Client, interaction: REF ANY] RETURNS [response: REF ANY] = { abort: BOOL; message: ROPE; IF client = NIL THEN RETURN [NIL]; DoLogging[interaction, client.log]; [abort, message, response] _ client.proc[interaction, client.data]; IF abort THEN { [] _ client.proc[NEW[DFOperations.InfoInteraction _ [class: $abort, message: message]], client.data]; DoAbort[client.log, message]; }; }; CheckAbort: PUBLIC PROC [client: DFInternal.Client] = { Process.CheckForAbort[]; SimpleInteraction[client, abort]; }; DoAbort: PUBLIC PROC [log: STREAM, message: ROPE _ NIL, proc: DFOperations.InteractionProc _ NIL, clientData: REF ANY _ NIL] = { interaction: REF ANY = NEW[DFOperations.InfoInteraction _ [class: $abort, message: message]]; IF proc # NIL AND message # NIL THEN [] _ proc[interaction, clientData]; DoLogging[interaction, log]; ERROR AbortDF }; DefaultInteractionProc: PUBLIC DFOperations.InteractionProc -- [interaction: REF ANY] RETURNS [abort: BOOL _ FALSE, abortMessageForLog: ROPE _ NIL, response: REF ANY _ NIL] -- = { WITH interaction SELECT FROM a: REF DFOperations.AbortInteraction => RETURN[abort: a.fromABORTED]; ENDCASE; }; GetFileInfo: PUBLIC PROC [info: REF ANY, notFoundOK: BOOL _ FALSE, remoteCheck: BOOL _ FALSE, client: DFInternal.Client _ NIL, errorLevel: DFOperations.InfoClass _ $error] = { WITH info SELECT FROM local: REF DFInternal.LocalFileInfo => { date: DFUtilities.Date _ []; name: ROPE _ local.name; IF local.date.format # $explicit THEN name _ DFUtilities.RemoveVersionNumber[name]; [fullFName: local.name, attachedTo: local.attachedTo, created: date.gmt, keep: local.keep] _ FS.FileInfo[name: name, remoteCheck: remoteCheck ! FS.Error => SELECT TRUE FROM error.group = $user AND notFoundOK => CONTINUE; RetryFSOperation[error, client] => RETRY; client # NIL => ReportFSError[error, info, client, errorLevel]; ENDCASE ]; IF date.gmt # BasicTime.nullGMT THEN date.format _ $explicit; local.date _ date; }; remote: REF DFInternal.RemoteFileInfo => { date: DFUtilities.Date _ IF remote.date.format = $explicit THEN remote.date ELSE []; uName: ROPE _ DFUtilities.RemoveVersionNumber[remote.name]; gmt: BasicTime.GMT _ BasicTime.nullGMT; <> [fullFName: remote.name, created: gmt] _ FS.FileInfo[name: uName, wantedCreatedTime: date.gmt, remoteCheck: TRUE ! FS.Error => SELECT TRUE FROM error.group = $user AND notFoundOK => CONTINUE; RetryFSOperation[error, client] => RETRY; client # NIL => ReportFSError[error, info, client, errorLevel]; ENDCASE ]; IF gmt # BasicTime.nullGMT THEN <> date.format _ $explicit; date.gmt _ gmt; remote.date _ date; }; ENDCASE => ERROR; }; LocalFile: PUBLIC PROC [file: ROPE] RETURNS [BOOL _ FALSE] = { len: INT _ Rope.Length[file]; IF len > 2 THEN SELECT Rope.Fetch[file, 0] FROM '[, '/ => { SELECT Rope.Fetch[file, 1] FROM '], '/ => RETURN [TRUE]; ENDCASE => RETURN [FALSE]; }; ENDCASE; <> RETURN[FS.ExpandName[file ! FS.Error => CONTINUE].cp.server.length = 0] }; ShortName: PUBLIC PROC [file: ROPE, keepVersion: BOOL _ FALSE] RETURNS [ROPE] = { <> bang: INT _ Rope.Length[file]; pos: INT _ bang; WHILE pos # 0 DO SELECT Rope.Fetch[file, pos _ pos - 1] FROM '! => IF NOT keepVersion THEN bang _ pos; '>, '/, '] => {pos _ pos + 1; EXIT}; ENDCASE; ENDLOOP; RETURN [Rope.Flatten[file, pos, bang-pos]]; }; RetryFSOperation: PUBLIC PROC [error: FS.ErrorDesc, client: DFInternal.Client] RETURNS [retry: BOOL _ FALSE] = { IF error.group # $environment THEN RETURN[FALSE]; retry _ YesOrNo[client: client, message: error.explanation.Concat[". Retry?"], default: TRUE]; SELECT error.code FROM $serverInaccessible, $connectionRejected, $connectionTimedOut => Process.Pause[retryInterval]; ENDCASE; }; ReportFSError: PUBLIC PROC [error: FS.ErrorDesc, info: REF ANY, client: DFInternal.Client, errorLevel: DFOperations.InfoClass _ $error] = { name: ROPE; WITH info SELECT FROM remote: REF DFInternal.RemoteFileInfo => name _ remote.name; local: REF DFInternal.LocalFileInfo => name _ FS.ExpandName[name _ local.name ! FS.Error => CONTINUE].fullFName; ENDCASE => ERROR; SimpleInteraction[ client, NEW[DFOperations.InfoInteraction _ [ class: errorLevel, message: IO.PutFR["%gFS.Error%g: %g", IO.rope[IF error.group = $user THEN NIL ELSE "Unexpected "], IO.rope[ IF error.explanation.Length[] = 0 THEN Rope.Concat[" manipulating ", name] ELSE NIL ], IO.rope[ IF error.explanation.Length[] # 0 THEN error.explanation ELSE "(no explanation)" ] ] ]] ]; IF errorLevel = $abort AND client # NIL THEN DoAbort[client.log]; }; <<>> <> DoLogging: PROC [interaction: REF ANY, log: STREAM] = { IF log = NIL THEN RETURN; WITH interaction SELECT FROM info: REF DFOperations.InfoInteraction => log.PutF["%g%g\N", IO.rope[ SELECT info.class FROM warning => "Warning: ", error => "Error: ", abort => "Abort: ", ENDCASE => NIL ], IO.rope[info.message] ]; info: REF DFOperations.DFInfoInteraction => log.PutF["%g: %g%g\N", IO.rope[ SELECT info.action FROM $start => "Start", $end => "End", $abort => "Abort", ENDCASE => NIL ], IO.rope[info.dfFile], IO.rope[IF info.message = NIL THEN NIL ELSE IO.PutFR[" (%g)", IO.rope[info.message]]] ]; file: REF DFOperations.FileInteraction => { log.PutF["%g %g %g {%g}%g\N", IO.rope[file.localFile], IO.rope[ SELECT file.action FROM $fetch => "<--", $store => "-->", $check => "<-->", ENDCASE => NIL], IO.rope[file.remoteFile], IO.rope[DFUtilities.DateToRope[[$explicit, file.date]]], IO.rope[ IF file.dateFormat = $explicit THEN NIL ELSE IO.PutFR[" ('%g')", SELECT file.dateFormat FROM $greaterThan => [character['>]], $notEqual => [rope["#"]], ENDCASE => [null[]] ] ] ]; }; ENDCASE; }; <> Initialize: PROC = { abort _ NEW[DFOperations.AbortInteraction _ [FALSE]]; }; Initialize[]; END.