MODULE OdDeltavBase;
IMPORT OdVCSBase, OdUtil, OdCond, XMLObjects,
Files, Streams, KernelLog, XML, OdXml, WebHTTP, Dates, Strings;
CONST
DefaultHostName = "127.0.0.1";
VersionMarker = "/hist/";
RepoMount = "";
DefaultRepoPath = "../httproot/dav/repo/";
DefaultWorkspace="../httproot/dav/root/";
DefaultWorkspaceTemp="../httproot/dav/temp/";
VerCh* = '.';
Indent = 9X;
CR = 0DX;
CollCh* = '/'; PropCh* = '_'; ConfCh* = '_';
CONST
MaxVal = 512;
TYPE
VcrList* = OBJECT (OdUtil.Link)
VAR state*,
path*,
version*: OdUtil.Line;
PROCEDURE &vcrList*(p, v: OdUtil.Line);
BEGIN link(); path := p; version := v; END vcrList;
PROCEDURE find(vcr: VcrList): VcrList;
VAR vcrs: VcrList; confA, confB, resA, resB, verA, verB: OdUtil.Line;
BEGIN vcrs := SELF;
WHILE vcrs # NIL DO
confA := ''; splitConfResVer(vcrs.version, confA, resA, verA);
confB := ''; splitConfResVer(vcr.version, confB, resB, verB);
IF resA = resB THEN
RETURN vcrs;
END;
IF vcrs.next # NIL THEN vcrs := vcrs.next(VcrList); ELSE vcrs := NIL; END;
END;
RETURN NIL;
END find;
PROCEDURE show(indent: OdUtil.Line);
VAR vcr: VcrList;
BEGIN vcr := SELF;
LOOP
OdUtil.Msg3(indent, vcr.path, vcr.version);
IF vcr.state = "thawed" THEN OdUtil.Msg1(" thawed"); END;
IF vcr.next = NIL THEN EXIT; ELSE vcr := vcr.next(VcrList); END;
END;
END show;
PROCEDURE xml(host: ARRAY OF CHAR; crRes: OdXml.ConfigurationReportRes; ms: XML.Element);
VAR vcr: VcrList;
BEGIN vcr := SELF;
LOOP
IF crRes IS OdXml.CompareBaselineReportRes THEN
crRes(OdXml.CompareBaselineReportRes).addVcrType(ms, crRes(OdXml.CompareBaselineReportRes).type,
vcr.path, vcr.version);
ELSIF crRes IS OdXml.BaselineReportRes THEN
crRes(OdXml.BaselineReportRes).addVcr(host, ms, vcr.path, vcr.version);
ELSE
crRes.addVcrState(host, ms, vcr.path, vcr.version, vcr.state);
END;
IF vcr.next = NIL THEN EXIT; ELSE vcr := vcr.next(VcrList); END;
END;
END xml;
END VcrList;
VccList* = OBJECT (VcrList)
VAR vcrs*: VcrList;
vccs*:VccList;
PROCEDURE &vccList*(p, v: OdUtil.Line); BEGIN vcrList(p, v); vcrs := NIL; vccs:= NIL; END vccList;
PROCEDURE show0(indent: OdUtil.Line);
VAR vcc: VccList;
BEGIN vcc := SELF;
LOOP
OdUtil.Msg3(indent, vcc.path, vcc.version);
IF vcc.state = "thawed" THEN OdUtil.Msg1(" thawed"); END;
IF vcc.next = NIL THEN EXIT; ELSE vcc := vcc.next(VccList); END;
END;
END show0;
PROCEDURE show*(indent: OdUtil.Line);
VAR vcc: OdUtil.Link;
BEGIN
OdUtil.Msg4(indent, "vcc: ", path, version);
IF state = "thawed" THEN OdUtil.Msg1(" thawed"); END;
Strings.AppendChar(indent, Indent);
IF vcrs # NIL THEN vcrs.show(indent); END;
vcc := vccs;
WHILE vcc # NIL DO
vcc(VccList).show(indent);
vcc := vcc.next;
END;
END show;
PROCEDURE xml*(host: ARRAY OF CHAR; crRes: OdXml.ConfigurationReportRes; ms: XML.Element);
VAR vcc: OdUtil.Link;
BEGIN
IF vcrs # NIL THEN vcrs.xml(host, crRes, ms); END;
vcc := vccs;
WHILE vcc # NIL DO
vcc(VccList).xml(host, crRes, ms);
vcc := vcc.next;
END;
END xml;
END VccList;
VcrDiff* = OBJECT (OdUtil.Link)
VAR pathA*, pathB,
versionA*, versionB: OdUtil.Line;
PROCEDURE &VcrDiffNew*(a, b: VcrList);
BEGIN link();
pathA := a.path; versionA := a.version; pathB := b.path; versionB := b.version;
END VcrDiffNew;
PROCEDURE show(indent: OdUtil.Line);
VAR vcr: VcrDiff;
BEGIN vcr := SELF;
LOOP
OdUtil.Msg6(indent, vcr.pathA, ': ', vcr.versionA, vcr.versionB, CRString);
IF vcr.next = NIL THEN EXIT; ELSE vcr := vcr.next(VcrDiff); END;
END;
END show;
PROCEDURE xml(host: ARRAY OF CHAR; crRes: OdXml.CompareBaselineReportRes; ms: XML.Element);
VAR vcrDiff: VcrDiff;
BEGIN vcrDiff := SELF;
LOOP
crRes.addVcrType(ms, crRes.type, vcrDiff.versionA, vcrDiff.versionB);
IF vcrDiff.next = NIL THEN EXIT; ELSE vcrDiff := vcrDiff.next(VcrDiff); END;
END;
END xml;
END VcrDiff;
VccDiff* = OBJECT (VcrDiff)
VAR addedVcrs, deletedVcrs: VcrList;
changedVcrs: VcrDiff;
addedVccs, deletedVccs: VccList;
changedVccs: VccDiff;
PROCEDURE &VccDiffNew*(old, new: VccList);
CONST PLog = FALSE;
VAR vcrOld, vcrNew, vcrTemp: VcrList; vcrDiff: VcrDiff;
vccOld, vccNew: VccList; vccDiff: VccDiff;
BEGIN
VcrDiffNew(old, new); addedVcrs := NIL; deletedVcrs := NIL; changedVcrs := NIL;
addedVccs := NIL; deletedVccs := NIL; changedVccs := NIL;
vcrOld := old.vcrs;
WHILE vcrOld # NIL DO
IF new.vcrs # NIL THEN
vcrNew := new.vcrs.find(vcrOld);
ELSE
vcrNew := NIL;
END;
IF vcrNew = NIL THEN
IF PLog THEN OdUtil.Msg2("VCR deleted:", vcrOld.path); END;
IF deletedVcrs = NIL THEN NEW(deletedVcrs, vcrOld.path, vcrOld.version);
ELSE NEW(vcrNew, vcrOld.path, vcrOld.version); deletedVcrs.add(vcrNew); END;
ELSE
IF vcrOld.version # vcrNew.version THEN
IF PLog THEN OdUtil.Msg4("VCR changed", vcrOld.path, vcrOld.version, vcrNew.version); END;
IF changedVcrs = NIL THEN NEW(changedVcrs, vcrOld, vcrNew);
ELSE NEW(vcrDiff, vcrOld, vcrNew); changedVcrs.add(vcrDiff); END;
ELSE
IF PLog THEN OdUtil.Msg2("VCR unchanged:", vcrOld.path); END;
END;
END;
IF vcrOld.next # NIL THEN vcrOld := vcrOld.next(VcrList); ELSE vcrOld := NIL; END;
END;
vcrNew := new.vcrs;
WHILE vcrNew # NIL DO
IF old.vcrs # NIL THEN
vcrOld := old.vcrs.find(vcrNew);
ELSE
vcrOld := NIL;
END;
IF vcrOld = NIL THEN
IF PLog THEN OdUtil.Msg2("VCR added;", vcrNew.path); END;
IF addedVcrs = NIL THEN NEW(addedVcrs, vcrNew.path, vcrNew.version);
ELSE NEW(vcrOld, vcrNew.path, vcrNew.version); addedVcrs.add(vcrOld); END;
END;
IF vcrNew.next # NIL THEN vcrNew := vcrNew.next(VcrList); ELSE vcrNew := NIL; END;
END;
vccOld := old.vccs;
WHILE vccOld # NIL DO
IF new.vccs # NIL THEN
vcrTemp := new.vccs.find(vccOld); vccNew := vcrTemp(VccList);
ELSE
vccNew := NIL;
END;
IF vccNew = NIL THEN
IF PLog THEN OdUtil.Msg2("VCC deleted:", vccOld.path); END;
IF deletedVccs = NIL THEN NEW(deletedVccs, vccOld.path, vccOld.version);
ELSE NEW(vccNew, vccOld.path, vccOld.version); deletedVccs.add(vccNew); END;
ELSE
IF vccOld.version # vccNew.version THEN
IF PLog THEN OdUtil.Msg4("VCC changed:", vccOld.path, vccOld.version, vccNew.version); END;
IF changedVccs = NIL THEN NEW(changedVccs, vccOld, vccNew);
ELSE NEW(vccDiff, vccOld, vccNew); changedVccs.add(vccDiff); END;
ELSE
IF PLog THEN OdUtil.Msg2("VCC unchanged:", vccOld.path); END;
END;
END;
IF vccOld.next # NIL THEN vccOld := vccOld.next(VccList); ELSE vccOld := NIL; END;
END;
vccNew := new.vccs;
WHILE vccNew # NIL DO
IF old.vccs # NIL THEN
vcrTemp := old.vccs.find(vccNew); vccOld := vcrTemp(VccList);
ELSE
vccOld := NIL;
END;
IF vccOld = NIL THEN
IF PLog THEN OdUtil.Msg2("VCC added:", vccNew.path); END;
IF addedVccs = NIL THEN NEW(addedVccs, vccNew.path, vccNew.version);
ELSE NEW(vccOld, vccNew.path, vccNew.version); addedVccs.add(vccOld); END;
END;
IF vccNew.next # NIL THEN vccNew := vccNew.next(VccList); ELSE vccNew := NIL; END;
END;
END VccDiffNew;
PROCEDURE show*(indent: OdUtil.Line);
VAR indent1: OdUtil.Line;
BEGIN
OdUtil.Msg6(indent, "", "vccdiff:", pathA, versionA, versionB);
Strings.AppendChar(indent, Indent); indent1 := indent; Strings.AppendChar(indent1, Indent);
IF addedVcrs # NIL THEN OdUtil.Msg3(indent, "", "added VCRs"); addedVcrs.show(indent1); END;
IF deletedVcrs # NIL THEN OdUtil.Msg3(indent, "", "deleted VCRs"); deletedVcrs.show(indent1); END;
IF changedVcrs # NIL THEN OdUtil.Msg3(indent, "", "changed VCRs"); changedVcrs.show(indent1); END;
IF addedVccs # NIL THEN OdUtil.Msg3(indent, "", "added VCCs"); addedVccs.show0(indent1); END;
IF deletedVccs # NIL THEN OdUtil.Msg3(indent, "", "deleted VCCs"); deletedVccs.show0(indent1); END;
IF changedVccs # NIL THEN OdUtil.Msg3(indent, "", "changed VCCs"); changedVccs.show(indent1); END;
END show;
PROCEDURE xml*(host: ARRAY OF CHAR; cbrRes: OdXml.CompareBaselineReportRes; ms: XML.Element);
VAR vcc: OdUtil.Link;
BEGIN
IF addedVcrs # NIL THEN cbrRes.type := "added"; addedVcrs.xml(host, cbrRes, ms); END;
IF deletedVcrs # NIL THEN cbrRes.type := "deleted"; deletedVcrs.xml(host, cbrRes, ms); END;
IF changedVcrs # NIL THEN cbrRes.type := "changed"; changedVcrs.xml(host, cbrRes, ms); END;
END xml;
END VccDiff;
TYPE
Version = OBJECT
VAR next: Version;
PROCEDURE &init*;
BEGIN next := NIL;
END init;
PROCEDURE add * (version: Version);
VAR old: Version;
BEGIN old := SELF;
WHILE old.next # NIL DO old := old.next; END;
old.next := version;
END add;
END Version;
TYPE
VersionProperties * = OBJECT
VAR
fileName, propName: OdUtil.Line; f: Files.File;
propVal: ARRAY MaxVal OF CHAR;
state*, versionHistory*, versionName*, creatorDisplayname*, comment*: OdUtil.Line;
creationDate*, keywords*, versionURL*: OdUtil.Line;
fields: WebHTTP.AdditionalField;
PROCEDURE &init*(conf, res: ARRAY OF CHAR);
CONST PLog = FALSE;
VAR r: Files.Reader;
BEGIN
state := "";
versionHistory := ""; versionName := ""; creatorDisplayname := ""; comment := "";
creationDate := ""; keywords := "f"; state := "";
versionURL := "";
IF (conf = "") & (res = "") THEN RETURN END;
IF isConfiguration(res) THEN
fileName := ConfDataFileName(res); Strings.Append(fileName, PropCh);
ELSIF isConfDataFileName(res) THEN
IF res[0] = '/' THEN
COPY(workMan.prefix, fileName);
unpadConfiguration(fileName);
Strings.Append(fileName, res);
ELSE COPY(res, fileName);
END;
Strings.Append(fileName, PropCh);
ELSE
fileName := ResPropFileName(conf, res);
END;
fields := NIL;
IF PLog THEN OdUtil.Msg6("VP.init:", conf, ":", res, ":", fileName); END;
f := Files.Old(fileName);
IF f # NIL THEN
Files.OpenReader(r, f, 0);
LOOP
r.RawString(propName);
IF r.res # 0 THEN
EXIT;
ELSE
r.RawString(propVal);
IF propName = "state" THEN COPY(propVal, state);
ELSIF propName = "versionHistory" THEN COPY(propVal, versionHistory);
ELSIF propName = "versionName" THEN COPY(propVal, versionName);
ELSIF propName = "creatorDisplayname" THEN COPY(propVal, creatorDisplayname);
ELSIF propName = "comment" THEN COPY(propVal, comment);
ELSIF propName = "creationDate" THEN COPY(propVal, creationDate);
ELSIF propName = "keywords" THEN COPY(propVal, keywords);
ELSE
WebHTTP.SetAdditionalFieldValue(fields, propName, propVal);
END;
versionURL := versionHistory; Strings.Append(versionURL, VerCh); Strings.Append(versionURL, versionName);
END;
END;
END;
END init;
PROCEDURE set*(prop: OdUtil.Line; val: ARRAY OF CHAR);
BEGIN
IF prop = "state" THEN COPY(val, state);
ELSIF prop = "versionHistory" THEN COPY(val, versionHistory);
ELSIF prop = "versionName" THEN COPY(val, versionName);
ELSIF prop = "creatorDisplayname" THEN COPY(val, creatorDisplayname);
ELSIF prop = "comment" THEN COPY(val, comment);
ELSIF prop = "creationDate" THEN COPY(val, creationDate);
ELSIF prop = "keywords" THEN COPY(val, keywords );
ELSE
WebHTTP.SetAdditionalFieldValue(fields, prop, val);
END;
store();
END set;
PROCEDURE get*(prop: OdUtil.Line; VAR val: ARRAY OF CHAR);
VAR ok: BOOLEAN;
BEGIN
IF prop = "state" THEN COPY(state, val);
ELSIF prop = "versionHistory" THEN COPY(versionHistory, val);
ELSIF prop = "versionName" THEN COPY(versionName, val);
ELSIF prop = "creatorDisplayname" THEN COPY(creatorDisplayname, val);
ELSIF prop = "comment" THEN COPY(comment, val);
ELSIF prop = "creationDate" THEN COPY(creationDate, val);
ELSIF prop = "keywords" THEN COPY(keywords, val);
ELSE
ok := WebHTTP.GetAdditionalFieldValue(fields, prop, val);
END;
END get;
PROCEDURE store;
VAR erg: LONGINT; w: Files.Writer; field: WebHTTP.AdditionalField;
PROCEDURE nameVal(name, value: ARRAY OF CHAR );
BEGIN
IF value # '' THEN
w.RawString(name); w.RawString(value);
END;
END nameVal;
BEGIN
f := Files.New(fileName);
IF f # NIL THEN
Files.OpenWriter(w, f, 0);
nameVal("state", state);
nameVal("versionHistory", versionHistory);
nameVal("versionName", versionName);
nameVal("creatorDisplayname", creatorDisplayname);
nameVal("comment", comment);
nameVal("creationDate", creationDate);
nameVal("keywords", keywords );
field := fields;
WHILE field # NIL DO
nameVal(field.key, field.value);
field := field.next;
END;
w.Update;
Files.Register(f);
ELSE
OdUtil.Msg2("VersionProperties.store: error f = NIL, filename =", fileName);
END;
END store;
END VersionProperties;
TYPE
RepositoryManager = OBJECT
VAR
prefix: OdUtil.Line;
PROCEDURE &Init*;
BEGIN
SELF.prefix := OdVCSBase.BaseDir;
END Init;
PROCEDURE newHistory*(res: OdUtil.Line): OdUtil.Line;
CONST PLog = FALSE;
VAR enum: Files.Enumerator;
flags, entryFlags: SET; time, date, size: LONGINT; pattern, last, hist, name, dir, base: OdUtil.Line;
numPos: LONGINT; prefix: OdUtil.Line;
BEGIN
numPos := Strings.Length(prefix);
flags := {}; last := prefix;
IF PLog THEN OdUtil.Msg2("RepMan: resAlt = ", res); END;
IF isConfiguration(res) THEN res := ConfShortDataFileName(res); END;
splitDirBase(res, dir, base);
pattern := prefix; Strings.Append(pattern, '*'); Strings.Append(pattern, base); Strings.Append(pattern, '.VCS');
IF PLog THEN OdUtil.Msg3("RepMan: resNeu,pattern = ", res, pattern); END;
NEW(enum); enum.Open(pattern, flags);
WHILE enum.GetEntry(name, entryFlags, time, date, size) DO
IF (name[numPos] >= '0') & (name[numPos] <= '9') THEN last := name; END;
END;
IF last = prefix THEN
hist := '0'; Strings.Append(hist, base);
ELSE
hist := ' '; hist[0] := CHR(ORD(last[numPos])+1); Strings.Append(hist, base);
END;
IF PLog THEN OdUtil.Msg2("RepMan: hist = ", hist); END;
RETURN hist;
END newHistory;
PROCEDURE repName*(hist: OdUtil.Line): OdUtil.Line;
VAR rep: OdUtil.Line;
BEGIN
rep := prefix;
IF hist[0] = '/' THEN
unpadConfiguration(rep);
END;
Strings.Append(rep, hist);
RETURN rep;
END repName;
END RepositoryManager;
TYPE
WorkspaceManager * = OBJECT
VAR prefix - : ARRAY 128 OF CHAR; TempDir-: ARRAY 8 OF CHAR;
PROCEDURE &Init*(prefix: ARRAY OF CHAR);
BEGIN
SELF.TempDir := "/temp";
COPY(prefix, SELF.prefix);
END Init;
PROCEDURE SetPrefix * (prefix: ARRAY OF CHAR);
BEGIN
COPY(prefix, SELF.prefix);
END SetPrefix;
PROCEDURE prefixLen(): LONGINT;
BEGIN
RETURN Strings.Length(prefix);
END prefixLen;
END WorkspaceManager;
TYPE
Server * = OBJECT
VAR
root: OdUtil.Line;
PROCEDURE &initServer*(root: OdUtil.Line);
BEGIN SELF.root := root; END initServer;
PROCEDURE freezeResource(conf, res, hist: OdUtil.Line; log: OdVCSBase.TLog; flags: SET);
CONST Log = FALSE;
VAR historyName, fileName: OdVCSBase.TFileName; nv: LONGINT; ver, verStr: OdUtil.Line;
BEGIN
ver := ResFileName(conf, res); COPY(ver, fileName);
COPY(root, historyName); Strings.Append(historyName, hist);
IF Log THEN OdUtil.Msg3("DAVDeltavBase.fR:", historyName, fileName); END;
nv := OdVCSBase.Create(historyName, fileName, log, flags);
IF nv > 0 THEN
COPY(fileName, ver); Strings.Append(ver, VerCh);
Strings.IntToStr(nv, verStr);
Strings.Append(ver, verStr);
selectResource(conf, res, hist, ver);
ELSE
preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.InternalServerError, OdVCSBase.errMsg, -1);
END;
END freezeResource;
PROCEDURE freezeInitialResource*(conf, res: OdUtil.Line; log: OdVCSBase.TLog; flags: SET);
CONST PLog = FALSE;
VAR confProps, props: VersionProperties; hist: OdUtil.Line;
BEGIN
preCond := OdCond.Ok;
IF conf # "" THEN
NEW(confProps, "", conf);
IF confProps.state = "frozen" THEN
preCond := OdCond.MustNotUpdateBaselineCollection;
RETURN;
END;
END;
NEW(props, conf, res);
IF props.state # "" THEN
OdUtil.Msg3(conf, res, "resource already under version control");
ELSE
IF PLog THEN OdUtil.Msg2(res, " before newHistory"); END;
hist := repMan.newHistory(res);
freezeResource(conf, res, hist, log, flags);
END;
END freezeInitialResource;
PROCEDURE equalVersion(conf, res, hist, ver: OdUtil.Line): BOOLEAN;
CONST TempBase = "equal";
VAR erg: LONGINT; f1, f2: Files.File; equal: BOOLEAN; resName, resPropName, tempDir: OdUtil.Line;
BEGIN
resName := ResFileName(workMan.TempDir, TempBase);
resPropName := ResPropFileName(workMan.TempDir, TempBase);
COPY(workMan.TempDir, tempDir);
selectResource(tempDir, TempBase, hist, ver);
IF preCond = OdCond.Ok THEN
f1 := Files.Old(ResFileName(conf, res)); f2 := Files.Old(resName);
equal := FileEqual(f1, f2);
Files.Register(f1); Files.Register(f2);
RETURN equal;
ELSE
preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.InternalServerError, OdVCSBase.errMsg, -1);
RETURN FALSE;
END;
END equalVersion;
PROCEDURE freezeOtherResource*(conf, res: OdUtil.Line; log: OdVCSBase.TLog; flags: SET);
CONST PLog = FALSE;
VAR confProps, props: VersionProperties;
BEGIN
NEW(confProps, "", conf);
IF confProps.state = "frozen" THEN
preCond := OdCond.VccMustBeCheckedOut;
RETURN;
END;
NEW(props, conf, res);
IF props.versionHistory = "" THEN
preCond := OdCond.VersionHistoryIsTree;
ELSIF props.state = "frozen" THEN
preCond := OdCond.MustBeCheckedOutVcr;
ELSE
IF PLog THEN OdUtil.Msg5("before equalVersion:", conf, res, props.versionHistory, props.versionURL); END;
IF equalVersion(conf, res, props.versionHistory, props.versionURL) THEN
props.set("state", "frozen");
preCond := OdCond.CheckedOutVersionUnchanged;
ELSE
freezeResource(conf, res, props.versionHistory, log, flags);
END;
END;
END freezeOtherResource;
PROCEDURE deleteFrozenVCRs(conf: OdUtil.Line);
CONST PLog = FALSE;
VAR lines: OdUtil.Lines; erg: LONGINT; resName, resPropName, fileName: OdUtil.Line;
BEGIN
IF PLog THEN OdUtil.Msg2("deleteFrozenVCRs:", conf); END;
lines := findVCRs(conf);
WHILE lines # NIL DO
resName := lines.line;
resPropName := lines.line; Strings.Append(resPropName, PropCh);
IF PLog THEN OdUtil.Msg3("deleteFrozenVCRs:", resName, resPropName); END;
Files.Delete(resName, erg);
Files.Delete(resPropName, erg);
lines := lines.next;
END;
lines := findVCCs(conf);
WHILE lines # NIL DO
IF PLog THEN OdUtil.Msg2("deleting subbaseline", lines.line); END;
deleteFrozenVCRs(lines.line);
fileName := ConfDataFileName(lines.line);
Files.Delete(fileName, erg);
fileName := ConfPropFileName(lines.line);
Files.Delete(fileName, erg);
lines := lines.next;
END;
END deleteFrozenVCRs;
PROCEDURE checkFrozenVCRs(conf: OdUtil.Line; root: BOOLEAN; VAR w: Files.Writer): BOOLEAN;
CONST PLog = FALSE;
VAR allFrozen: BOOLEAN; subconfs, lines: OdUtil.Lines; confLen: LONGINT; res:OdUtil.Line; props: VersionProperties;
BEGIN
IF PLog THEN OdUtil.Msg2("checkFrozenVCRs:", conf); END;
lines := findVCRs(conf);
confLen := Strings.Length(conf);
allFrozen := TRUE;
WHILE lines # NIL DO
splitConfRes(lines.line, conf, res);
IF PLog THEN OdUtil.Msg4("checkFrozenVCRs:", lines.line, conf, res); END;
NEW(props, conf, res);
IF props.state = "frozen" THEN
IF root THEN
IF PLog THEN OdUtil.Msg2(lines.line, "frozen."); END;
w.String(res); w.Char(' ');
w.String(props.versionHistory); w.Char(VerCh);
w.String(props.versionName); w.Ln();
END;
ELSIF props.state = "" THEN
IF PLog THEN OdUtil.Msg2(lines.line, "configuration"); END;
ELSE
IF PLog THEN OdUtil.Msg2(lines.line, "not frozen."); END;
allFrozen := FALSE;
END;
lines := lines.next;
END;
IF allFrozen THEN
subconfs := findVCCs(conf);
WHILE subconfs # NIL DO
IF PLog THEN OdUtil.Msg2("checkFrozenVCRs: subconf", subconfs.line); END;
IF ~checkFrozenVCRs(subconfs.line, FALSE, w) THEN allFrozen := FALSE; END;
subconfs := subconfs.next;
END;
END;
RETURN allFrozen;
END checkFrozenVCRs;
PROCEDURE freezeConfiguration(mode, conf, hist: OdUtil.Line; log: OdVCSBase.TLog; flags: SET);
CONST PLog = FALSE;
VAR subconf: OdUtil.Line; subconfs: OdUtil.Lines; textLen: LONGINT; allFrozen: BOOLEAN; props: VersionProperties;
f: Files.File; r: Files.Rider; erg: INTEGER; fileName: OdUtil.Line; w: Files.Writer;
BEGIN
fileName := ConfDataFileName(conf);
IF PLog THEN OdUtil.Msg3("freezeConfiguration.ConfDataFileName:", conf, fileName); END;
f := Files.New(fileName); Files.OpenWriter(w, f, 0);
IF PLog THEN OdUtil.Msg4("freezeConfiguration: ", mode, conf, hist); END;
unpadConfiguration(conf);
allFrozen := checkFrozenVCRs(conf, TRUE, w);
IF allFrozen THEN
subconfs := findVCCs(conf);
WHILE subconfs # NIL DO
IF PLog THEN OdUtil.Msg3("freeze subconf", conf, subconfs.line); END;
subconf := subconfs.line;
padConfiguration(subconf);
NEW(props, "", subconf);
IF props.state = "" THEN
freezeConfiguration("initial", subconf, hist, log, flags);
IF PLog THEN OdUtil.Msg3("freezeConfigurations: subconf ", subconf, "created"); END;
ELSIF props.state = "thawed" THEN
freezeConfiguration("other", subconf, hist, log, flags);
IF PLog THEN OdUtil.Msg3("freezeConfigurations: subconf ", subconf, "frozen"); END;
ELSE
IF PLog THEN OdUtil.Msg3("freezeConfigurations: subconf ", subconf, "was already frozen"); END;
END;
NEW(props, "", subconf);
IF Strings.Pos(conf, subconf) = 0 THEN
Slice(subconf, Strings.Length(conf)+1, Strings.Length(subconf) - Strings.Length(conf) -1 , subconf);
END;
w.String(ConfShortDataFileName(subconf)); w.Char(' ');
w.String(props.versionURL); w.Ln();
subconfs := subconfs.next;
END;
END;
IF allFrozen THEN
w.Update(); Files.Register(f);
fileName := ConfShortDataFileName(conf);
IF PLog THEN OdUtil.Msg3("freezeConfiguration.ConfShortDataFileName", conf, fileName); END;
IF mode = "initial" THEN freezeInitialResource("", fileName, log, flags);
ELSIF mode = "other" THEN freezeOtherResource("", fileName, log, flags);
END;
ELSE
preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.InternalServerError, "Not all VCRs were frozen", -1);
END;
END freezeConfiguration;
PROCEDURE freezeInitialConfiguration*(conf: OdUtil.Line; log: OdVCSBase.TLog; flags: SET);
VAR props: VersionProperties; hist: OdUtil.Line;
BEGIN
preCond := OdCond.Ok;
NEW(props, "", conf);
IF props.state # "" THEN
preCond := OdCond.VccMustNotExist;
ELSE
hist := repMan.newHistory(conf);
freezeConfiguration("initial", conf, hist, log, flags);
END;
END freezeInitialConfiguration;
PROCEDURE freezeOtherConfiguration*(conf: OdUtil.Line; log: OdVCSBase.TLog; flags: SET);
VAR props: VersionProperties;
BEGIN
preCond := OdCond.Ok;
NEW(props, "", conf);
IF props.versionHistory = "" THEN
OdUtil.Msg2(conf, "no version history property found for configuration");
ELSIF props.state = "frozen" THEN
OdUtil.Msg2(conf, "VCR exists and is frozen. Please thaw it.");
ELSE
freezeConfiguration("other", conf, props.versionHistory, log, flags);
END;
END freezeOtherConfiguration;
PROCEDURE selectResource(conf, res, hist, ver: OdUtil.Line);
CONST PLog = FALSE;
VAR historyName, fileName: OdVCSBase.TFileName; version, pos, erg, verPos: LONGINT;
log: OdVCSBase.TLog;
props: VersionProperties; line: OdUtil.Line;
errMsg: ARRAY 256 OF CHAR; f: Files.File;
BEGIN
IF PLog THEN OdUtil.Msg5("DAVDeltavBase.sR:",conf, res, hist, ver); END;
line := ResFileName(conf, res); COPY(line, fileName);
verPos := -1;
FOR pos := 0 TO Strings.Length(ver)-1 DO
IF ver[pos] = VerCh THEN verPos := SHORT(pos); END;
END;
INC(verPos);
Strings.StrToIntPos(ver, version, verPos);
IF version <= 0 THEN
OdUtil.Msg2("DAVDeltavBase.sR: ver = ", ver);
preCond := OdCond.MustBeVersion;
RETURN;
END;
line := repMan.repName(hist); COPY(line, historyName);
erg := OdVCSBase.View(historyName, version, fileName);
IF erg < 0 THEN
preCond := OdCond.ErrorMsg;
Strings.Concat("DAVDeltavBasse.selectResource: ", OdVCSBase.errMsg, errMsg);
OdC.SetError(WebHTTP.InternalServerError, errMsg, erg);
ELSE
OdVCSBase.GetLog(historyName, version, log);
IF PLog THEN OdUtil.Msg3("DAVDeltavBase.sR: NEW(props)", conf, res); END;
NEW(props, conf, res);
GetSuffix(ver, props.versionName);
IF props.versionName = "" THEN
props.versionName := ver;
END;
props.set("versionName", props.versionName);
props.set("state", "frozen");
props.set("versionHistory", hist);
props.set("DAV:creator-displayname", log.author);
props.set("DAV:comment", log.logText);
props.set("creationDate", log.date);
IF ~ (OdVCSBase.MakroBit IN log.flags) THEN
props.set("keywords", "f");
ELSE
props.set("keywords", "t");
END;
END;
END selectResource;
PROCEDURE selectInitialResource*(conf, res, versionUrl: OdUtil.Line);
CONST PLog = FALSE;
VAR histPos, verPos, pos: LONGINT; histName: OdUtil.Line;
confProps, props: VersionProperties;
BEGIN
preCond := OdCond.Ok;
IF PLog THEN OdUtil.Msg6("DAVDeltavBase.siR:",conf, ",", res, ",", versionUrl); END;
IF conf # "" THEN
NEW(confProps, "", conf);
IF confProps.state = "frozen" THEN
preCond := OdCond.MustNotUpdateBaselineCollection;
RETURN;
END;
END;
NEW(props, conf, res);
IF props.state # "" THEN
preCond := OdCond.CannotAddToExistingHistory;
RETURN;
END;
histPos := Strings.Pos(VersionMarker, versionUrl);
IF histPos > -1 THEN
Slice(versionUrl, histPos+6, Strings.Length(versionUrl)-histPos-6, histName);
ELSE
histName := versionUrl;
END;
FOR pos := 0 TO Strings.Length(histName)-1 DO
IF histName[pos] = VerCh THEN verPos := pos; END;
END;
histName[verPos] := 0X;
selectResource(conf, res, histName, versionUrl);
END selectInitialResource;
PROCEDURE selectOtherResource*(conf, res, ver: OdUtil.Line);
CONST PLog = FALSE;
VAR confProps, props: VersionProperties; verPos, pos: LONGINT;
BEGIN
preCond := OdCond.Ok;
IF PLog THEN OdUtil.Msg6("soR: conf, res, ver =",conf, ":", res, ":", ver); END;
IF conf # "" THEN
NEW(confProps, "", conf);
IF confProps.state = "frozen" THEN
OdUtil.Msg2(conf, "VCC exists and is frozen. Please thaw it.");
RETURN;
END;
END;
NEW(props, conf, res);
IF PLog THEN OdUtil.Msg2("soR: props.versionHistory =", props.versionHistory); END;
IF props.versionHistory = "" THEN
OdUtil.Msg3("soR: couldn't find props.versionHistory. conf, res = ", conf, res);
RETURN;
END;
IF props.state # "frozen" THEN
OdUtil.Msg3(conf, res, "must be checked-in for UPDATE");
ELSE
verPos := -1;
FOR pos := 0 TO Strings.Length(ver)-1 DO
IF ver[pos] = VerCh THEN verPos := pos; END;
END;
IF verPos > 0 THEN
pos := Strings.Pos(props.versionHistory, ver);
IF pos # 0 THEN
OdUtil.Msg3(props.versionHistory, ver, "must belong to same version history");
RETURN;
END;
END;
IF PLog THEN OdUtil.Msg4("soR: props.versionHistory, ver", props.versionHistory, ":", ver); END;
selectResource(conf, res, props.versionHistory, ver);
END;
END selectOtherResource;
PROCEDURE selectConfiguration(mode, conf, ver: OdUtil.Line);
CONST Log0 = FALSE; Log1 = FALSE; Log2 = FALSE;
VAR f: Files.File; w: Files.Writer; r: Files.Reader; line, res, resVer, subConf: OdUtil.Line;
confProps: VersionProperties; absConf, confData: OdUtil.Line;
dir: Files.File; splitter: OdXml.StringSplitter; ok: BOOLEAN;
status: LONGINT; errMsg: ARRAY 128 OF CHAR;
BEGIN
IF Log0 THEN OdUtil.Msg4("sC:", mode, conf, ver); END;
absConf := AbsWorkPath(conf); unpadConfiguration(absConf);
dir := Files.Old(absConf);
IF dir # NIL THEN
IF Log1 THEN OdUtil.Msg2("sC: Directory exists:", absConf); END;
ELSE
IF Log0 THEN OdUtil.Msg2("sC: Directory will be created:", absConf); END;
mkcol(absConf, status);
dir := Files.Old(absConf);
IF dir = NIL THEN
preCond := OdCond.ErrorMsg;
Strings.Concat("SelectConfiguration: couldn't create directory ", absConf, errMsg);
OdC.SetError(WebHTTP.InternalServerError, errMsg, status);
RETURN;
END;
END;
f := Files.New(""); Files.OpenWriter(w, f, 0);
IF checkFrozenVCRs(conf, TRUE, w) THEN
Files.Register(f);
deleteFrozenVCRs(conf);
confData := ConfDataFileName(conf);
IF Log1 THEN OdUtil.Msg2("sC: confData:", confData); END;
IF mode = "initial" THEN
selectInitialResource("", confData, ver);
IF preCond # OdCond.Ok THEN
RETURN;
END;
ELSIF mode = "other" THEN
selectOtherResource("", confData, ver);
IF preCond # OdCond.Ok THEN
RETURN;
END;
ELSE
preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.InternalServerError, "SelectConfiguration: Unknown mode", 0);
RETURN;
END;
NEW(confProps, "", ResFileName("", conf)); confProps.set("state", "thawed");
f := Files.Old(confData);
IF f = NIL THEN
preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.InternalServerError, "SelectConfiguration: couldn't open conf datafile", 0);
RETURN;
END;
Files.OpenReader(r, f, 0);
LOOP
r.Ln(line);
IF r.res # Streams.Ok THEN EXIT; END;
NEW(splitter, line); ok := splitter.Next(' ', res); ok := splitter.Next(' ', resVer);
IF Log2 THEN OdUtil.Msg3("sC: res,resVer = ",res, resVer); END;
IF isConfDataFileName(res) THEN
IF res[0] = CollCh THEN
subConf := Data2Conf(res);
ELSE
absConf := Data2Conf(res);
subConf := FullSubconfName(conf, absConf);
IF Log2 THEN OdUtil.Msg3("sC: conf,fullConf = ",absConf, subConf); END;
END;
selectConfiguration("initial", subConf, resVer);
IF preCond # OdCond.Ok THEN
Files.Register(f); RETURN;
ELSE
confProps.set("DAV:subbaseline-set", subConf);
END;
ELSE
selectInitialResource(conf, res, resVer);
IF preCond # OdCond.Ok THEN
Files.Register(f); RETURN;
END;
END;
END;
confProps.set("state", "frozen");
ELSE
Files.Register(f);
END;
END selectConfiguration;
PROCEDURE selectInitialConfiguration*(conf, ver: OdUtil.Line);
CONST PLog = FALSE;
VAR props: VersionProperties;
BEGIN
IF PLog THEN OdUtil.Msg2("siC: conf = ", conf); END;
NEW(props, "", conf);
IF PLog THEN OdUtil.Msg2("siC: props.state = ", props.state); END;
IF props.state # "" THEN
preCond := OdCond.VccMustNotExist;
RETURN;
END;
selectConfiguration("initial", conf, ver);
END selectInitialConfiguration;
PROCEDURE selectOtherConfiguration*(conf, ver: OdUtil.Line);
VAR props: VersionProperties; errMsg: ARRAY 64 OF CHAR;
BEGIN
NEW(props, "", conf);
IF props.state = "" THEN
preCond := OdCond.ErrorMsg;
COPY(conf, errMsg); Strings.Append(errMsg, " not found");
OdC.SetError(WebHTTP.InternalServerError, errMsg, -1);
ELSIF props.state = "thawed" THEN
preCond := OdCond.ErrorMsg;
COPY(conf, errMsg); Strings.Append(errMsg, "must be checked-in for UPDATE");
OdC.SetError(WebHTTP.InternalServerError, errMsg, -1);
ELSE
selectConfiguration("other", conf, ver);
END;
END selectOtherConfiguration;
PROCEDURE thawResource*(conf, res: OdUtil.Line);
VAR confProps, props: VersionProperties;
BEGIN
preCond := OdCond.Ok;
NEW(confProps, "", conf);
IF confProps.state = "frozen" THEN
preCond := OdCond.MustNotUpdateBaselineCollection;
ELSE
NEW(props, conf, res);
IF props.state = "" THEN
preCond := OdCond.MustBeVcr;
ELSIF props.state = "thawed" THEN
preCond := OdCond.MustBeCheckedIn;
ELSE
props.set("state", "thawed");
END;
END;
END thawResource;
PROCEDURE unThawResource*(conf, res: OdUtil.Line);
VAR props: VersionProperties;
BEGIN
preCond := OdCond.Ok;
NEW(props, conf, res);
IF props.state = "" THEN
preCond := OdCond.MustBeVcr;
ELSIF props.state = "frozen" THEN
preCond := OdCond.MustBeCheckedOutVcr;
ELSE
props.set("state", "frozen");
selectOtherResource(conf, res, props.versionURL);
END;
END unThawResource;
PROCEDURE thawConfiguration*(conf: OdUtil.Line);
BEGIN
thawResource("", conf);
END thawConfiguration;
PROCEDURE unThawConfiguration*(conf: OdUtil.Line);
CONST PLog = TRUE;
VAR thawed: OdUtil.Lines; props: VersionProperties;
BEGIN
thawed := thawedVCRs(conf);
IF thawed # NIL THEN
IF PLog THEN OdUtil.Msg3("DAVDeltavBase.unThawConfiguration:", conf, "unthaw thawed VCRs"); END;
WHILE thawed # NIL DO OdUtil.Msg2(thawed.line, "thawed"); thawed := thawed.next; END;
preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.Conflict, "vcc-has-checked-out-vcrs", 0);
ELSE
unThawResource("", conf);
END;
END unThawConfiguration;
PROCEDURE modifyResource*;
BEGIN HALT(21); END modifyResource;
PROCEDURE modifyConfiguration*;
BEGIN HALT(21); END modifyConfiguration;
PROCEDURE reportResource*(conf, res: OdUtil.Line);
VAR props: VersionProperties;
BEGIN
NEW(props, conf, res);
OdUtil.Msg4(conf, res, props.versionName, props.state);
END reportResource;
PROCEDURE reportConfiguration*(conf: OdUtil.Line; vccList: VccList);
VAR vccs, lines: OdUtil.Lines; res, ver: OdUtil.Line; props: VersionProperties; vcrList: VcrList; subList: VccList;
BEGIN lines := findVCRs(conf);
NEW(props, "", conf);
vccList.state := props.state; vccList.version := props.versionURL;
WHILE lines # NIL DO
splitConfRes(lines.line, conf, res);
NEW(props, conf, res);
ver := props.versionHistory; Strings.Append(ver, VerCh); Strings.Append(ver, props.versionName);
IF ver # '.' THEN
IF vccList.vcrs = NIL THEN NEW(vccList.vcrs, res, ver); vccList.vcrs.state := props.state;
ELSE NEW(vcrList, res, ver); vcrList.state := props.state; vccList.vcrs.add(vcrList); END;
END;
lines := lines.next;
END;
vccs := findVCCs(conf);
WHILE vccs # NIL DO
NEW(subList, vccs.line, props.versionURL);
IF vccList.vccs = NIL THEN vccList.vccs := subList; ELSE vccList.vccs.add(subList); END;
reportConfiguration(vccs.line, subList);
vccs := vccs.next;
END;
END reportConfiguration;
PROCEDURE webReportConfiguration*(host: ARRAY OF CHAR; conf: OdUtil.Line; VAR xmlDoc: XML.Document);
VAR vcc: VccList; crRes: OdXml.ConfigurationReportRes;
BEGIN NEW(vcc, conf, "top");
reportConfiguration(conf, vcc);
NEW(crRes, hostName, conf);
vcc.xml(host, crRes, crRes.GetRoot());
xmlDoc := crRes;
END webReportConfiguration;
PROCEDURE reportBaseline*(confName, baselineUrl: OdUtil.Line; vccList: VccList; level: INTEGER; VAR statusCode: LONGINT);
CONST PLog = FALSE;
VAR confPropFileName, confDataFileName, line, res, ver: OdUtil.Line;
vcrList: VcrList; subList: VccList;
rc: LONGINT; f: Files.File; r: Files.Reader; splitter: OdXml.StringSplitter; ok: BOOLEAN;
BEGIN
IF level > 9 THEN
statusCode := WebHTTP.InternalServerError; preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.InternalServerError, "DAVDeltavBase.reportBaseline: too many nested baselines", 0);
RETURN;
END;
confDataFileName := ResFileName(workMan.TempDir, confName);
Strings.Append(confDataFileName, " _");
confDataFileName[Strings.Length(confDataFileName)-2] := CHR(ORD('0')+level);
Files.Delete(confDataFileName, rc);
confPropFileName := ConfData2PropFileName(confDataFileName);
Files.Delete(confPropFileName, rc);
IF PLog THEN OdUtil.Msg3("DAVDeltavBase.rB: confDataFileName, baseline = ", confDataFileName, baselineUrl); END;
selectInitialResource("", confDataFileName, baselineUrl);
f := Files.Old(confDataFileName);
IF f = NIL THEN
statusCode := WebHTTP.InternalServerError; preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.InternalServerError, "DAVDeltavBase.reportBaseline: couldn't open confDataFileName", 0);
RETURN;
END;
Files.OpenReader(r, f, 0);
LOOP
r.Ln(line);
IF r.res # Streams.Ok THEN EXIT; END;
NEW(splitter, line); ok := splitter.Next(' ', res); ok := splitter.Next(' ', ver);
IF PLog THEN OdUtil.Msg3("DAVDeltavBase.rB: res, ver = ", res, ver); END;
IF ~ isConfDataFileName(res) THEN
IF vccList.vcrs = NIL THEN NEW(vccList.vcrs, res, ver);
ELSE NEW(vcrList, res, ver); vccList.vcrs.add(vcrList); END;
ELSE
NEW(subList, Data2Conf(res), ver);
IF vccList.vccs = NIL THEN vccList.vccs := subList; ELSE vccList.vccs.add(subList); END;
reportBaseline(Data2Conf(res), ver , subList, level+1, statusCode);
IF statusCode # WebHTTP.OK THEN RETURN; END;
END;
END;
END reportBaseline;
PROCEDURE webReportBaseline*(host: ARRAY OF CHAR; baseline: OdUtil.Line; VAR xmlDoc: XML.Document;
VAR statusCode: LONGINT);
CONST conf = "bl";
VAR vcc: VccList; brRes: OdXml.BaselineReportRes;
BEGIN NEW(vcc, conf, "top");
reportBaseline(conf, baseline, vcc, 0, statusCode);
NEW(brRes, hostName, baseline);
vcc.xml(host, brRes, brRes.GetRoot());
xmlDoc := brRes;
END webReportBaseline;
PROCEDURE compareBaseline*(a, b: OdUtil.Line; VAR vccDiff: VccDiff; VAR statusCode: LONGINT);
CONST PLog = FALSE;
VAR blA, blB: VccList;
BEGIN
NEW(blA, "baselineA", a); reportBaseline("blA", a, blA, 0, statusCode);
IF statusCode # WebHTTP.OK THEN RETURN; END;
IF PLog THEN blA.show(""); END;
NEW(blB, "baselineB", b); reportBaseline("blB", b, blB, 0, statusCode);
IF statusCode # WebHTTP.OK THEN RETURN; END;
IF PLog THEN blB.show(""); END;
NEW(vccDiff, blA, blB);
END compareBaseline;
PROCEDURE reportCompareBaseline*(host: ARRAY OF CHAR; baseline0, baseline1: OdUtil.Line;
VAR xmlOut: XML.Document; VAR statusCode: LONGINT);
CONST PLog = FALSE;
VAR vccDiff: VccDiff; cbrRes: OdXml.CompareBaselineReportRes;
BEGIN
IF PLog THEN OdUtil.Msg3("reportCompareBaseline: baseline0, baseline1 =", baseline0, baseline1); END;
localServer.compareBaseline(baseline0, baseline1, vccDiff, statusCode);
IF statusCode = WebHTTP.OK THEN
IF PLog THEN vccDiff.show(""); END;
NEW(cbrRes, hostName, baseline0);
vccDiff.xml(host, cbrRes, cbrRes.GetRoot());
xmlOut := cbrRes;
END;
END reportCompareBaseline;
PROCEDURE reportHistory*(hist: OdUtil.Line);
VAR historyName: OdVCSBase.TFileName; version, newestVersion: LONGINT;
log: OdVCSBase.TLog;
BEGIN
COPY(root, historyName); Strings.Append(historyName, hist);
newestVersion := OdVCSBase.Init(historyName);
IF newestVersion < 0 THEN OdUtil.Msg2(hist, "no versions"); RETURN; END;
FOR version := 1 TO newestVersion DO
OdVCSBase.GetLog(historyName, version, log);
KernelLog.String(hist); KernelLog.Char(VerCh); KernelLog.Int(log.versionID, 0); KernelLog.Char(' ');
KernelLog.String(log.date); KernelLog.Char(' '); KernelLog.String(log.author); KernelLog.Ln;
KernelLog.String(log.logText); KernelLog.Ln;
END;
END reportHistory;
PROCEDURE reportVersionTree*(host: ARRAY OF CHAR; conf, res: OdUtil.Line; VAR xmlDoc: XML.Document);
CONST PLog = FALSE;
VAR historyName: OdVCSBase.TFileName; version, newestVersion: LONGINT; temp: ARRAY 8 OF CHAR;
log: OdVCSBase.TLog; props: VersionProperties; vtRes: OdXml.VersionTreeRes; w: Streams.Writer;
BEGIN
NEW(props, conf, res);
COPY(root, historyName); Strings.Append(historyName, props.versionHistory);
NEW(vtRes, props.versionHistory);
newestVersion := OdVCSBase.Init(historyName);
IF newestVersion < 0 THEN OdUtil.Msg1("no versions"); RETURN; END;
FOR version := 1 TO newestVersion DO
OdVCSBase.GetLog(historyName, version, log);
temp:=OdUtil.I(log.versionID); vtRes.addVersion(host, temp, log.author, log.date, log.logText);
END;
xmlDoc := vtRes;
END reportVersionTree;
PROCEDURE PropNames(VAR href: ARRAY OF CHAR; propfindRes: OdXml.PropfindCollectionRes);
VAR
props: VersionProperties;
host: ARRAY 64 OF CHAR; path: ARRAY 256 OF CHAR; port: LONGINT;
BEGIN
propfindRes.addOK("D:getcontentlength", "");
propfindRes.addOK("D:getlastmodified", "");
propfindRes.addOK("D:resourcetype", "");
propfindRes.addOK("D:displayname", "");
IF WebHTTP.SplitHTTPAdr (href, host, path, port) THEN
NEW(props, "", path);
IF props.state # "" THEN
propfindRes.addOK("D:comment", "");
propfindRes.addOK("D:creator-displayname", "");
propfindRes.addOK("D:checked-in", "");
propfindRes.addOK("D:checked-out", "");
END;
END;
END PropNames;
PROCEDURE doPropfindList(propfindRes: OdXml.PropfindCollectionRes; propList: XML.Document;
href, type, dateTime: ARRAY OF CHAR; length: LONGINT);
VAR propfindEl, propEl, prop: XML.Element; elName: ARRAY 128 OF CHAR; p: ANY;
resourceProps: VersionProperties;
host, path: ARRAY 128 OF CHAR; value: ARRAY 512 OF CHAR; port: LONGINT;
propName, absName: OdUtil.Line; props: XMLObjects.Enumerator;
BEGIN
propfindRes.addResponse(href);
propEl := OdX.GetFirstChild(propList.GetRoot());
absName := OdX.AbsXmlName(propEl.GetName());
IF absName = "DAV:propname" THEN
PropNames(href, propfindRes);
ELSIF absName = "DAV:prop" THEN
props := propEl.GetContents();
WHILE props.HasMoreElements() DO
p := props.GetNext();
IF p IS XML.Element THEN
prop := p(XML.Element);
propName := OdX.AbsXmlName(prop.GetName());
IF propName = "DAV:getcontentlength" THEN
Strings.IntToStr(length, host); propfindRes.addOK("D:getcontentlength", host);
ELSIF propName = "DAV:getlastmodified" THEN
propfindRes.addOK("D:getlastmodified", dateTime);
ELSIF propName = "DAV:resourcetype"THEN
propfindRes.addResourceType(type);
ELSIF propName = "DAV:displayname"THEN
IF WebHTTP.SplitHTTPAdr(href, host, path, port) THEN
Files.SplitPath(path, host, elName);
ELSE
elName := "";
END;
propfindRes.addOK("D:displayname", elName);
ELSE
IF resourceProps = NIL THEN
IF WebHTTP.SplitHTTPAdr(href, host, path, port) THEN
absName := ResFileName("", path);
NEW(resourceProps, "", absName);
END;
END;
IF resourceProps # NIL THEN
value := "";
IF propName = "DAV:version-time" THEN
COPY(resourceProps.creationDate, value);
ELSIF (propName = "DAV:checked-in") & (resourceProps.state = "frozen") THEN
Strings.Concat("/hist/", resourceProps.versionHistory, value);
Strings.Append(value, "."); Strings.Append(value, resourceProps.versionName);
ELSIF (propName = "DAV:checked-out") & (resourceProps.state = "thawed") THEN
Strings.Concat("/hist/", resourceProps.versionHistory, value);
Strings.Append(value, "."); Strings.Append(value, resourceProps.versionName);
ELSE
resourceProps.get(propName, value);
END;
IF value # "" THEN
propfindRes.addOK(propName, value);
ELSE
propfindRes.addNotFound(propName);
END;
ELSE
propfindRes.addNotFound(propName);
END;
END;
ELSE
propfindRes.addNotFound("ES:DAVDeltavBase.doPropfindList.Unexpected XML element");
END;
END;
ELSE
OdUtil.Msg1("DAVDeltavBase.doPropfindList: no prop element found");
END;
END doPropfindList;
PROCEDURE propfind*(host : ARRAY OF CHAR; conf, res: OdUtil.Line; depth: ARRAY OF CHAR;
propList: XML.Document; VAR propResults: XML.Document);
CONST PLog = FALSE;
VAR historyName: OdVCSBase.TFileName; version, pos: LONGINT; prefixLen: LONGINT;
log: OdVCSBase.TLog; w: Streams.Writer;
propfindRes: OdXml.PropfindCollectionRes;
enum: Files.Enumerator; pattern, fullPattern, name, href: OdUtil.Line; time, date, size: LONGINT;
entryFlags, flags: SET;
dateTimeStr, timeStr, depthString: ARRAY 32 OF CHAR;
hostPrefix, parentColl, coll, absColl: ARRAY 64 OF CHAR;
BEGIN
IF host[0] = '*' THEN Strings.Delete(host, 0, 1); END;
IF host#"" THEN Strings.Concat("http://", host, hostPrefix); ELSE COPY(host,hostPrefix) END;
padConfiguration(workMan.prefix);
name := ResFileName(conf, res);
IF PLog THEN OdUtil.Msg6("host name depth = ", host, ",", name, ",", depth); END;
IF isConfiguration(name) THEN
NEW(propfindRes, res);
IF depth = "0" THEN
pos := Strings.Pos(RepoPath, res);
IF pos = 0 THEN
fullPattern := RepoMount;
ELSE
COPY(workMan.prefix, fullPattern);
END;
unpadConfiguration(fullPattern);
prefixLen := Strings.Length(fullPattern);
Strings.Append(fullPattern, res); unpadConfiguration(fullPattern);
Files.SplitPath(fullPattern, parentColl, coll);
IF PLog THEN OdUtil.Msg4("propfind pattern, depth = ", parentColl, ",", depth); END;
NEW(enum); enum.Open(parentColl, flags);
WHILE enum.GetEntry(name, entryFlags, time, date, size) DO
IF PLog THEN OdUtil.Msg2("propfind.name = ", name); END;
IF name = fullPattern THEN
Strings.FormatDateTime(WebHTTP.DateTimeFormat, Dates.OberonToDateTime(date, time), dateTimeStr);
IF PLog THEN OdUtil.Msg3("propfind.addMember: ", name, dateTimeStr); END;
COPY(hostPrefix, href);
IF Strings.Length(name) = prefixLen THEN
Strings.Append(href, "/");
ELSE
Slice(name, prefixLen, Strings.Length(name) - prefixLen + 1, name);
Strings.Append(href, name);
END;
IF propList # NIL THEN
doPropfindList(propfindRes, propList, href, "collection", dateTimeStr, size);
ELSE
propfindRes.addMember(href, "collection", dateTimeStr, size);
END;
END;
END;
enum.Close;
ELSIF depth # "0" THEN
pos := Strings.Pos(RepoPath, res);
IF pos = 0 THEN
pattern := RepoMount;
ELSE
COPY(workMan.prefix, pattern);
END;
prefixLen := Strings.Length(pattern);
unpadConfiguration(pattern);
prefixLen := Strings.Length(pattern);
Strings.Append(pattern, res); padConfiguration(pattern); Strings.Append(pattern, '*');
IF PLog THEN OdUtil.Msg5("propfindCollection: ", conf, CollCh, res, pattern); END;
NEW(enum); enum.Open(pattern, flags);
WHILE enum.GetEntry(name, entryFlags, time, date, size) DO
IF name[Strings.Length(name)-1] # PropCh THEN
Strings.FormatDateTime(WebHTTP.DateTimeFormat, Dates.OberonToDateTime(date, time), dateTimeStr);
Slice(name, prefixLen, Strings.Length(name) - prefixLen + 1, name);
Strings.Concat(hostPrefix, name, href);
IF PLog THEN OdUtil.Msg3("propfind.addMember: ", href, dateTimeStr); END;
IF propList # NIL THEN
IF (Files.Directory IN entryFlags) THEN
doPropfindList(propfindRes, propList, href, "collection", dateTimeStr, size);
ELSE
doPropfindList(propfindRes, propList, href, "resource", dateTimeStr, size);
END;
ELSE
IF (Files.Directory IN entryFlags) THEN
propfindRes.addMember(href, "collection", dateTimeStr, size);
ELSE
propfindRes.addMember(href, "resource", dateTimeStr, size);
END;
END;
END;
END;
enum.Close;
END ;
propResults := propfindRes;
ELSE
name := ResFileName(conf, res);
NEW(enum); enum.Open(name, flags);
IF enum.GetEntry(name, entryFlags, time, date, size) THEN
Strings.FormatDateTime(WebHTTP.DateTimeFormat, Dates.OberonToDateTime(date, time), dateTimeStr);
END;
href := ResHrefName(host, conf, res);
NEW(propfindRes, href);
IF propList # NIL THEN
doPropfindList(propfindRes, propList, href, "resource", dateTimeStr, size);
ELSE
propfindRes.addMember(href, "resource", dateTimeStr, size);
END;
propResults := propfindRes;
END;
END propfind;
PROCEDURE proppatch * (conf, res: OdUtil.Line; patchMode: ARRAY OF CHAR; props: OdUtil.Lines; VAR xmlDoc: XML.Document);
CONST PLog = FALSE;
SplitChar = 0DX;
VAR versionProps: VersionProperties; key: OdUtil.Line; value, oldValue: ARRAY 1024 OF CHAR;
pos: LONGINT;
BEGIN
NEW(versionProps, conf, res);
IF PLog THEN OdUtil.Msg4("conf = ", conf, "res = ", res); END;
IF patchMode = "DAV:set" THEN
key := "";
WHILE props # NIL DO
IF PLog THEN OdUtil.Msg2("line = ", props.line); END;
IF props.line # key THEN
IF key # "" THEN versionProps.set(OdX.AbsName(key), value); END;
COPY(props.line, key);
props := props.next;
COPY(props.line, value);
ELSE
props := props.next;
Strings.AppendChar(value, SplitChar);
Strings.Append(value, props.line);
END;
props := props.next;
END;
IF key # "" THEN versionProps.set(OdX.AbsName(key), value); END;
ELSIF patchMode = "DAV:add" THEN
key := "";
WHILE props # NIL DO
IF PLog THEN OdUtil.Msg2("line = ", props.line); END;
IF props.line # key THEN
IF key # "" THEN
versionProps.get(key, oldValue);
IF oldValue # "" THEN Strings.AppendChar(oldValue, SplitChar); END;
Strings.Append(oldValue, value);
versionProps.set(OdX.AbsName(key), oldValue);
END;
COPY(props.line, key);
props := props.next;
COPY(props.line, value);
ELSE
props := props.next;
Strings.AppendChar(value, SplitChar);
Strings.Append(value, props.line);
END;
props := props.next;
END;
IF key # "" THEN
versionProps.get(key, oldValue);
IF oldValue # "" THEN Strings.AppendChar(oldValue, SplitChar); END;
Strings.Append(oldValue, value);
versionProps.set(key, oldValue);
END;
ELSIF patchMode = "DAV:remove" THEN
key := "";
WHILE props # NIL DO
IF PLog THEN OdUtil.Msg2("line = ", props.line); END;
IF props.line # key THEN
IF key # "" THEN
versionProps.get(key, oldValue);
pos := Strings.Pos(value, oldValue);
IF pos = 0 THEN
Strings.Delete(oldValue, pos, Strings.Length(value)+1);
ELSIF pos > 0 THEN
Strings.Delete(oldValue, pos-1, Strings.Length(value)+1);
END;
versionProps.set(key, oldValue);
END;
COPY(props.line, key);
props := props.next;
COPY(props.line, value);
ELSE
props := props.next;
Strings.AppendChar(value, SplitChar);
Strings.Append(value, props.line);
END;
props := props.next;
END;
IF key # "" THEN
versionProps.get(key, oldValue);
pos := Strings.Pos(value, oldValue);
IF pos = 0 THEN
Strings.Delete(oldValue, pos, Strings.Length(value)+1);
ELSIF pos > 0 THEN
Strings.Delete(oldValue, pos-1, Strings.Length(value)+1);
END;
versionProps.set(key, oldValue);
END;
END;
END proppatch;
PROCEDURE addConfiguration * (conf, subconf: OdUtil.Line);
VAR confProps: VersionProperties; members: OdUtil.Lines;
BEGIN
NEW(confProps, "", conf);
IF confProps.state # "thawed" THEN
OdUtil.Msg2(conf, "must be thawed to add subconfiguration");
ELSE
members := VCCloadMembers(conf);
members.add(ConfShortDataFileName(subconf)); members.add("dummyURL");
VCCstoreMembers(conf, members);
END;
END addConfiguration;
PROCEDURE remConfiguration * (conf, subconf: OdUtil.Line);
VAR confProps: VersionProperties; members, member: OdUtil.Lines; subconfData: OdUtil.Line;
BEGIN
NEW(confProps, "", conf);
IF confProps.state # "thawed" THEN
OdUtil.Msg2(conf, "must be thawed to remove subconfiguration");
ELSE
subconfData := ConfShortDataFileName(subconf);
members := VCCloadMembers(conf); member := members;
IF members.line = subconfData THEN
members := members.next.next;
ELSE
member := members.next;
WHILE member.next # NIL DO
IF member.next.line = subconfData THEN member.next := member.next.next.next;
ELSE member := member.next.next;
END;
END;
END;
VCCstoreMembers(conf, members);
END;
END remConfiguration;
PROCEDURE delete * (uri: ARRAY OF CHAR);
CONST PLog = FALSE;
VAR absName, name: OdUtil.Line; rc, pos: LONGINT;
BEGIN
preCond := OdCond.Ok;
COPY(uri, name);
IF isConfiguration(name) THEN
absName := ResFileName("", uri);
unpadConfiguration(absName);
Files.RemoveDirectory(absName, TRUE , rc);
IF rc # 0 THEN
preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.InternalServerError, "DAVDeltavBase.delete: collection", rc);
ELSE
Files.RemoveDirectory(absName, TRUE , rc);
END;
name := ConfDataFileName(absName);
Files.Delete(name, rc);
IF rc # 0 THEN
ELSE
Files.Delete(name, rc);
END;
name :=ConfPropFileName(absName);
Files.Delete(name, rc);
IF rc # 0 THEN
ELSE
Files.Delete(name, rc);
END;
ELSE
pos := Strings.Pos(RepoPath, uri);
IF pos = 0 THEN
absName := RepoMount; Strings.Append(absName, uri);
ELSE
absName := ResFileName("", uri);
END;
Files.Delete(absName, rc);
IF rc # 0 THEN
preCond := OdCond.ErrorMsg;
OdC.SetError(WebHTTP.InternalServerError, "DAVDeltavBase.delete: resource", rc);
END;
name := ResPropFileName("", absName);
IF PLog THEN OdUtil.Msg3("delete: res, reprop = ", absName, name); END;
Files.Delete(name, rc);
IF rc # 0 THEN
ELSE
Files.Delete(name, rc);
END;
END;
END delete;
PROCEDURE mkcol * (uri: ARRAY OF CHAR; VAR statusCode: LONGINT);
VAR absName, name: OdUtil.Line; rc: LONGINT; errMsg: ARRAY 256 OF CHAR;
BEGIN
preCond := OdCond.Ok;
absName := ResFileName("", uri);
unpadConfiguration(absName);
Files.CreateDirectory(absName, rc);
IF rc # 0 THEN
statusCode := WebHTTP.InternalServerError;
preCond := OdCond.ErrorMsg;
Strings.Concat("DAVDeltavBase.mkcol: ", absName, errMsg);
OdC.SetError(WebHTTP.InternalServerError, errMsg, rc);
END;
END mkcol;
END Server;
VAR
Workspace*: ARRAY 256 OF CHAR;
WorkspaceTemp*: ARRAY 256 OF CHAR;
RepoPath: ARRAY 256 OF CHAR;
frozenDeleted: BOOLEAN;
preCond*, postCond*: INTEGER;
repMan: RepositoryManager;
workMan * : WorkspaceManager;
hostName * : ARRAY 64 OF CHAR;
localServer*: Server;
OdC:OdCond.OdCond;
OdX:OdXml.OdXml;
CRString:ARRAY 2 OF CHAR;
PROCEDURE GetSuffix*(VAR str(** in *), suf(** out *): ARRAY OF CHAR);
VAR i, j, l, dot: LONGINT;
BEGIN
dot := -1; i := 0;
WHILE str[i] # 0X DO
IF str[i] = "." THEN
dot := i
ELSIF str[i] = "/" THEN
dot := -1
END;
INC(i)
END;
j := 0;
IF dot > 0 THEN
l := LEN(suf)-1; i := dot+1;
WHILE (j < l) & (str[i] # 0X) DO
suf[j] := str[i]; INC(j); INC(i)
END
END;
suf[j] := 0X
END GetSuffix;
PROCEDURE Slice*(src: ARRAY OF CHAR; pos, len: LONGINT; VAR dest: ARRAY OF CHAR);
BEGIN dest[len] := 0X; WHILE len > 0 DO dest[len-1] := src[pos+len-1]; DEC(len); END; END Slice;
PROCEDURE splitConfRes*(confRes: OdUtil.Line; VAR conf, res: OdUtil.Line);
VAR confPos: LONGINT;
BEGIN
IF conf # "" THEN
padConfiguration(conf);
confPos := Strings.Pos(conf, confRes);
Slice(confRes, confPos+Strings.Length(conf), Strings.Length(confRes)-confPos-Strings.Length(conf), res);
ELSE
res := confRes;
END;
END splitConfRes;
PROCEDURE splitConfResVer*(confResVer: OdUtil.Line; VAR conf, res, ver: OdUtil.Line);
VAR resVer: OdUtil.Line; verPos: INTEGER; pos: LONGINT;
BEGIN
splitConfRes(confResVer, conf, resVer);
verPos:= 0;
FOR pos := 0 TO Strings.Length(resVer)-1 DO
IF resVer[pos] = VerCh THEN verPos := SHORT(pos); END;
END;
Slice(resVer, 0, verPos, res);
Slice(resVer, verPos+1, Strings.Length(resVer)-verPos-1, ver);
END splitConfResVer;
PROCEDURE splitDirBase(dirBase: OdUtil.Line; VAR dir, base: OdUtil.Line);
VAR resVer: OdUtil.Line; basePos: INTEGER; pos: LONGINT;
BEGIN
basePos:= -1;
FOR pos := 0 TO Strings.Length(dirBase)-1 DO
IF dirBase[pos] = CollCh THEN basePos := SHORT(pos); END;
END;
IF basePos = -1 THEN
dir := ""; base := dirBase;
ELSE
Slice(dirBase, 0, basePos, dir);
Slice(dirBase, basePos+1, Strings.Length(dirBase)-basePos-1, base);
END;
END splitDirBase;
PROCEDURE isConfiguration*(res: ARRAY OF CHAR): BOOLEAN;
VAR f: Files.File; absName: OdUtil.Line;
BEGIN
IF res[Strings.Length(res)-1] = CollCh THEN
RETURN TRUE;
ELSE
absName := ResFileName("", res);
f := Files.Old(absName);
IF f # NIL THEN
RETURN Files.Directory IN f.flags;
ELSE
RETURN FALSE;
END;
END;
END isConfiguration;
PROCEDURE isConfDataFileName*(res: ARRAY OF CHAR): BOOLEAN;
VAR len: LONGINT;
BEGIN
IF res # "" THEN
RETURN res[Strings.Length(res)-1] = PropCh;
ELSE
RETURN FALSE;
END;
END isConfDataFileName;
PROCEDURE isConfPropFileName(res: OdUtil.Line): BOOLEAN;
VAR len: LONGINT;
BEGIN len := Strings.Length(res);
IF len > 1 THEN
RETURN (res[len-1] = PropCh);
ELSE
RETURN FALSE;
END;
END isConfPropFileName;
PROCEDURE padConfiguration*(VAR conf: ARRAY OF CHAR);
BEGIN
IF conf = "" THEN
COPY("/", conf);
ELSIF conf[Strings.Length(conf)-1] # CollCh THEN
Strings.Append(conf, CollCh);
END;
END padConfiguration;
PROCEDURE unpadConfiguration*(VAR conf: ARRAY OF CHAR);
BEGIN
IF conf # "" THEN
IF (conf[Strings.Length(conf)-1] = CollCh) THEN
conf[Strings.Length(conf)-1] := 0X;
END;
END;
END unpadConfiguration;
PROCEDURE ResFileName*(conf, res: ARRAY OF CHAR): OdUtil.Line;
CONST PLog = FALSE;
VAR name: OdUtil.Line; pos: LONGINT;
BEGIN
IF conf # "" THEN
COPY(workMan.prefix, name); unpadConfiguration(name);
Strings.Append(name, conf); padConfiguration(name);
ELSE
pos := Strings.Pos(workMan.prefix, res);
IF pos # 0 THEN COPY(workMan.prefix, name); ELSE name := ""; END;
END;
IF res[0] = CollCh THEN
unpadConfiguration(name);
ELSE
IF pos # 0 THEN
padConfiguration(name);
END;
END;
Strings.Append(name, res);
IF PLog THEN OdUtil.Msg6("ResFileName:", conf, ":", res, ":", name); END;
RETURN name;
END ResFileName;
PROCEDURE ResHrefName * (host, conf, res: ARRAY OF CHAR): OdUtil.Line;
CONST PLog = FALSE;
VAR name: OdUtil.Line; pos: LONGINT;
BEGIN
IF host#"" THEN Strings.Concat("http://", host, name); ELSE Strings.Concat("http://", DefaultHostName, name); END;
padConfiguration(name);
IF conf # "" THEN
unpadConfiguration(name);
Strings.Append(name, conf); padConfiguration(name);
END;
IF res[0] = CollCh THEN
unpadConfiguration(name);
END;
Strings.Append(name, res);
IF PLog THEN OdUtil.Msg6("ResHrefName:", conf, ":", res, ":", name); END;
RETURN name;
END ResHrefName;
PROCEDURE ResPropFileName*(conf, res: ARRAY OF CHAR): OdUtil.Line;
VAR name: OdUtil.Line;
BEGIN
name := ResFileName(conf, res); Strings.Append(name, PropCh);
RETURN name;
END ResPropFileName;
PROCEDURE FullSubconfName*(conf, subconf: ARRAY OF CHAR): OdUtil.Line;
VAR full: OdUtil.Line;
BEGIN
IF subconf[0] = CollCh THEN
COPY(subconf, full);
ELSE
COPY(conf, full);
padConfiguration(full);
Strings.Append(full, subconf);
END;
RETURN full;
END FullSubconfName;
PROCEDURE AbsWorkPath*(conf: ARRAY OF CHAR): OdUtil.Line;
VAR abs: OdUtil.Line;
BEGIN
COPY(workMan.prefix, abs);
IF conf[Strings.Length(abs)-1] = ':' THEN
COPY(conf, abs);
ELSE
IF conf[0] = CollCh THEN
unpadConfiguration(abs);
ELSE
padConfiguration(abs);
END;
Strings.Append(abs, conf);
END;
RETURN abs;
END AbsWorkPath;
PROCEDURE ConfDataFileName*(conf: ARRAY OF CHAR): OdUtil.Line;
VAR name: OdUtil.Line; pos: LONGINT;
BEGIN
pos := Strings.Pos(workMan.prefix, conf);
IF pos # 0 THEN
COPY(workMan.prefix, name);
IF conf[0] = CollCh THEN
unpadConfiguration(name);
ELSE
padConfiguration(name);
END;
Strings.Append(name, conf);
ELSE
COPY(conf, name);
END;
padConfiguration(name);
name[Strings.Length(name)-1] := PropCh;
RETURN name;
END ConfDataFileName;
PROCEDURE ConfData2PropFileName*(confDat: ARRAY OF CHAR): OdUtil.Line;
VAR name: OdUtil.Line;
BEGIN
COPY(confDat, name);
Strings.Append(name, PropCh);
RETURN name;
END ConfData2PropFileName;
PROCEDURE ConfShortDataFileName*(conf: ARRAY OF CHAR): OdUtil.Line;
CONST PLog = FALSE;
VAR name: OdUtil.Line;
BEGIN
COPY(conf, name);
padConfiguration(name);
name[Strings.Length(name)-1] := PropCh;
IF PLog THEN OdUtil.Msg3("ConfShortDataFileName:", conf, name); END;
RETURN name;
END ConfShortDataFileName;
PROCEDURE ConfHistFileName*(conf: ARRAY OF CHAR): OdUtil.Line;
VAR name: OdUtil.Line; pos, slash: LONGINT;
BEGIN
slash := 0; FOR pos := 0 TO Strings.Length(conf) -1 DO IF conf[pos] = CollCh THEN slash := pos END; END;
INC(slash); pos := 0;
REPEAT name[pos] := conf[slash]; INC(slash); INC(pos); UNTIL conf[slash] = 0X;
Strings.Append(name, PropCh);
RETURN name;
END ConfHistFileName;
PROCEDURE ConfPropFileName * (conf: ARRAY OF CHAR): OdUtil.Line;
VAR name: OdUtil.Line;
BEGIN
name := ConfDataFileName(conf); Strings.Append(name, PropCh);
RETURN name;
END ConfPropFileName;
PROCEDURE ConfFullFileName * (conf: ARRAY OF CHAR): OdUtil.Line;
VAR name: OdUtil.Line;
BEGIN
COPY(workMan.prefix, name);
IF conf[0] = CollCh THEN
unpadConfiguration(name);
ELSE
padConfiguration(name);
END;
Strings.Append(name, conf);
padConfiguration(name);
RETURN name;
END ConfFullFileName;
PROCEDURE Data2HistFileName*(VAR conf: OdUtil.Line);
VAR segment: OdUtil.Line; pos, slash: LONGINT;
BEGIN
pos := Strings.Length(conf); conf[pos-2] := PropCh; conf[pos-1] := 0X;
slash := -1; FOR pos := 0 TO Strings.Length(conf) -1 DO IF conf[pos] = CollCh THEN slash := pos END; END;
INC(slash); pos := 0;
REPEAT segment[pos] := conf[slash]; INC(slash); INC(pos); UNTIL conf[slash] = 0X;
conf := segment;
END Data2HistFileName;
PROCEDURE Data2Conf*(dataFileName: OdUtil.Line): OdUtil.Line;
BEGIN
dataFileName[Strings.Length(dataFileName)-1] := CollCh;
RETURN dataFileName;
END Data2Conf;
PROCEDURE FileEqual(f1, f2: Files.File): BOOLEAN;
VAR f1r, f2r: Files.Rider; f1ch, f2ch: CHAR;
BEGIN
IF f1.Length() # f2.Length() THEN RETURN FALSE; END;
f1.Set(f1r, 0); f2.Set(f2r, 0);
LOOP
f1r.file.Read(f1r,f1ch); f2r.file.Read(f2r,f2ch);
IF f1r.eof OR f2r.eof THEN RETURN f1r.eof & f2r.eof; END;
IF f1ch # f2ch THEN RETURN FALSE END;
END;
END FileEqual;
PROCEDURE VCCloadMembers(conf: OdUtil.Line): OdUtil.Lines;
VAR lines: OdUtil.Lines; line: OdUtil.Line;
reader: Files.Reader; file: Files.File;
BEGIN
NEW(lines); line := ConfDataFileName(conf);
file := Files.Old(line);
IF file # NIL THEN
NEW(reader, file, 0);
LOOP
reader.SkipWhitespace; IF reader.res # Streams.Ok THEN EXIT; END;
reader.Token(line); IF reader.res # Streams.Ok THEN EXIT; END;
OdUtil.Msg2("VCCloadMembers res", line);
lines.add(line);
reader.SkipWhitespace; IF reader.res # Streams.Ok THEN EXIT; END;
reader.Token(line); IF reader.res # Streams.Ok THEN EXIT; END;
OdUtil.Msg2("VCCloadMembers ver", line);
lines.add(line);
END;
END;
IF lines = lines.next THEN lines := NIL; END;
RETURN lines;
END VCCloadMembers;
PROCEDURE VCCstoreMembers(conf: OdUtil.Line; lines: OdUtil.Lines);
VAR fileName: OdUtil.Line; file: Files.File; writer: Files.Writer;
BEGIN
fileName := ConfDataFileName(conf);
file := Files.New(fileName);
NEW(writer, file, 0);
WHILE lines # NIL DO
OdUtil.Msg2("VCCstoreMembers res", lines.line);
writer.String(lines.line); writer.Char(' '); lines := lines.next;
OdUtil.Msg2("VCCstoreMembers ver", lines.line);
writer.String(lines.line); writer.Char(0DX); lines := lines.next;
END;
writer.Update;
Files.Register(file);
END VCCstoreMembers;
PROCEDURE findVCCs*(conf: OdUtil.Line): OdUtil.Lines;
CONST PLog0 = FALSE; PLog1 = FALSE;
VAR subconfs: OdUtil.Lines; subconf: OdUtil.Line;
splitter: OdXml.StringSplitter;
props: VersionProperties; subbaselineLine: ARRAY 1024 OF CHAR;
BEGIN
padConfiguration(conf);
IF PLog0 THEN OdUtil.Msg2("DAVDeltavBase.findVCCs: ", conf); END;
NEW(subconfs);
NEW(props, "", conf);
props.get("DAV:subbaseline-set", subbaselineLine);
IF PLog0 THEN OdUtil.Msg2("DAVDeltavBase.findVCCs: subbaselineLine = ", subbaselineLine); END;
NEW(splitter, subbaselineLine);
WHILE splitter.Next(0DX, subconf) DO
IF PLog1 THEN OdUtil.Msg2("DAVDeltavBase.findVCC: subbaseline = ", subconf); END;
subconfs.add(FullSubconfName(conf, subconf));
END;
IF subconfs = subconfs.next THEN subconfs := NIL; END;
RETURN subconfs;
END findVCCs;
PROCEDURE findVCRs * (conf: OdUtil.Line): OdUtil.Lines;
VAR lines: OdUtil.Lines;
PROCEDURE findVCRs0(conf, resDir: OdUtil.Line);
CONST
PLog = FALSE;
VAR enum: Files.Enumerator;
pattern, name, confResDir: OdUtil.Line; time, date, size: LONGINT;
entryFlags, flags: SET;
f: Files.File;
BEGIN
flags := {}; entryFlags := {};
padConfiguration(conf);
Strings.Concat(conf, resDir, confResDir);
pattern := ConfFullFileName(confResDir); Strings.Append(pattern, '*');
IF PLog THEN OdUtil.Msg3("findVCRs:", confResDir, pattern); END;
NEW(enum); enum.Open(pattern, flags);
WHILE enum.GetEntry(name, entryFlags, time, date, size) DO
IF PLog THEN OdUtil.Msg2("findVCRs.file:", name); END;
IF name[Strings.Length(name)-1] = PropCh THEN
name[Strings.Length(name)-1] := 0X;
IF name[Strings.Length(name)-1] # PropCh THEN
f := Files.Old(name);
IF f # NIL THEN
IF ~ (Files.Directory IN f.flags) THEN
IF PLog THEN OdUtil.Msg3("findVCRs.found:", conf, name); END;
lines.add(name);
END;
Files.Register(f);
END;
END;
ELSIF Files.Directory IN entryFlags THEN
f := Files.Old(ConfDataFileName(name));
IF f = NIL THEN
Strings.Copy(name, Strings.Length(pattern)-1, Strings.Length(name)-Strings.Length(pattern)+1, resDir);
padConfiguration(resDir);
findVCRs0(conf, resDir);
ELSE
Files.Register(f);
END;
END;
END;
enum.Close;
END findVCRs0;
BEGIN
NEW(lines);
findVCRs0(conf, "");
IF lines = lines.next THEN lines := NIL; END;
RETURN lines;
END findVCRs;
PROCEDURE thawedVCRs(conf: OdUtil.Line): OdUtil.Lines;
VAR thawed, vcrs: OdUtil.Lines; props: VersionProperties; res: OdUtil.Line;
BEGIN
vcrs := findVCRs(conf); NEW(thawed);
WHILE vcrs # NIL DO
splitConfRes(vcrs.line, conf, res);
NEW(props, conf, res);
IF props.state = "thawed" THEN thawed.add(res); END;
vcrs := vcrs.next;
END;
IF thawed = thawed.next THEN thawed := NIL; END;
RETURN thawed;
END thawedVCRs;
PROCEDURE GetErrorMsg(res: LONGINT; VAR s: ARRAY OF CHAR);
VAR temp: ARRAY 8 OF CHAR;
BEGIN
temp:=OdUtil.I(res); OdUtil.Msg2("GetErrorMsg: error=", temp);
END GetErrorMsg;
PROCEDURE CreDir*(path: ARRAY OF CHAR);
VAR p: ARRAY 1024 OF CHAR;
res: LONGINT; msg: ARRAY 256 OF CHAR;
BEGIN
COPY(path, p);
OdUtil.Msg3("Creating directory: ", p, ": ");
Files.CreateDirectory(p, res);
IF (res = 0) THEN
OdUtil.Msg1("created");
Files.CreateDirectory(p, res);
ELSE
IF (res = -1) THEN COPY("directories not supported by file system", msg)
ELSE GetErrorMsg(res, msg);
END;
OdUtil.Msg1(msg)
END;
END CreDir;
PROCEDURE RemDir*(path: ARRAY OF CHAR; force: BOOLEAN);
VAR p: ARRAY 1024 OF CHAR;
res: LONGINT; msg: ARRAY 256 OF CHAR;
BEGIN
COPY(path, p);
OdUtil.Msg3("Deleting directory: ", p, ": ");
Files.RemoveDirectory(p, force, res);
IF (res = 0) THEN OdUtil.Msg1("deleted")
ELSE
IF (res = -1) THEN COPY("directories not supported by file system", msg)
ELSE GetErrorMsg(res, msg);
END;
OdUtil.Msg1(msg)
END;
END RemDir;
BEGIN
COPY(DefaultHostName, hostName);
COPY(DefaultWorkspace,Workspace);
COPY(DefaultWorkspaceTemp,WorkspaceTemp);
COPY(DefaultRepoPath, RepoPath);
NEW(repMan); NEW(workMan, Workspace);
NEW(localServer, repMan.prefix);
frozenDeleted := FALSE;
NEW(OdC); NEW(OdX);
Strings.AppendChar(CRString,CR);
END OdDeltavBase.
Builder.Compile * System.Free DAVDeltavBase VCS OdVCSBase ~
OFSTools.Mount DV AosFS IDE0#05 ~ OFSTools.Unmount DV ~
(* Collection DV:deltav.test. exists. DAVDeltavBase.localServer,localClient are created with loading. *)
Environment
Repository: v.<resource name>
Release configuration: deltav.rel.
Development configuration: deltav.dev
System.DeleteFiles ~ System.Directory ^ v.*\d deltav.test*\d deltav.rel.*\d deltav.test.data1.Text deltav.rel.data1.Text
deltav.rel.data1.Text. deltav.rest*
CHECKIN DAVDeltavBase.fiR deltav.test. data1.Text "edgar@edgarschwarz.de" "Eine erste Testversion" expand ~
DAVDeltavBase.fiR deltav.test. data2.Text "edgar@edgarschwarz.de" "Eine erste Testversion der 2. Datei" expand ~
DAVDeltavBase.foR deltav.test. data1.Text "edgar@edgarschwarz.de" "Eine 4. Testversion der 1. Datei" expand ~
DAVDeltavBase.foC deltav.test. "edgar@edgarschwarz.de" "Nun mit relativem Pfad und Versionhistory in ResourceURLs" ~
UPDATE DAVDeltavBase.siR deltav.test. data1.Text data1.Text.3 ~ History name from version URL
DAVDeltavBase.soR deltav.test. data1.Text 3 ~ History name from property file.
DAVDeltavBase.siC deltav.rest. deltav.test..5 ~ Take resource name as history name at the moment.
CHECKOUT DAVDeltavBase.tR deltav.test. data1.Text ~
UNCHECKOUT DAVDeltavBase.utR deltav.test. data1.Text ~
REPORT DAVDeltavBase.rC deltav.test. DAVDeltavBase.rR deltav.test. data1.Text
DAVDeltavBase.rH data1.Text DAVDeltavBase.rH deltav.test.
DAVDeltavBase.cB deltav.test..7 deltav.test..8
DAVDeltavBase.cB deltav.test..8 deltav.test..9
DAVDeltavBase.cB deltav.test..7 deltav.test..9
Old Interface:
VCS.HandleView v.data1.Text 1 VCS.init v.deltav.test. VCS.init v.data1.Text VCS.rlog v.deltav.test. 3
Report VCS.init <file name> ; number of versions, -1 if none exist
shows number of versions in <version number>
CheckIn VCS.New <file name> "<author>" "log text"
; create new version, first is 1, else increment last
PropFind VCS.rlog <file> <version> VCS.rlog v.data3.Text 1
; show log text of version in System.log and also in panel
; tags only will be expanded it log text starts with $
CheckOut VCS.HandleView <file name> <version number>
; get version from file and create file <file>.V<version>
; if it doesn't exist
Was passiert eigentlich nach dem ersten VERSION-CONTROL ? Ist da die Arbeitsdatei da ? Dann müsste ich gleich
ein selectInitialResource hinterherschicken.
Subconfigurations:
- Version is registered in '<conf>.'. The '.' is a sign for a subbaseline. Will be the collection char. CollCh = '.' | '/'.
- Freeze:
- check own frozen VCRs
- check sub VCRs. If VCC is frozen just return version URL. Else show thawed stuff.
- if all VCRs are frozen but some thawed VCCs freeze them recursively and add their version URLs to '<conf>.'.
use the same logtext for all thawed VCCs.
- then freeze configuration itself.
- Select:
- check recursively for thawed VCRs
- selcect VCRs
- select VCCs
- Thaw:
Check whether Masterconfiguration is thawed => Configuration needs 'parentConf'.
Done
- Vergleich mit falscher Version beim Diff: ExpandTags hat gefehlt.
ToDo
- Relative Pfade unter einer Rootkonfiguration.
- Beschreibung in DAV.Panel ergänzen
- Erste Baseline von DAVDeltav: Workspace 'dav.' ?
es.DAVDeltav.Tool
- Historyfiles v.<nnn><name> Einfach dreistellig durchzählen oder mit '0' anfangen und nur im Falle eines
Konflikts (sollte selten vorkommen) hochzählen ?
- Bei Select einer Konfiguration Dateien die stimmen nicht löschen und wieder herausholen, sondern
lassen.