MODULE OdSvn;
IMPORT OdClient, Log := TFLog, U := Strings, WebHTTP, Streams, XML, Files, OdUtil, OdXml,
XMLObjects, Commands, KernelLog,
SVNOutput, SVNAdmin, SVNUtil;
VAR
log: Log.Log;
encTable: ARRAY 64 OF CHAR;
decTable: ARRAY 128 OF INTEGER;
TYPE
SvnProps = OBJECT
VAR
add : BOOLEAN;
date : ARRAY 33 OF CHAR;
author : ARRAY 50 OF CHAR;
revision : ARRAY 10 OF CHAR;
uuid : ARRAY 37 OF CHAR;
checksum : ARRAY 34 OF CHAR;
END SvnProps;
TYPE
StringReader = OBJECT
VAR res, pos: LONGINT; s: U.String;
PROCEDURE &Init(s: U.String);
BEGIN SELF.s := s; res := Streams.Ok; pos := 0; END Init;
PROCEDURE Char(VAR ch: CHAR);
BEGIN ch := s^[pos]; INC(pos); IF ch = 0X THEN res := Streams.EOF; END; END Char;
END StringReader;
TYPE
LogItem = OBJECT
VAR
versionName, date, addedPath, modifiedPath, comment: U.String;
PROCEDURE &Init;
BEGIN
versionName := NIL;
date:= NIL;
addedPath := NIL;
modifiedPath:= NIL;
comment := NIL;
END Init;
END LogItem;
TYPE
Activity* = OBJECT
VAR url: U.String;
statuscode*: LONGINT;
log: Log.Log;
client : OdClient.OdClient;
PROCEDURE &Init*( c : OdClient.OdClient; CONST name: ARRAY OF CHAR);
VAR urlPath: ARRAY 128 OF CHAR;
repos : OdClient.Repos;
BEGIN
client := c;
log := OdClient.log;
repos := client.GetRepos();
Files.JoinPath(repos.path, "!svn/act/", urlPath);
repos.expand(urlPath);
url := U.ConcatToNew(urlPath, name);
END Init;
PROCEDURE make*;
VAR
resHeader: WebHTTP.ResponseHeader; doc: XML.Document;
out : Streams.Reader; res: LONGINT;
BEGIN
OdClient.ShowMethodUrl(WebHTTP.MkactivityM, url^);
client.Mkactivity(url^, resHeader, out, res);
doc := client.XmlResult(resHeader, res, out);
statuscode := resHeader.statuscode;
IF resHeader.statuscode # 201 THEN
log.Enter; log.String("SvnDeltaV.Get: mkactivity error. Statuscode="); log.Int(resHeader.statuscode, 4); log.Exit;
url := NIL;
END;
END make;
PROCEDURE getUrl* () : U.String;
BEGIN
RETURN url;
END getUrl;
PROCEDURE delete*;
VAR resHeader: WebHTTP.ResponseHeader; doc: XML.Document;
out : Streams.Reader; res: LONGINT;
BEGIN
ASSERT ( url # NIL );
OdClient.ShowMethodUrl(WebHTTP.DeleteM, url^);
client.Delete(url^, resHeader, out, res);
doc := client.XmlResult(resHeader, res, out);
IF resHeader.statuscode # 204 THEN
log.Enter; log.String("SvnDeltaV.Get: delete error. Statuscode="); log.Int(resHeader.statuscode, 4); log.Exit;
END;
END delete;
END Activity;
TYPE
UpdateReq* = OBJECT(XML.Document);
PROCEDURE &InitUpdateReq*( client : OdClient.OdClient; svn : OdSvn; CONST pathName: ARRAY OF CHAR; headVersion, version: LONGINT );
VAR el1, el2: XML.Element; ac: XML.ArrayChars;
path,name: ARRAY 256 OF CHAR;
versionStr: ARRAY 32 OF CHAR;
repos : OdClient.Repos;
BEGIN Init();
repos := client.GetRepos();
IF svn.useSvn & ( svn.repositoryPathLength >= U.Length( pathName )) THEN
svn.useUpdateTarget := FALSE;
COPY ( pathName, path );
ELSE
svn.useUpdateTarget := TRUE;
Files.SplitPath(pathName, path, name);
END;
NEW(el1); el1.SetName("S:update-report"); SELF.AddContent(el1);
el1.SetAttributeValue("send-all", "true"); el1.SetAttributeValue("xmlns:S", "svn:");
repos.expand(path);
NEW(el2); el2.SetName("S:src-path"); el1.AddContent(el2);
NEW(ac); ac.SetStr(path); el2.AddContent(ac);
NEW(el2); el2.SetName("S:target-revision"); el1.AddContent(el2);
U.IntToStr(version, versionStr);
NEW(ac); ac.SetStr(versionStr); el2.AddContent(ac);
IF svn.useUpdateTarget THEN
NEW(el2); el2.SetName("S:update-target"); el1.AddContent(el2);
END;
NEW(ac); ac.SetStr(name); el2.AddContent(ac);
NEW(el2); el2.SetName("S:entry");
el1.AddContent(el2);
IF headVersion = -1 THEN
el2.SetAttributeValue("start-empty", "true");
ELSE
U.IntToStr(headVersion, versionStr);
END;
el2.SetAttributeValue("rev", versionStr);
END InitUpdateReq;
END UpdateReq;
LogReq = OBJECT(XML.Document);
PROCEDURE &InitLogReq(start, end: LONGINT);
VAR el1, el2: XML.Element; ac: XML.ArrayChars;
startStr, endStr: ARRAY 32 OF CHAR;
BEGIN Init();
NEW(el1); el1.SetName("S:log-report"); el1.SetAttributeValue("xmlns:S", "svn:"); SELF.AddContent(el1);
NEW(el2); el2.SetName("S:start-revision"); el1.AddContent(el2);
U.IntToStr(start, startStr);
NEW(ac); ac.SetStr(startStr); el2.AddContent(ac);
NEW(el2); el2.SetName("S:end-revision"); el1.AddContent(el2);
U.IntToStr(end, endStr);
NEW(ac); ac.SetStr(endStr); el2.AddContent(ac);
NEW(el2); el2.SetName("S:discover-changed-paths"); el1.AddContent(el2);
NEW(el2); el2.SetName("S:path"); el1.AddContent(el2);
END InitLogReq;
END LogReq;
TYPE
OdSvn* = OBJECT
VAR
useSvn : BOOLEAN;
globalVersion : LONGINT;
svnFileUpdate : BOOLEAN;
traverseDummy*, useUpdateTarget*, checkout* : BOOLEAN;
client* : OdClient.OdClient;
xml : OdXml.OdXml;
wrk*, ver*, errorMsg, repositoryURL* : ARRAY 256 OF CHAR;
pfStatus* : LONGINT;
countChanges*, repositoryPathLength* : LONGINT;
removeDir*, svnUpdated* : BOOLEAN;
resultDoc* : XML.Document;
nextVersion* : ARRAY 10 OF CHAR;
context* : Commands.Context;
PROCEDURE &Init*;
BEGIN
NEW ( xml );
NEW ( client, xml );
useSvn := FALSE;
globalVersion := 0;
client.server := "svn";
checkout := FALSE;
END Init;
PROCEDURE Get(CONST url: ARRAY OF CHAR; VAR f: Files.File);
VAR reqHeader: WebHTTP.RequestHeader; resHeader: WebHTTP.ResponseHeader;
res: LONGINT;
out : Streams.Reader;
BEGIN
OdClient.ShowMethodUrl(WebHTTP.GetM, url);
client.Get(url, reqHeader, resHeader, out, res);
OdClient.StoreResult2File(resHeader, res, out, "", f);
END Get;
PROCEDURE ParseUpdate(doc: XML.Document; VAR txDelta: Files.File);
VAR wtr: Files.Writer; s: XML.String;
root, txdelta: XML.Element;
elPath: ARRAY 256 OF CHAR;
strRdr: StringReader;
str : U.String;
BEGIN
NEW ( str, 4096 );
root := doc.GetRoot();
IF root # NIL THEN
s := root.GetName();
IF xml.EqualName(s, "S:update-report") THEN
xml.xmlns := NIL;
xml.GetXmlns(root);
elPath := "svn:open-directory.svn:open-file.svn:txdelta";
txdelta := xml.SplitElement(root, elPath);
IF txdelta # NIL THEN
log.Enter; log.String("XML.Element found: "); log.String(elPath); log.Exit;
NEW(strRdr, OdXml.GetCharString(txdelta));
txDelta := Files.New("");
NEW(wtr, txDelta, 0);
IF DecodeIO(strRdr, wtr) THEN
wtr.Update();
log.Enter; log.String("txdelta decoded"); log.Exit;
ELSE
log.Enter; log.String("txdelta error on decoding"); log.Exit;
txDelta := NIL;
END;
ELSE
log.Enter; log.String("XML.Element not found: "); log.String(elPath); log.Exit;
END;
ELSE
log.Enter; log.String("SvnDeltaV.ParseUpdate unexpected root name:" ); log.String(s^); log.Exit;
xml.LogDoc("DAV:update-report not found", doc);
END;
ELSE
log.Enter; log.String("SvnDeltaV.ParseUpdate: doc.root not found"); log.Exit;
END;
log.Enter; log.String( "" ); log.Exit;
END ParseUpdate;
PROCEDURE DecodeIO(in: StringReader; out: Streams.Writer): BOOLEAN;
VAR
codes: ARRAY 4 OF INTEGER;
i: INTEGER;
ch: CHAR;
ok, end: BOOLEAN;
BEGIN
ok := TRUE; end := FALSE;
in.Char(ch);
REPEAT
i := 0;
WHILE (in.res = Streams.Ok) & ok & (i < 4) DO
WHILE (in.res = Streams.Ok) & (ch <= " ") DO
in.Char(ch)
END;
codes[i] := decTable[ORD(ch)];
ok := codes[i] >= 0; INC(i);
IF ok THEN
in.Char(ch)
END
END;
IF i > 0 THEN
IF ok THEN
out.Char(CHR(ASH(codes[0], 2)+ASH(codes[1], -4)));
out.Char(CHR(ASH(codes[1], 4)+ASH(codes[2], -2)));
out.Char(CHR(ASH(codes[2], 6)+codes[3]))
ELSIF ch = "=" THEN
ok := TRUE; end := TRUE; DEC(i);
IF i = 2 THEN
out.Char(CHR(ASH(codes[0], 2)+ASH(codes[1], -4)))
ELSIF i = 3 THEN
out.Char(CHR(ASH(codes[0], 2)+ASH(codes[1], -4)));
out.Char(CHR(ASH(codes[1], 4)+ASH(codes[2], -2)))
ELSIF i # 0 THEN
ok := FALSE
END
ELSIF i = 4 THEN
ok := TRUE; end := TRUE;
out.Char(CHR(ASH(codes[0], 2)+ASH(codes[1], -4)));
out.Char(CHR(ASH(codes[1], 4)+ASH(codes[2], -2)));
out.Char(CHR(ASH(codes[2], 6)+codes[3]))
ELSIF i = 1 THEN
ok := TRUE; end := TRUE
END
ELSE
end := TRUE
END
UNTIL (in.res # Streams.Ok) OR end;
RETURN ok
END DecodeIO;
PROCEDURE TxDelta(txDelta: Files.File; CONST workUrl, targetName: ARRAY OF CHAR );
CONST
PLog = FALSE;
Is = 0;
It = 1;
Id = 2;
BufLen = 1024;
VAR source, delta, deltaData, targetR, from: Files.Reader; targetW: Files.Writer;
buf: ARRAY BufLen OF CHAR;
svo,
svl,
tvl,
il,
dl,
co, cl,
tvo,
istart, n, read: LONGINT;
iord, op: INTEGER; ch: CHAR;
sourceF, targetF: Files.File;
BEGIN
log.Enter;
log.Ln; log.Ln;
log.String( "--- TXDELTA ---" );
log.Ln;
log.Exit;
targetF := Files.New(targetName);
IF targetF # NIL THEN
NEW(targetW, targetF, 0);
NEW(targetR, targetF, 0);
ELSE
log.Enter; log.String("SvnDeltaV.TxDelta: Files.New targetF=NIL"); log.Exit;
RETURN;
END;
IF useSvn THEN
sourceF := Files.Old ( workUrl );
ASSERT ( sourceF # NIL );
ELSE
Get(workUrl, sourceF);
END;
IF sourceF # NIL THEN
NEW(source, sourceF, 0);
ELSE
log.Enter; log.String("SvnDeltaV.TxDelta: Get workUrl sourceF=NIL"); log.Exit;
RETURN;
END;
NEW(delta, txDelta, 0);
delta.RawLInt(svo);
LOOP
RawNum(delta, svo);
IF delta.res # Streams.Ok THEN
log.Enter; log.String("SvnDeltaV.TxDelta: delta.res = "); log.Int(delta.res, 4); log.Exit;
EXIT;
END;
RawNum(delta, svl); IF PLog THEN log.Enter; log.String("svl = "); log.Int(svl, 8); log.Exit; END;
RawNum(delta, tvl); IF PLog THEN log.Enter; log.String("tvl = "); log.Int(tvl, 8); log.Exit; END;
RawNum(delta, il); IF PLog THEN log.Enter; log.String("il = "); log.Int(il, 8); log.Exit;END;
RawNum(delta, dl); IF PLog THEN log.Enter; log.String("dl = "); log.Int(dl, 8); log.Exit;END;
istart := delta.Pos();
NEW(deltaData, txDelta, istart+il);
tvo := targetW.Pos();
WHILE delta.Pos() < istart+il DO
iord := ORD(delta.Get());
op := iord DIV 64;
IF iord MOD 64 > 0 THEN cl := iord MOD 64; ELSE RawNum(delta, cl); END;
CASE op OF
Is, It:
RawNum(delta, co);
IF PLog THEN log.Enter; log.Int(op, 8); log.Int(cl, 8); log.Int(co, 8); log.Exit; END;
IF op = Is THEN NEW(from , sourceF, svo+co);
ELSIF op = It THEN NEW(from, targetF, tvo+co);
END;
WHILE cl > BufLen DO
from.Bytes(buf, 0, BufLen, read);
targetW.Bytes(buf, 0, read);
DEC(cl, BufLen);
END;
from.Bytes(buf, 0, cl, read);
targetW.Bytes(buf, 0, read);
| Id:
IF PLog THEN log.Enter; log.Int(op, 8); log.Int(cl, 8); log.Exit; END;
FOR n := 1 TO cl DO
ch := deltaData.Get();
targetW.Char(ch);
END;
ELSE
END;
END;
FOR n := 1 TO dl DO
ch := delta.Get();
END;
END;
targetW.Update();
Files.Register(targetF);
END TxDelta;
PROCEDURE Propfind*(url : ARRAY OF CHAR; CONST properties: ARRAY OF CHAR; VAR props: WebHTTP.AdditionalField; VAR err: ARRAY OF CHAR);
VAR splitter: OdXml.StringSplitter;
name: ARRAY 64 OF CHAR;
resHeader: WebHTTP.ResponseHeader; doc: XML.Document;
out : Streams.Reader; res: LONGINT;
list: WebHTTP.AdditionalField;
repos : OdClient.Repos;
BEGIN
repos := client.GetRepos();
IF err # "" THEN
log.Enter; log.String(err); log.Exit;
RETURN;
END;
IF U.Pos("http://", url) # 0 THEN repos.expand(url); END;
OdClient.ShowMethodUrl(WebHTTP.PropfindM, url);
props := NIL;
NEW(splitter, properties);
WHILE splitter.Next('.', name) DO
WebHTTP.SetAdditionalFieldValue(props, name, "");
END;
client.Propfind(url, "0", props, resHeader, out, res);
pfStatus := resHeader.statuscode;
IF pfStatus = 0 THEN RETURN END;
log.Enter; log.String("SvnDeltaV.Propfind. Statuscode="); log.Int(resHeader.statuscode, 4); log.Exit;
doc := client.XmlResult(resHeader, res, out);
IF doc # NIL THEN
props := NIL;
client.ParseProps(doc, props);
list := props;
WHILE list # NIL DO
OdUtil.Msg3(list.key, ": ", list.value);
list := list.next;
END;
ELSE
COPY("SvnDeltaV.Propfind: err no result doc", err);
END;
log.Enter; log.String( "" ); log.Exit;
END Propfind;
PROCEDURE Versions* ( context: Commands.Context );
VAR url, err, vcc, ci, bc, pathName, path, name: ARRAY 256 OF CHAR;
props: WebHTTP.AdditionalField;
start, end: LONGINT;
BEGIN
log.Enter; log.String( "" ); log.Exit;
log.Enter; log.String( "" ); log.Exit;
log.Enter; log.String( "***** VERSIONS *****" ); log.Exit;
log.Enter; log.String( "" ); log.Exit;
context.arg.SkipWhitespace; context.arg.String( url);
context.arg.SkipWhitespace; context.arg.Int( start, FALSE );
context.arg.SkipWhitespace; context.arg.Int( end, FALSE );
IF context.arg.res = Commands.Ok THEN
Propfind(url, "D:version-controlled-configuration", props, err);
IF err = "" THEN
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:version-controlled-configuration", vcc) THEN END;
Propfind(vcc, "D:checked-in", props, err);
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:checked-in", ci) THEN END;
Propfind(ci, "D:baseline-collection", props, err);
IF WebHTTP.GetAdditionalFieldValue(props, "DAV:baseline-collection", bc) THEN
IF start = 0 THEN
Files.SplitPath(bc, pathName, name);
Files.SplitPath(pathName, path, name);
U.StrToInt(name, start);
END;
END;
LogReport(url, bc, start, end);
ELSE
log.Enter; log.String( "Propfind Error: " ); log.String( err ); log.Ln; log.Exit;
END;
ELSE
log.Enter; log.String('SvnDeltaV.Versions "<url>" <start revision> <end revision>'); log.Exit;
END;
END Versions;
PROCEDURE UseSvn* ( b : BOOLEAN );
BEGIN
useSvn := b;
END UseSvn;
PROCEDURE FileUpdate* ( b : BOOLEAN );
BEGIN
svnFileUpdate := b;
END FileUpdate;
PROCEDURE UpdateReport*(pathName, vcc: ARRAY OF CHAR; CONST workUrl: ARRAY OF CHAR;
headVersion, version: LONGINT; CONST workName: ARRAY OF CHAR; VAR res : LONGINT );
VAR resBody: XML.Document;
reqBody: UpdateReq;
resHeader: WebHTTP.ResponseHeader;
out : Streams.Reader; res2 : LONGINT;
txDelta: Files.File;
repos : OdClient.Repos;
BEGIN
repos := client.GetRepos();
globalVersion := version;
NEW(reqBody, client, SELF, pathName, headVersion, version );
repos.expand(vcc);
repos.expand(pathName);
OdClient.ShowMethodUrl(WebHTTP.ReportM, vcc);
client.Report(vcc, "", reqBody, resHeader, out, res2);
log.Enter; log.String("SvnDeltaV.UpdateReport. Statuscode="); log.Int(resHeader.statuscode, 4); log.Exit;
IF res = OdClient.Ok THEN
resBody := client.XmlResult(resHeader, res, out);
IF resBody # NIL THEN
IF useSvn THEN
svnUpdated := FALSE;
SvnParseUpdate( resBody, workUrl, workName, res );
ELSE
ParseUpdate(resBody, txDelta);
IF txDelta # NIL THEN
TxDelta(txDelta, workUrl, workName);
ELSE
log.Enter; log.String("SvnDeltaV.UpdateReport: err = "); log.String("no txdelta file"); log.Exit;
END;
END;
ELSE
log.Enter; log.String("SvnDeltaV.UpdateReport: err = "); log.String("no result doc"); log.Exit;
END;
ELSE
log.Enter; log.String( "Report Error: http error #" ); log.Int( res, 5 ); log.Ln; log.Exit;
END;
log.Enter; log.String( "" ); log.Exit;
END UpdateReport;
PROCEDURE Update* ( context: Commands.Context );
VAR
pathName, path, collUrl, name, workName, workUrl, vcc, ver, err: ARRAY 256 OF CHAR;
resHeader: WebHTTP.ResponseHeader;
version,headVersion, pos, res: LONGINT;
props: WebHTTP.AdditionalField;
act: Activity;
BEGIN
log.Enter; log.String( "" ); log.Exit;
log.Enter; log.String( "" ); log.Exit;
log.Enter; log.String( "***** UPDATE *****" ); log.Exit;
log.Enter; log.String( "" ); log.Exit;
context.arg.SkipWhitespace; context.arg.String( pathName );
context.arg.SkipWhitespace; context.arg.Int( version, FALSE );
context.arg.SkipWhitespace; context.arg.String( workName );
IF context.arg.res = Commands.Ok THEN
err := ""; res := 0;
NEW(act, client, "1"); act.make();
IF act.url = NIL THEN RETURN; END;
Files.SplitPath(pathName, path, name);
CollHead(path, collUrl);
log.Enter; log.String("CollUrl = "); log.String(collUrl); log.Exit;
Propfind(pathName, "D:checked-in", props, err);
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:checked-in", ver) THEN END;
Checkout(ver, resHeader, err);
COPY(resHeader.location, workUrl);
log.Enter; log.String("workUrl = "); log.String(workUrl); log.Exit;
U.Delete(ver, 0, U.Length("/repos/!svn/ver/"));
U.StrToIntPos(ver, headVersion, pos);
log.Enter; log.String("headVersion = "); log.Int(headVersion, 5); log.Exit;
Propfind(pathName, "D:version-controlled-configuration", props, err);
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:version-controlled-configuration", vcc) THEN END;
UpdateReport(pathName, vcc, workUrl, headVersion, version, workName, res);
act.delete();
ELSE
log.Enter; log.String("SvnDeltaV.Update: parameter error."); log.Exit;
END;
log.Enter; log.String( "" ); log.Exit;
END Update;
PROCEDURE ParseVersions(url: ARRAY OF CHAR; doc: XML.Document; VAR versions: OdUtil.Dict);
VAR
root, item, versionName, comment, path: XML.Element;
items: XMLObjects.Enumerator;
p: ANY; s: XML.String;
dataChars, versionChars, pathData: ARRAY 256 OF CHAR;
logItem: LogItem;
repos : OdClient.Repos;
BEGIN
repos := client.GetRepos();
root := doc.GetRoot();
IF root # NIL THEN
U.Delete(url, 0, U.Length(repos.path));
s := root.GetName();
IF xml.EqualName(s, "S:log-report") THEN
xml.xmlns := NIL;
xml.GetXmlns(root);
items := root.GetContents();
WHILE items.HasMoreElements() DO
p := items.GetNext();
item := p(XML.Element);
IF item # NIL THEN
xml.GetXmlns(item);
NEW(logItem);
path := xml.FindElement(item, "svn:added-path");
IF path # NIL THEN
OdXml.GetCharData(path, pathData);
logItem.addedPath := U.NewString(pathData);
ELSE
path := xml.FindElement(item, "svn:modified-path");
IF path # NIL THEN
OdXml.GetCharData(path, pathData);
logItem.modifiedPath := U.NewString(pathData);
END;
END;
IF path # NIL THEN
IF pathData = url THEN
IF versions = NIL THEN NEW(versions); END;
versionName := xml.FindElement(item, "DAV:version-name");
IF versionName # NIL THEN
OdXml.GetCharData(versionName, versionChars);
logItem.versionName := U.NewString(versionChars);
END;
comment := xml.FindElement(item, "DAV:comment");
IF comment # NIL THEN
OdXml.GetCharData(comment, dataChars);
logItem.comment := U.NewString(dataChars);
END;
versions.set(versionChars, logItem);
END;
END;
END;
END;
ELSE
log.Enter; log.String("SvnDeltaV.ParseVersions unexpected root name:" ); log.String(s^); log.Exit;
xml.LogDoc("S:log-report not found", doc);
END
ELSE
log.Enter; log.String("SvnDeltaV.ParseVersions: doc.root not found"); log.Exit;
END
END ParseVersions;
PROCEDURE LogReport(CONST url:ARRAY OF CHAR; bc: ARRAY OF CHAR; start, end: LONGINT);
VAR resBody: XML.Document;
reqBody: LogReq;
resHeader: WebHTTP.ResponseHeader;
out : Streams.Reader; res : LONGINT;
versions: OdUtil.Dict; logItem: LogItem;
repos : OdClient.Repos;
BEGIN
repos := client.GetRepos();
NEW(reqBody, start, end);
repos.expand(bc);
OdClient.ShowMethodUrl(WebHTTP.ReportM, bc);
client.Report(bc, "", reqBody, resHeader, out, res);
resBody := client.XmlResult(resHeader, res, out);
IF resBody # NIL THEN
OdUtil.Msg3("url", ": ", url);
versions := NIL;
ParseVersions(url, resBody, versions);
WHILE versions # NIL DO
logItem := versions.value(LogItem);
IF logItem.comment # NIL THEN
OdUtil.Msg3(versions.key, ": ", logItem.comment^);
ELSE
OdUtil.Msg3(versions.key, ": ", "no comment");
END;
versions := versions.next;
END;
ELSE
log.Enter; log.String("SvnDeltaV.LogReport: err = "); log.String("no result doc"); log.Exit;
END;
END LogReport;
PROCEDURE Add* ( context: Commands.Context );
VAR
pathName, path, name, collUrl, resUrl, repoWorkName, workName,
vcc, ci, s1, s2, err: ARRAY 256 OF CHAR;
act: Activity;
logText: ARRAY 256 OF CHAR; lenStr: ARRAY 16 OF CHAR;
resHeader: WebHTTP.ResponseHeader; doc: XML.Document;
reqHeader: WebHTTP.RequestHeader;
in: Files.Reader; out : Streams.Reader; res: LONGINT;
props: WebHTTP.AdditionalField;
root: XML.Element; s: XML.String;
f: Files.File;
repos : OdClient.Repos;
BEGIN
log.Enter; log.String( "" ); log.Exit;
log.Enter; log.String( "" ); log.Exit;
log.Enter; log.String( "***** ADD *****" ); log.Exit;
log.Enter; log.String( "" ); log.Exit;
repos := client.GetRepos();
context.arg.SkipWhitespace; context.arg.String( pathName );
context.arg.SkipWhitespace; context.arg.String( workName );
context.arg.SkipWhitespace; context.arg.String( logText );
IF context.arg.res = Commands.Ok THEN
NEW(act, client, "1"); act.make();
IF act.url = NIL THEN RETURN; END;
Files.SplitPath(pathName, path, name);
COPY(path, collUrl);
repos.expand(collUrl);
Propfind(collUrl, "D:version-controlled-configuration", props, err);
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:version-controlled-configuration", vcc) THEN END;
Propfind(vcc, "D:checked-in", props, err);
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:checked-in", ci) THEN END;
repos.expand(ci);
OdClient.ShowMethodUrl(WebHTTP.CheckoutM, ci);
client.Checkout(ci, resHeader, out, res);
log.Enter; log.String("SvnDeltaV.Get: checkout. Statuscode="); log.Int(resHeader.statuscode, 4); log.Exit;
doc := client.XmlResult(resHeader, res, out);
IF doc # NIL THEN
LOOP
root := doc.GetRoot();
s := root.GetName();
IF s^ # "D:error" THEN
xml.LogDoc("OdClient.Checkout: Unexpected root element = ", doc);
EXIT;
END;
OdXml.GetCharData(root, s1);
s2 := "DAV:error = "; U.Append(s1, s2);
log.Enter; log.String(s2); log.Exit;
EXIT;
END;
END;
log.Enter; log.String("resHeader.location="); log.String(resHeader.location); log.Ln; log.Exit;
COPY(resHeader.location, resUrl);
props := NIL;
WebHTTP.SetAdditionalFieldValue(props, 'log xmlns=http://subversion.tigris.org/xmlns/svn/' , logText);
OdClient.ShowMethodUrl(WebHTTP.ProppatchM, resUrl);
client.Proppatch(resUrl, "set", props, resHeader, out, res);
doc := client.XmlResult(resHeader, res, out);
IF doc # NIL THEN
LOOP
root := doc.GetRoot();
s := root.GetName();
IF s^ # "D:error" THEN
xml.LogDoc("OdClient.Set|RemProp: unexpected root element in ", doc);
EXIT;
END;
OdXml.GetCharData(root, resUrl);
err := "DAV:error = "; U.Append(err, resUrl);
log.Enter; log.String(err); log.Exit;
EXIT;
END;
END;
Propfind(collUrl, "D:checked-in", props, err);
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:checked-in", ci) THEN END;
repos.expand(ci);
OdClient.ShowMethodUrl(WebHTTP.CheckoutM, ci);
client.Checkout(ci, resHeader, out, res);
log.Enter; log.String("SvnDeltaV.Get: checkout. Statuscode="); log.Int(resHeader.statuscode, 4); log.Exit;
doc := client.XmlResult(resHeader, res, out);
IF doc # NIL THEN
LOOP
root := doc.GetRoot();
s := root.GetName();
IF s^ # "D:error" THEN
xml.LogDoc("OdClient.Checkout: Unexpected root element = ", doc);
EXIT;
END;
OdXml.GetCharData(root, s1);
s2 := "DAV:error = "; U.Append(s1, s2);
log.Enter; log.String(s2); log.Exit;
EXIT;
END;
END;
Files.JoinPath(resHeader.location, name, repoWorkName);
f := Files.Old(workName);
IF f # NIL THEN
NEW(in, f, 0);
WebHTTP.SetAdditionalFieldValue(reqHeader.additionalFields, "Content-Type", "application/octet-stream");
U.IntToStr(f.Length(), lenStr);
WebHTTP.SetAdditionalFieldValue(reqHeader.additionalFields, "Content-Length", lenStr);
OdClient.ShowMethodUrl(WebHTTP.PutM, repoWorkName);
client.Put(repoWorkName, reqHeader, resHeader, out, in, res);
doc := client.XmlResult(resHeader, res, out);
IF doc # NIL THEN
LOOP
root := doc.GetRoot();
s := root.GetName();
IF s^ # "D:error" THEN
xml.LogDoc("OdClient.Put: Unexpected root element = ", doc);
EXIT;
END;
OdXml.GetCharData(root, s1);
s2:= "DAV:error = "; U.Append(s2, s1);
log.Enter; log.String(s2); log.Exit;
EXIT;
END;
END;
ELSE
log.Enter; log.String("File not found: "); log.String(workName); log.Exit;
END;
Merge(path, act.url, resHeader, err);
act.delete();
ELSE
log.Enter; log.String("SvnDeltaV.Get: parameter error."); log.Exit;
END;
END Add;
PROCEDURE Commit* ( context: Commands.Context );
VAR
pathName, path, name, collUrl, workName, repoWorkName,
ver, s1, s2, err: ARRAY 265 OF CHAR;
act: Activity;
logText: ARRAY 256 OF CHAR;
lenStr: ARRAY 32 OF CHAR;
resHeader: WebHTTP.ResponseHeader; doc: XML.Document;
reqHeader: WebHTTP.RequestHeader;
out : Streams.Reader; res: LONGINT;
props: WebHTTP.AdditionalField;
root: XML.Element; s: XML.String;
f: Files.File; in: Files.Reader;
BEGIN
log.Enter; log.String( "" ); log.Exit;
log.Enter; log.String( "" ); log.Exit;
log.Enter; log.String( "***** COMMIT *****" ); log.Exit;
log.Enter; log.String( "" ); log.Exit;
context.arg.SkipWhitespace; context.arg.String( pathName );
context.arg.SkipWhitespace; context.arg.String( workName );
context.arg.SkipWhitespace; context.arg.String( logText );
IF context.arg.res = Commands.Ok THEN
NEW(act, client, "1"); act.make();
IF act.url = NIL THEN RETURN; END;
Files.SplitPath(pathName, path, name);
CollHead(path, collUrl);
props := NIL;
WebHTTP.SetAdditionalFieldValue(props, 'log xmlns=http://subversion.tigris.org/xmlns/svn/' , logText);
Proppatch(collUrl, props, err);
Propfind(pathName, "D:checked-in", props, err);
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:checked-in", ver) THEN END;
Checkout(ver, resHeader, err);
COPY(resHeader.location, repoWorkName);
f := Files.Old(workName);
IF f # NIL THEN
NEW(in, f, 0);
WebHTTP.SetAdditionalFieldValue(reqHeader.additionalFields, "Content-Type", "application/octet-stream");
U.IntToStr(f.Length(), lenStr);
WebHTTP.SetAdditionalFieldValue(reqHeader.additionalFields, "Content-Length", lenStr);
OdClient.ShowMethodUrl(WebHTTP.PutM, repoWorkName);
client.Put(repoWorkName, reqHeader, resHeader, out, in, res);
doc := client.XmlResult(resHeader, res, out);
IF doc # NIL THEN
LOOP
root := doc.GetRoot();
s := root.GetName();
IF s^ # "D:error" THEN
xml.LogDoc("OdClient.Put: Unexpected root element = ", doc);
EXIT;
END;
OdXml.GetCharData(root, s1);
s2:= "DAV:error = "; U.Append(s2, s1);
log.Enter; log.String(s2); log.Exit;
EXIT;
END;
END;
ELSE
log.Enter; log.String("File not found: "); log.String(workName); log.Exit;
END;
Merge(path, act.url, resHeader, err);
act.delete();
ELSE
log.Enter; log.String("SvnDeltaV.Commit: parameter error."); log.Exit;
END;
log.Enter; log.String( "" ); log.Exit;
END Commit;
PROCEDURE CollHead(CONST path: ARRAY OF CHAR; VAR resUrl: ARRAY OF CHAR);
VAR props: WebHTTP.AdditionalField;
vcc, bln, err: ARRAY 265 OF CHAR;
resHeader: WebHTTP.ResponseHeader;
BEGIN
Propfind(path, "D:version-controlled-configuration", props, err);
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:version-controlled-configuration", vcc) THEN END;
Propfind(vcc, "D:checked-in", props, err);
IF ~WebHTTP.GetAdditionalFieldValue(props, "DAV:checked-in", bln) THEN END;
Checkout(bln, resHeader, err);
COPY(resHeader.location, resUrl);
END CollHead;
PROCEDURE Checkout*(url: ARRAY OF CHAR; VAR resHeader: WebHTTP.ResponseHeader; CONST err: ARRAY OF CHAR);
VAR doc: XML.Document;
out : Streams.Reader; res: LONGINT;
root: XML.Element; s: U.String;
s1, s2: ARRAY 256 OF CHAR;
repos : OdClient.Repos;
BEGIN
IF err # "" THEN RETURN; END;
repos := client.GetRepos();
IF U.Pos("http://", url) # 0 THEN repos.expand(url); END;
OdClient.ShowMethodUrl(WebHTTP.CheckoutM, url);
client.Checkout(url, resHeader, out, res);
log.Enter; log.String("SvnDeltaV.Checkout. Statuscode="); log.Int(resHeader.statuscode, 4); log.Exit;
doc := client.XmlResult(resHeader, res, out);
IF doc # NIL THEN
LOOP
root := doc.GetRoot();
s := root.GetName();
IF s^ # "D:error" THEN
xml.LogDoc("OdClient.Checkout: Unexpected root element = ", doc);
EXIT;
END;
OdXml.GetCharData(root, s1);
s2 := "DAV:error = "; U.Append(s1, s2);
log.Enter; log.String(s2); log.Exit;
EXIT;
END;
END;
log.Enter; log.String( "" ); log.Exit;
END Checkout;
PROCEDURE Proppatch*(url: ARRAY OF CHAR; VAR props: WebHTTP.AdditionalField; CONST err: ARRAY OF CHAR);
VAR resHeader: WebHTTP.ResponseHeader;
doc: XML.Document;
out : Streams.Reader; res: LONGINT;
root: XML.Element; s: U.String;
s1: ARRAY 256 OF CHAR;
repos : OdClient.Repos;
BEGIN
IF err # "" THEN RETURN; END;
repos := client.GetRepos();
IF U.Pos("http://", url) # 0 THEN repos.expand(url); END;
OdClient.ShowMethodUrl(WebHTTP.ProppatchM, url);
client.Proppatch(url, "set", props, resHeader, out, res);
doc := client.XmlResult(resHeader, res, out);
IF doc # NIL THEN
IF useSvn THEN
props := NIL;
client.ParseProps(doc, props);
ELSE
LOOP
root := doc.GetRoot();
s := root.GetName();
IF s^ # "D:error" THEN
xml.LogDoc("OdClient.Set|RemProp: unexpected root element in ", doc);
EXIT;
END;
OdXml.GetCharData(root, url);
s1 := "DAV:error = "; U.Append(s1, url);
log.Enter; log.String(s1); log.Exit;
EXIT;
END;
END;
END;
log.Enter; log.String( "" ); log.Exit;
END Proppatch;
PROCEDURE Merge*(url: ARRAY OF CHAR; actUrl: U.String; VAR resHeader: WebHTTP.ResponseHeader; CONST err: ARRAY OF CHAR);
VAR doc: XML.Document;
out : Streams.Reader; res: LONGINT;
root: XML.Element; s: U.String;
s1, s2: ARRAY 265 OF CHAR;
repos : OdClient.Repos;
BEGIN
IF err # "" THEN RETURN; END;
repos := client.GetRepos();
IF U.Pos("http://", url) # 0 THEN repos.expand(url); END;
OdClient.ShowMethodUrl(WebHTTP.MergeM, url);
client.Merge(url, actUrl^, resHeader, out, res);
doc := client.XmlResult(resHeader, res, out);
IF doc # NIL THEN
IF useSvn THEN
resultDoc := doc;
ELSE
LOOP
root := doc.GetRoot();
s := root.GetName();
IF s^ # "D:error" THEN
xml.LogDoc("OdClient.Merge: Unexpected root element = ", doc);
EXIT;
END;
OdXml.GetCharData(root, s1);
s2 := "DAV:error = "; U.Append(s2, s1);
log.Enter; log.String(s2); log.Exit;
EXIT;
END;
END;
END;
log.Enter; log.String( "" ); log.Exit;
END Merge;
PROCEDURE SvnWrite ( parent : XML.Element; CONST path, filename, version : ARRAY OF CHAR; added : BOOLEAN; VAR res : LONGINT );
VAR
enum: XMLObjects.Enumerator;
p: ANY;
e, e2: XML.Element;
s, attr, rev : XML.String;
c : XMLObjects.Enumerator;
ar : XML.ArrayChars;
path2, src, dest, tmp : ARRAY 256 OF CHAR;
checkedin : ARRAY 256 OF CHAR;
writeProps, overwrite : BOOLEAN;
props : SvnProps;
strRdr : StringReader;
wtr: Files.Writer;
f : Files.File;
res2 : LONGINT;
str : U.String;
data : SVNAdmin.EntryEntity;
w : Files.Writer;
searcher : SVNUtil.FSItemSearch;
BEGIN
IF parent = NIL THEN RETURN END;
NEW ( props );
props.add := added;
writeProps := FALSE;
enum := parent.GetContents();
WHILE enum.HasMoreElements() DO
IF res # 0 THEN RETURN END;
p := enum.GetNext();
IF p IS XML.Element THEN
e := p(XML.Element); s := e.GetName();
IF s # NIL THEN
IF xml.EqualName ( s, "svn:open-directory" ) OR xml.EqualName ( s, "svn:add-directory" ) THEN
attr := e.GetAttributeValue ( "name" );
IF attr # NIL THEN
Files.JoinPath ( path, attr^, path2 );
ELSE
COPY ( path, path2 );
END;
IF writeProps THEN
writeProps := FALSE;
SvnWritePROPS ( path, filename, props );
END;
added := xml.EqualName ( s, "svn:add-directory" );
IF added THEN
NEW ( searcher );
searcher.Open ( path2, {Files.Directory} );
IF searcher.Exists () THEN
res := SVNOutput.ResADDDIRECTORYEXISTS;
COPY ( path2, errorMsg );
RETURN;
END;
Files.CreateDirectory ( path2, res2 ); ASSERT ( res2 = 0 );
SVNAdmin.CreateDirectory ( path2 );
context.out.String ( "A " ); context.out.String ( path2 ); context.out.Ln;
COPY ( attr^, data.Name );
data.NodeKind := "dir";
Files.JoinPath ( path, ".svn/entries", tmp );
f := Files.Old ( tmp );
ASSERT ( f # NIL );
SVNAdmin.RemoveFileAttribute2 ( tmp, f );
Files.OpenWriter ( w, f, f.Length() );
SVNAdmin.Write ( w, data );
SVNAdmin.SetFileAttribute2 ( tmp, f );
svnUpdated := TRUE;
END;
SvnWrite ( e, path2, "", "0", added, res );
ELSIF xml.EqualName ( s, "svn:open-file" ) OR xml.EqualName ( s, "svn:add-file" ) THEN
attr := e.GetAttributeValue ( "name" );
ASSERT ( attr # NIL );
IF writeProps THEN
writeProps := FALSE;
SvnWritePROPS ( path, filename, props );
END;
added := xml.EqualName ( s, "svn:add-file" );
IF added THEN
Files.JoinPath ( path, ".svn/text-base", src );
Files.JoinPath ( src, attr^, src );
U.Append ( src, ".svn-base" );
f := Files.New ( src );
Files.Register ( f );
NEW ( rev, 2 );
rev^ := "0";
ELSE
rev := e.GetAttributeValue ( "rev" );
ASSERT ( rev # NIL );
END;
SvnWrite ( e, path, attr^, rev^, added, res );
ELSIF xml.EqualName ( s, "DAV:checked-in" ) THEN
e2 := xml.SplitElement ( e, "DAV:href" );
ASSERT ( e2 # NIL );
OdXml.GetCharData(e2, checkedin);
SVNAdmin.WriteWCPROPS ( path, filename, checkedin );
ELSIF xml.EqualName ( s, "svn:set-prop" ) THEN
attr := e.GetAttributeValue ( "name" );
ASSERT ( attr # NIL );
c := e.GetContents();
p := c.GetNext();
ASSERT ( p IS XML.ArrayChars );
ar := p (XML.ArrayChars);
s := ar.GetStr();
ASSERT ( s # NIL );
writeProps := TRUE;
IF attr^ = "svn:entry:committed-date" THEN
COPY ( s^, props.date );
ELSIF attr^ = "svn:entry:last-author" THEN
COPY ( s^, props.author );
ELSIF attr^ = "svn:entry:uuid" THEN
COPY ( s^, props.uuid );
ELSIF attr^ = "svn:entry:committed-rev" THEN
COPY ( s^, props.revision );
END;
ELSIF xml.EqualName ( s, "svn:txdelta" ) THEN
c := e.GetContents();
p := c.GetNext();
ASSERT ( p IS XML.ArrayChars );
ar := p (XML.ArrayChars);
NEW(strRdr, ar.GetStr() );
f := Files.New("");
NEW(wtr, f, 0);
IF DecodeIO(strRdr, wtr) THEN
wtr.Update();
Files.JoinPath ( path, ".svn/text-base", src );
Files.JoinPath ( src, filename, src );
U.Append ( src, ".svn-base" );
Files.JoinPath ( path, filename, dest );
IF Files.Old ( dest ) # NIL THEN
IF props.add THEN
COPY ( dest, errorMsg );
res := SVNOutput.ResUPDATEFILEALREADYEXISTS;
RETURN;
END;
IF ~SVNAdmin.CheckChecksum ( src ) THEN
KernelLog.String ( "checksum of file: " );
KernelLog.String ( src );
str := SVNUtil.GetChecksum ( src );
KernelLog.String ( " was '" ); KernelLog.String ( str^ ); KernelLog.String ( "' expected '" );
str := SVNAdmin.ReadChecksum ( src );
KernelLog.String ( str^ ); KernelLog.String ( "'." ); KernelLog.Ln;
COPY ( src, errorMsg );
res := SVNOutput.ResCHECKSUMMISMATCH;
RETURN;
END;
IF ~SVNAdmin.CheckChecksum ( dest ) THEN
context.out.String ( "C " ); context.out.String ( dest ); context.out.Ln;
U.Concat ( dest, ".r", tmp );
U.Concat ( tmp, version, tmp );
overwrite := FALSE;
Files.CopyFile ( src, tmp, overwrite, res2 );
U.Concat ( dest, ".mine", tmp );
overwrite := FALSE;
Files.CopyFile ( dest, tmp, overwrite, res2 );
U.Append ( dest, ".r" );
U.Append ( dest, props.revision );
ELSE
context.out.String ( "U " );
context.out.String ( dest ); context.out.Ln;
END;
ELSE
ASSERT ( props.add );
context.out.String ( "A " );
context.out.String ( dest ); context.out.Ln;
END;
SVNAdmin.RemoveFileAttribute ( src );
svnUpdated := TRUE;
TxDelta ( f, src, dest );
overwrite := TRUE;
Files.CopyFile ( dest, src, overwrite, res2 );
SVNAdmin.SetFileAttribute ( src );
ELSE
log.Enter; log.String("txdelta error on decoding"); log.Exit;
END;
ELSIF xml.EqualName ( s, "svn:prop" ) THEN
e2 := xml.FindElement ( e, "http://subversion.tigris.org/xmlns/dav/md5-checksum" );
IF e2 # NIL THEN
OdXml.GetCharData(e2, props.checksum);
END;
END;
END;
END
END;
IF writeProps THEN
writeProps := FALSE;
SvnWritePROPS ( path, filename, props );
END;
END SvnWrite;
PROCEDURE SvnParseUpdate(doc: XML.Document; CONST workUrl, workName : ARRAY OF CHAR; VAR res : LONGINT );
VAR
s : XML.String;
root, e : XML.Element;
elPath: ARRAY 256 OF CHAR;
str : U.String;
m : SVNOutput.Message;
BEGIN
NEW ( str, 256 );
root := doc.GetRoot();
IF root # NIL THEN
s := root.GetName();
IF xml.EqualName( s, "S:update-report") THEN
xml.xmlns := NIL;
xml.GetXmlns(root);
IF useUpdateTarget THEN
Files.SplitPath ( workName, elPath, str^ );
ELSE
COPY ( workName, elPath );
END;
e := xml.SplitElement ( root, "svn:target-revision" );
ASSERT ( e # NIL );
str := e.GetAttributeValue ( "rev" );
COPY ( str^, nextVersion );
SvnWrite ( root, elPath, "", "0", FALSE, res );
NEW ( m, context );
m.Print ( res, errorMsg );
res := 0;
ELSE
log.Enter; log.String("SvnDeltaV.ParseUpdate unexpected root name:" ); log.String(s^); log.Exit;
xml.LogDoc("DAV:update-report not found", doc);
END;
ELSE
log.Enter; log.String("SvnDeltaV.ParseUpdate: doc.root not found"); log.Exit;
END;
log.Enter; log.String( "" ); log.Exit;
END SvnParseUpdate;
PROCEDURE SvnWritePROPS ( CONST path, filename : ARRAY OF CHAR; props : SvnProps );
VAR
tmp,fstr,fstr2 : ARRAY 256 OF CHAR;
len, i, res : LONGINT;
fr, fw : Files.File;
r : Files.Reader;
w : Files.Writer;
overwrite, nextFileEntry : BOOLEAN;
adminEntry : SVNAdmin.Entry;
data : SVNAdmin.EntryEntity;
start: ARRAY 2 OF CHAR;
BEGIN
Files.JoinPath ( path, ".svn/entries", fstr );
IF (filename = "") & ~SVNUtil.FileExists ( fstr ) THEN
IF ~checkout THEN
Files.SplitPath ( path, tmp, fstr2 );
NEW ( adminEntry, NIL );
adminEntry.SetPath ( tmp, res );
adminEntry.ReadData ( res ); ASSERT ( res = SVNOutput.ResOK );
adminEntry.GetUrl ( data.Url );
Files.JoinPath ( data.Url, fstr2, data.Url );
adminEntry.GetRepo ( data.RepositoryRoot );
ELSE
checkout := FALSE;
COPY ( repositoryURL, data.Url );
COPY ( repositoryURL, data.RepositoryRoot );
END;
data.Revision := globalVersion;
COPY ( props.date, data.LastChangedDate );
U.StrToInt ( props.revision, data.LastChangedRevision );
COPY ( props.author, data.LastChangedAuthor );
COPY ( props.uuid, data.RepositoryUUID );
fw := Files.New ( fstr );
ASSERT ( fw # NIL );
Files.OpenWriter ( w, fw, 0 );
SVNAdmin.Write ( w, data );
Files.Register ( fw );
ELSE
ASSERT ( ~( ( filename = "") & props.add) );
Files.JoinPath ( path, ".svn/tmp/od-entries", fstr2 );
IF SVNUtil.FileExists ( fstr2 ) THEN
Files.Delete ( fstr2, res );
ASSERT ( res = Files.Ok );
END;
fw := Files.New ( fstr2 );
SVNAdmin.RemoveFileAttribute2 ( fstr2, fw );
fr := Files.Old ( fstr );
ASSERT ( fr # NIL );
Files.OpenWriter ( w, fw, 0 );
Files.OpenReader ( r, fr, 0 );
IF filename = "" THEN
FOR i := 1 TO 3 DO
r.Ln ( tmp );
ASSERT ( r.res = Files.Ok );
w.String ( tmp ); w.Char ( 0AX );
END;
w.Int ( globalVersion, 0 ); w.Char ( 0AX ); r.SkipLn;
FOR i := 5 TO 9 DO
r.Ln ( tmp );
ASSERT ( r.res = Files.Ok );
w.String ( tmp ); w.Char ( 0AX );
END;
w.String ( props.date ); w.Char ( 0AX ); r.SkipLn;
w.String ( props.revision ); w.Char ( 0AX ); r.SkipLn;
w.String ( props.author ); w.Char ( 0AX ); r.SkipLn;
FOR i := 13 TO 26 DO
r.Ln ( tmp );
ASSERT ( r.res = Files.Ok );
w.String ( tmp ); w.Char ( 0AX );
END;
w.String ( props.uuid ); w.Char ( 0AX ); r.SkipLn;
ELSE
nextFileEntry := FALSE;
LOOP
r.Ln ( tmp );
IF r.res = Files.Ok THEN
w.String ( tmp ); w.Char ( 0AX );
IF nextFileEntry & (tmp = filename) THEN
FOR i := 1 TO 6 DO
r.Ln ( tmp );
ASSERT ( r.res = Files.Ok );
IF (i = 2) & svnFileUpdate THEN w.String ( props.revision ) ELSE w.String ( tmp ) END;
w.Char ( 0AX );
END;
w.String ( props.checksum ); w.Char ( 0AX ); r.SkipLn;
w.String ( props.date ); w.Char ( 0AX ); r.SkipLn;
w.String ( props.revision ); w.Char ( 0AX ); r.SkipLn;
w.String ( props.author ); w.Char ( 0AX ); r.SkipLn;
EXIT;
END;
ELSE
COPY ( filename, data.Name );
COPY ( props.checksum, data.Checksum );
COPY ( props.date, data.LastChangedDate );
COPY ( props.author, data.LastChangedAuthor );
data.NodeKind := "file";
U.StrToInt ( props.revision, data.LastChangedRevision );
SVNAdmin.Write ( w, data );
EXIT;
END;
start[0] := CHR(12); start[1] := 0X;
nextFileEntry := U.StartsWith ( start, 0, tmp );
END;
END;
REPEAT
r.Bytes ( tmp, 0, LEN(tmp), len );
w.Bytes ( tmp, 0, len );
UNTIL len < LEN(tmp);
w.Update;
SVNAdmin.RemoveFileAttribute2 ( fstr, fr );
Files.Register ( fw );
overwrite := TRUE;
Files.CopyFile ( fstr2, fstr, overwrite, res );
ASSERT ( res = Files.Ok );
SVNAdmin.SetFileAttribute2 ( fstr, fr );
END;
SVNAdmin.SetFileAttribute ( fstr );
END SvnWritePROPS;
END OdSvn;
PROCEDURE InitTables;
VAR i, max: INTEGER;
BEGIN
max := ORD("Z")-ORD("A");
FOR i := 0 TO max DO
encTable[i] := CHR(i+ORD("A"))
END;
INC(max);
FOR i := max TO max+ORD("z")-ORD("a") DO
encTable[i] := CHR(i-max+ORD("a"))
END;
max := max+ORD("z")-ORD("a")+1;
FOR i := max TO max+ORD("9")-ORD("0") DO
encTable[i] := CHR(i-max+ORD("0"))
END;
encTable[62] := "+";
encTable[63] := "/";
FOR i := 0 TO 127 DO
decTable[i] := -1
END;
FOR i := 0 TO 63 DO
decTable[ORD(encTable[i])] := i
END
END InitTables;
PROCEDURE RawNum(VAR delta: Files.Reader; VAR li: LONGINT);
VAR ch: CHAR;
BEGIN
li := 0;
REPEAT
ch := delta.Get();
li := 128 * li + (ORD(ch) MOD 128);
UNTIL ch < 80X;
END RawNum;
BEGIN
InitTables;
log := OdClient.log;
END OdSvn.