DIRECTORY
BasicTime, Commander, CommandTool, DFClosure, DFUtilities, FileNames, FS, IO, MessageWindow, ProcessProps, Rope, SystemVersion;
BringEnvironment:
CEDAR
PROGRAM
IMPORTS Commander, CommandTool, DFClosure, DFUtilities, FileNames, FS, IO, MessageWindow, ProcessProps, Rope, SystemVersion
ROPE: TYPE ~ Rope.ROPE;
ROPES: TYPE ~ LIST OF ROPE;
STREAM:
TYPE =
IO.
STREAM;
Switches:
TYPE =
PACKED
ARRAY
CHAR['a..'z]
OF
BOOL;
CmdData: TYPE = REF CmdDataRec; -- for user feedback
CmdDataRec:
TYPE =
RECORD [
out: STREAM,
considered: INT ← 0,
attached: INT ← 0,
wDir: ROPE ← "///Commands/",
switches: Switches ← ALL [FALSE],
failed: BOOL ← FALSE
];
File: DFClosure.FileProc = {
cmdData: CmdData = NARROW [data];
localName: ROPE = DFUtilities.RemoveVersionNumber[name];
serverName: ROPE = Rope.Cat[from, name];
BEGIN
attachedTo: ROPE;
created: BasicTime.GMT;
cmdData.considered ← cmdData.considered + 1;
[attachedTo: attachedTo, created: created] ← FS.FileInfo[name: localName, remoteCheck: FALSE, wDir: cmdData.wDir ! FS.Error => GOTO Copy]; -- if the file is inexistent, we copy it!
IF attachedTo=NIL THEN {cmdData.out.PutF["%g not copied: local version exists.\n", IO.rope[serverName]]; RETURN};
IF created=date.gmt THEN RETURN; -- already there
IF LOOPHOLE [created, INT]>LOOPHOLE [date.gmt, INT] THEN {cmdData.out.PutF["%g not copied: local version is more recent.\n", IO.rope[serverName]]; RETURN};
GOTO Copy;
EXITS
Copy => {
IF cmdData.switches['v] THEN cmdData.out.PutF["Attaching %g.\n", IO.rope[serverName]];
IF cmdData.switches['w]
THEN cmdData.out.PutF["%g not attached.\n", IO.rope[serverName]]
ELSE {
[] ←
FS.Copy[
to: localName, from: serverName, wantedCreatedTime: date.gmt, attach: TRUE, wDir: cmdData.wDir
! FS.Error => cmdData.out.PutF["%g can not be copied: %g.\n", IO.rope[serverName], IO.rope[error.explanation]];
];
cmdData.attached ← cmdData.attached + 1;
};
};
END;
};
cedarTop: ROPE = IO.PutFR["/Cedar/Cedar%g.%g/Top/*.df", IO.int[SystemVersion.release.major], IO.int[SystemVersion.release.minor]];
environmentDF:
ROPE =
IO.PutFR["/Cedar/CedarChest%g.%g/Top/Environment.df",
IO.int[SystemVersion.release.major],
IO.int[SystemVersion.release.minor]];
Import: DFClosure.ImportProc = {
cmdData: CmdData = NARROW [data];
dfName ← FileNames.ConvertToSlashFormat[dfName];
RETURN [
SELECT
TRUE
FROM
NOT cmdData.switches['c] AND Rope.Match[cedarTop, dfName, FALSE] => none, -- those are already running
ENDCASE => public];
};
Error: DFClosure.ErrorProc = {
cmdData: CmdData = NARROW [data];
cmdData.out.PutF[message];
cmdData.failed ← kind=aborted;
};
Message: DFClosure.MessageProc = {MessageWindow.Append[message,
TRUE]};
BringEnvironment: Commander.CommandProc = {
out: STREAM = NARROW [ProcessProps.GetProp[$CommanderHandle], Commander.Handle].out;
cmdData: CmdData = NEW [CmdDataRec ← [out: out]];
localDir: BOOL ← FALSE;
argv: CommandTool.ArgumentVector ← CommandTool.Parse[cmd: cmd, starExpand:
FALSE
! CommandTool.Failed => {msg ← errorMsg; GO TO failed}];
FOR i:
NAT
IN [1..argv.argc)
DO
sense: BOOL ← TRUE;
arg: ROPE = argv[i];
IF Rope.Length[arg] = 0 THEN LOOP;
IF localDir THEN {localDir ← FALSE; LOOP};
IF Rope.Fetch[arg, 0] # '- THEN {msg ← "Incorrect Syntax"; GO TO failed};
FOR index:
INT
IN [0..Rope.Length[arg])
DO
char: CHAR ← Rope.Fetch[arg, index];
SELECT char
FROM
'- => LOOP;
'~ => {sense ← NOT sense; LOOP};
'd, 'D =>
IF i=argv.argc-1
THEN {msg ← "Local Directory expected"; GO TO failed}
ELSE {localDir ← cmdData.switches['d] ← TRUE; cmdData.wDir ← argv[i+1]};
IN ['a..'z] => cmdData.switches[char] ← sense;
IN ['A..'Z] => cmdData.switches[char + ('a-'A)] ← sense;
ENDCASE => {msg ← "Incorrect Syntax"; GO TO failed};
sense ← TRUE;
ENDLOOP;
ENDLOOP;
[] ← DFClosure.EnumerateClosure[environmentDF, FALSE, File, Import, Error, Message, cmdData];
IF cmdData.failed
THEN result ← $Failure
ELSE {
MessageWindow.Append["BringEnvironment done!", TRUE];
out.PutF["BringEnvironment: %g files considered, %g files attached.\n", IO.int[cmdData.considered], IO.int[cmdData.attached]];
};
EXITS
failed => {result ← $Failure};
};
doc:
ROPE = "Brings Environment.df in ///Commands/
-c: also bring public part of Cedar imports
-d: next argument specifies local dir (instead of ///Commands/)
-v: verbose (list files to be attached)
-w: warning only (no files attached)
";
Commander.Register["BringEnvironment", BringEnvironment, doc];