DFOperations.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Levin on December 7, 1983 9:16 pm
Russ Atkinson (RRA) February 13, 1985 11:30:20 am PST
DIRECTORY
BasicTime USING [GMT],
IO USING [STREAM],
Rope USING [ROPE];
DFOperations: CEDAR DEFINITIONS = BEGIN OPEN BasicTime, IO, Rope;
This interface defines the major operations on DF files. Lower-level DF facilities appear in the DFUtilities interface.
The procedures in this interface generally have three arguments named 'interact', 'clientData', and 'log', all of which may be defaulted. 'interact', if present, is a procedure used to interact with the client and/or user ('clientData' is passed to it); see the description of these interactions under the definition of 'InteractionProc', below. 'log', if non-NIL, specifies an output stream for recording a text description of the actions taken by the DF operation procedure to which it is passed.
BringOver: PROC [dfFile: ROPE, filter: BringOverFilter ← [], action: BringOverAction ← enter, interact: InteractionProc ← NIL, clientData: REF ANYNIL, log: STREAMNIL] RETURNS [errors, warnings, filesActedUpon: INT];
The behavior of BringOver is most easily described as a three-stage process, although the stages actually occur concurrently.
First, BringOver reads 'dfFile' (which may be either local or remote) and all of the DF files it Includes (in the technical sense) and builds up a list of remote file names and associated creation date specifications.
Second, the specified 'filter' is applied to the list of files, producing a reduced list. The detailed interpretation of the 'filter' parameter appears under the definition of 'BringOverFilter', below.
Third, for each file in the reduced list, a local file name is derived from the remote file name by removing the remote path and version number. This name is then looked up in the local directory. If no such local file can be found, the specified 'action' is applied to the remote file. If a local file exists and the creation date of highest local version differs from the date associated with the remote file, the specified 'action' is applied to the remote file. Otherwise, no action is taken on the given file. The detailed interpretation of the 'action' parameter appears under the definition of 'BringOverAction', below.
The first two return values from BringOver summarize error and warning conditions that have been written to the log (if one was specified). Non-zero values for either of these quantities alert the client to the existence of unusual behavior, even if no log has been written. 'filesActedUpon' is the number of files to which 'action' was actually applied.
BringOverFilter: TYPE = RECORD [
filterA: BringOverFilterA ← $all,
filterB: BringOverFilterB ← $all,
filterC: BringOverFilterC ← $all,
list: LIST OF ROPENIL
];
A BringOverFilter specifies the subset of files that will be entered in the directory with local names. A file is said to "satisfy" the filter (alternatively, the filter "passes" a given file) if the file satisfies all three of the subfilters 'filterA', 'filterB', and 'filterC' and, in addition, either 'list' is NIL or the file appears on 'list'.
BringOverFilterA: TYPE = {source, derived, all};
This subfilter screens files according to the origin of their bits. 'derived' means files whose extensions BringOver recognizes as identifying files produced mechanically from other files. This includes files with extension "bcd", "boot", "press", and "signals". 'source' really means "not derived"; that is, files with no extension or with an extension that BringOver doesn't recognize as 'derived'. 'all' passes all files.
BringOverFilterB: TYPE = {public, private, all};
This subfilter screens files by their interest to a client. 'public' files are those that a client would want to see (i.e., those that the DF file Exports). 'private' files are all others. 'all' passes all files.
BringOverFilterC: TYPE = {defining, imported, all};
This subfilter screens files by the nature of the entry in which they appear. An 'imported' instance is a file that appears in an Imports statement (including the DF file being imported). A 'defining' instance is any other appearance of a file; that is, one that can potentially include a date. 'all' passes all files.
BringOverAction: TYPE = {enter, check, checkAndEnter, fetch};
'enter' means that an attachment will be made in the directory without contacting the file server. 'check' contacts the file server and verifies that the specified remote file actually exists (an error occurs if it doesn't). 'checkAndEnter' combines the previous two, performing the 'enter' portion only if the 'check' portion succeeds. 'fetch' is equivalent to 'checkAndEnter' except that the file is copied rather than attached.
SModel: PROC [ dfFile: ROPE, action: SModelAction ← [], interact: InteractionProc ← NIL, clientData: REF ANYNIL, log: STREAMNIL] RETURNS [errors, warnings, filesActedUpon: INT];
SModel reads 'dfFile' (which is assumed to be a local file) and, for each defining instance (see description "defining instance" under BringOverFilterC, above), considers the created dates of the remote file and a local file with the corresponding short name. If the dates are the same, no action is taken. If the files differ, the local file will be stored at the remote location, creating a new version. (Exception: if the date in the defining instance is specified as ">", the file will be stored only if the local file is newer than the remote one.) The details of this comparison are controlled by 'action.remoteCheck'; see below. If any files are stored, SModel writes a new local version of 'dfFile' with appropriately updated dates. 'dfFile' is permitted to contain a self-reference, which SModel will handle properly; however, defining occurrences for 'dfFile' that occur elsewhere will be incorrect. Note that an "Include" item in the DF file will cause a recursive invocation of SModel for the included DF file.
The first two return values from SModel summarize error and warning conditions that have been written to the log (if one was specified). Non-zero values for either of these quantities alert the client to the existence of unusual behavior, even if no log has been written. 'filesActedUpon' is the number of files to which 'action' was actually applied. (Fine point: the value of 'filesActedUpon' is not affected by 'action.storeChanged'.)
SModelAction: TYPE = RECORD [remoteCheck: BOOLTRUE, storeChanged: BOOLTRUE];
If 'remoteCheck' is TRUE, SModel will determine whether the remote location is up-to-date by comparing the local file's create date with the remote one. If 'remoteCheck' is FALSE, the local file's create date is compared with the date specified in the DF file, which may or may not correspond to an extant file at the remote location.
If 'storeChanged' is TRUE, SModel will copy files to their remote locations as necessary. If 'storeChanged' is FALSE, SModel will update the DF file but will not actually transfer files.
Verify: PROC [ dfFile: ROPE, interact: InteractionProc ← NIL, clientData: REF ANYNIL, log: STREAMNIL] RETURNS [errors, warnings, filesActedUpon: INT];
Verify reads 'dfFile', which may be local or remote, and checks it for completeness and consistency. Each file whose name is preceded by a '+' is treated as the root of a dependency tree and the DF file must contain all files upon which the root files depend. Verify follows "Include" items recursively and produces warnings (but otherwise ignores) "Imports" items that do not contain an explicit "Using" list.
The first two return values from Verify summarize error and warning conditions that have been written to the log (if one was specified). Non-zero values for either of these quantities alert the client to the existence of unusual behavior, even if no log has been written. 'filesActedUpon' is the number of files actually examined during the verification process.
The following procedure (type) is used by many of the DF operations to communicate with the client, which may, in turn, interact with the user, if any.
InteractionProc: TYPE = PROC [interaction: REF ANY, clientData: REF ANY] RETURNS [abort: BOOLFALSE, abortMessageForLog: ROPENIL, response: REF ANYNIL];
An InteractionProc is invoked when the DF operation believes it has information of interest to its client or when the client can reasonably be expected to want to influence the immediate behavior. The particular type of "interaction" indicates the kind of interaction expected; these are described below. 'abort' and 'abortMessageForLog' are normally defaulted; however, if the client wishes to terminate the DF operation, it should set 'abort' to TRUE and optionally supply 'abortMessageForLog', which will be included in a log entry written to the 'log' (if any) specified when the DF operation was invoked. Some interactions expect a response, as described below. Omitting the response (i.e., returning 'response' = NIL) is always legitimate and causes the DF operation to take some default action, as described below for each interaction.
The clientData argument is supplied to the DF operation and is passed to the InteractionProc for the client's convenience.
InfoInteraction: TYPE = RECORD [class: InfoClass, message: ROPE];
'message' conveys a message of possible interest to the user; 'class' indicates its importance. No 'response' is expected.
InfoClass: TYPE = {info, warning, error, abort};
DFInfoInteraction: TYPE = RECORD [action: DFInfoClass, dfFile: ROPE, message: ROPENIL];
Since many DF operations are recursive, the client may wish to structure the feedback to the user according to the recursion depth. A DFInfoInteraction is logically a special case of an InfoInteraction with class = $info; however, it is conveniently structured for the client program. 'action' is described below; 'dfFile' is the name of the DF file to which it applies. Occasionally, 'message' supplies additional information about the 'action'. No 'response' is expected.
DFInfoClass: TYPE = {start, end, abort};
'start' means processing of the DF is beginning; 'end' means it is ending; 'abort' means that processing has terminated prematurely. 'abort' will only be reported for the outermost DF file (i.e., the one passed to the operation procedure). In cases where an operation is aborted, there is no guarantee that 'start's and 'end's will always be paired.
AbortInteraction: TYPE = RECORD [fromABORTED: BOOL];
If an InteractionProc is specified, the DF operation will call it regularly with a REF AbortInteraction to determine if the client wishes to abort. In addition, if ABORTED is raised within the execution of a DF operation, the AbortProc will be called. 'fromABORTED' distinguishes these two cases to the client. No 'response' is expected by the DF operation; the 'abort' Boolean encodes the desired action. Note: if no InteractionProc is specified, the DF operation assumes one that returns 'abort: fromABORTED', which is not quite the same as an InteractionProc that defaults all the return values.
FileInteraction: TYPE = RECORD [
If an InteractionProc is specified, it is called for every file handled by the DF operation. 'localFile' and 'remoteFile' are the local and remote names, respectively, of the file. 'dateFormat' defines the form in which the DF file specified the date, while 'date' is the create time of the file. 'action' specifies what the DF operation is about to do with the file. No `response' is expected.
localFile: ROPE,
remoteFile: ROPE,
dateFormat: FileDateFormat,
date: GMT,
action: FileAction
];
FileAction: TYPE = {fetch, store, check};
FileDateFormat: TYPE = {explicit, greaterThan, notEqual};
ChoiceInteraction: TYPE = RECORD [
'message' is a question for the user. 'choices' is a set of valid responses to the question. 'explanations' is a set of prose explanations (corresponding one-for-one with 'choices'), which are intended to assist the user in understanding the semantics of the choices. The InteractionProc is expected to converse with the user and return the index in the `choices' sequence of the one selected by the user. If no InteractionProc is supplied or if the InteractionProc omits a response, the DF operation behaves as if `default' were chosen. If 'response' is not defaulted (i.e., is non-NIL), it must be a REF ChoiceResponse. Note: if 'blunder' is TRUE, the client may wish to ensure that the human user has a chance to make the choice explicitly, since something fairly serious is (about to go) wrong.
message: ROPE,
blunder: BOOLFALSE,
choices: REF Choices,
explanations: REF Explanations,
default: NAT
];
Choices: TYPE = RECORD [SEQUENCE length: NAT OF ROPE];
Explanations: TYPE = RECORD [SEQUENCE length: NAT OF ROPE];
ChoiceResponse: TYPE = RECORD [choice: NAT];
YesNoInteraction: TYPE = RECORD [
A YesNoInteraction is a special case of a ChoiceInteraction, where only two responses are possible. As in a ChoiceInteraction, 'message' is a question for the user. The InteractionProc is expected to converse with the user and return a Boolean response (yes = TRUE, no = FALSE). If no InteractionProc is supplied or if the InteractionProc omits a response, the DF operation behaves as if `default' were chosen. If 'response' is not defaulted (i.e., is non-NIL), it must be a REF YesNoResponse. Note: if 'blunder' is TRUE, the client may wish to ensure that the human user has a chance to make the choice explicitly, since something fairly serious is (about to go) wrong.
message: ROPE,
blunder: BOOLFALSE,
default: BOOL
];
YesNoResponse: TYPE = RECORD [BOOL];
END.