Skip to content

Commit 5b8378e

Browse files
author
Denis
committed
getBranchesDiff() is implemented, documentation updated
1 parent fb8734e commit 5b8378e

File tree

3 files changed

+101
-47
lines changed

3 files changed

+101
-47
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
[![Release](https://jitpack.io/v/ProjectKaiser/pk-vcs-svn.svg)](https://jitpack.io/#ProjectKaiser/pk-vcs-svn)
2+
13
# Overview
24
Pk-vcs-svn is lightweight library for execute basic SVN VCS operations (merge, branch create etc). It uses [pk-vcs-api](https://github.com/ProjectKaiser/pk-vcs-api) exposing IVCS implementation for SVN repositories and [SVNKit](https://svnkit.com/) as framework to work with SVN repositories.
35
Features:
46
- Branch create and remove
57
- Branch merge returning result(success or list of conflicted files)
68
- Commit messages list
7-
- Summarized branch changes list
9+
- Summarized diff between branches
810
- Branches list
911
- File content getting and setting
1012
- File create and remove
@@ -68,4 +70,4 @@ Features:
6870
- Branches/Br2/Folder/file.txt
6971
- Trunk/Folder/file.txt
7072
- Tags/Tag1/
71-
- Then `SVNVCS.getBranches()` method will return [Br1, Br2, Trunk]
73+
- Then `SVNVCS.getBranches()` method will return [Br1, Br2, Trunk]

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ defaultTasks 'build';
1919

2020
dependencies {
2121
compile 'com.github.ProjectKaiser:pk-vcs-api:master-SNAPSHOT'
22-
compile 'org.tmatesoft.svnkit:svnkit:1.8.10'
22+
compile 'org.tmatesoft.svnkit:svnkit:1.8.14'
2323
compile 'commons-logging:commons-logging:1.2'
2424

2525
testCompile 'junit:junit:4.12'

src/main/java/com/projectkaiser/scm/vcs/svn/SVNVCS.java

Lines changed: 96 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@
2424
import org.tmatesoft.svn.core.auth.BasicAuthenticationManager;
2525
import org.tmatesoft.svn.core.auth.SVNAuthentication;
2626
import org.tmatesoft.svn.core.auth.SVNPasswordAuthentication;
27-
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
2827
import org.tmatesoft.svn.core.internal.wc.DefaultSVNOptions;
29-
import org.tmatesoft.svn.core.internal.wc.SVNFileType;
3028
import org.tmatesoft.svn.core.io.SVNRepository;
3129
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
3230
import org.tmatesoft.svn.core.wc.ISVNConflictHandler;
@@ -45,6 +43,7 @@
4543
import org.tmatesoft.svn.core.wc.SVNWCClient;
4644
import org.tmatesoft.svn.core.wc.SVNWCUtil;
4745
import org.tmatesoft.svn.core.wc2.ISvnObjectReceiver;
46+
import org.tmatesoft.svn.core.wc2.SvnDiff;
4847
import org.tmatesoft.svn.core.wc2.SvnDiffStatus;
4948
import org.tmatesoft.svn.core.wc2.SvnDiffSummarize;
5049
import org.tmatesoft.svn.core.wc2.SvnOperationFactory;
@@ -92,7 +91,6 @@ public SVNVCS(IVCSRepositoryWorkspace repo, String user, String password) {
9291
if (!repoUrl.endsWith("/") && !repoUrl.endsWith("\\")) {
9392
repoUrl += "/";
9493
}
95-
DAVRepositoryFactory.setup();
9694
options = SVNWCUtil.createDefaultOptions(true);
9795
try {
9896
trunkSVNUrl = SVNURL.parseURIEncoded(repo.getRepoUrl().replace("\\", "/"));
@@ -108,8 +106,6 @@ public SVNVCS(IVCSRepositoryWorkspace repo, String user, String password) {
108106

109107
clientManager = SVNClientManager.newInstance(
110108
options, repository.getAuthenticationManager());
111-
112-
SVNFileType.setSymlinkSupportEnabled(false);
113109
}
114110

115111
public SVNRepository getRepository() {
@@ -120,6 +116,10 @@ private SVNURL getBranchUrl(String branchPath) throws SVNException {
120116
return SVNURL.parseURIEncoded(repoUrl + (branchPath == null ? MASTER_PATH : BRANCHES_PATH + branchPath));
121117
}
122118

119+
private String getBranchPath(String branchPath) {
120+
return branchPath == null ? MASTER_PATH : BRANCHES_PATH + branchPath;
121+
}
122+
123123
@Override
124124
public void createBranch(String srcBranchName, String dstBranchName, String commitMessage) {
125125
try {
@@ -170,7 +170,7 @@ public void deleteBranch(String branchName, String commitMessage) {
170170
}
171171

172172
@Override
173-
public VCSMergeResult merge(String srcBranchÒôüó, String dstBranchName, String commitMessage) {
173+
public VCSMergeResult merge(String srcBranchName, String dstBranchName, String commitMessage) {
174174
SVNDiffClient diffClient = clientManager.getDiffClient();
175175
try {
176176
try (IVCSLockedWorkingCopy wc = repo.getVCSLockedWorkingCopy()) {
@@ -190,7 +190,7 @@ public SVNConflictResult handleConflict(SVNConflictDescription conflictDescripti
190190

191191
try {
192192
SVNRevisionRange range = new SVNRevisionRange(SVNRevision.create(1), SVNRevision.HEAD);
193-
diffClient.doMerge(getBranchUrl(srcBranchÒôüó),
193+
diffClient.doMerge(getBranchUrl(srcBranchName),
194194
SVNRevision.HEAD, Collections.singleton(range),
195195
wc.getFolder(), SVNDepth.UNKNOWN, true, false, false, false);
196196

@@ -326,47 +326,99 @@ public void setFileContent(String branchName, String filePath, String content, S
326326
public String getRepoUrl() {
327327
return repo.getRepoUrl();
328328
}
329-
330-
@Override
331-
public List<VCSDiffEntry> getBranchesDiff(final String srcBranchName, final String dstBranchName) {
332-
try {
333-
final List<SVNLogEntry> entries = new ArrayList<>();
334-
repository.log(new String[] { "branches/" + srcBranchName }, -1 /* start from head descending */,
335-
0, true, true, -1, new ISVNLogEntryHandler() {
336-
@Override
337-
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
338-
entries.add(logEntry);
339-
}
340-
});
341-
SVNLogEntry branchFirstCommit = entries.get(entries.size() - 1);
329+
330+
private void fillUnifiedDiffs(final String srcBranchName, final String dstBranchName, List<VCSDiffEntry> entries,
331+
IVCSLockedWorkingCopy wc) throws SVNException {
332+
for (VCSDiffEntry entry : entries) {
333+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
342334

343-
SvnOperationFactory svnOperationFactory = new SvnOperationFactory();
344-
SvnDiffSummarize diff = svnOperationFactory.createDiffSummarize();
345-
diff.setSources(
346-
SvnTarget.fromURL(getBranchUrl(srcBranchName), SVNRevision.create(branchFirstCommit.getRevision())),
347-
SvnTarget.fromURL(getBranchUrl(srcBranchName), SVNRevision.HEAD));
335+
final SvnOperationFactory svnOperationFactory = new SvnOperationFactory();
336+
final SvnDiff diff = svnOperationFactory.createDiff();
348337

349-
final List<VCSDiffEntry> res = new ArrayList<>();
350-
diff.setReceiver(new ISvnObjectReceiver<SvnDiffStatus>() {
351-
public void receive(SvnTarget target, SvnDiffStatus diffStatus) throws SVNException {
352-
res.add(new VCSDiffEntry(diffStatus.getPath(),
353-
SVNChangeTypeToVCSChangeType(diffStatus.getModificationType())));
354-
}
338+
if (entry.getChangeType() == VCSChangeType.ADD) {
339+
SVNLogEntry firstCommit = getBranchFirstCommit(getBranchPath(dstBranchName));
340+
diff.setSource(SvnTarget.fromURL(getBranchUrl(srcBranchName).appendPath(entry.getFilePath(), true), SVNRevision.HEAD),
341+
SVNRevision.create(firstCommit.getRevision()),
342+
SVNRevision.create(repository.info(getBranchPath(dstBranchName), -1).getRevision()));
343+
} else if (entry.getChangeType() == VCSChangeType.DELETE) {
344+
SVNLogEntry firstCommit = getBranchFirstCommit(getBranchPath(dstBranchName));
345+
diff.setSource(SvnTarget.fromURL(getBranchUrl(dstBranchName).appendPath(entry.getFilePath(), true), SVNRevision.HEAD),
346+
SVNRevision.create(repository.info(getBranchPath(dstBranchName), -1).getRevision()),
347+
SVNRevision.create(firstCommit.getRevision()));
348+
} else {
349+
diff.setSources(
350+
SvnTarget.fromURL(getBranchUrl(dstBranchName).appendPath(entry.getFilePath(), true), SVNRevision.HEAD),
351+
SvnTarget.fromURL(getBranchUrl(srcBranchName).appendPath(entry.getFilePath(), true), SVNRevision.HEAD));
352+
}
353+
diff.setOutput(baos);
354+
diff.run();
355355

356-
private VCSChangeType SVNChangeTypeToVCSChangeType(SVNStatusType modificationType) {
357-
if (SVNStatusType.STATUS_ADDED.equals(modificationType)) {
358-
return VCSChangeType.ADD;
359-
} else if (SVNStatusType.STATUS_DELETED.equals(modificationType)) {
360-
return VCSChangeType.DELETE;
361-
} else if (SVNStatusType.STATUS_MODIFIED.equals(modificationType)) {
362-
return VCSChangeType.MODIFY;
363-
} else {
364-
return VCSChangeType.UNKNOWN;
365-
}
356+
try {
357+
entry.setUnifiedDiff(baos.toString("UTF-8"));
358+
} catch (UnsupportedEncodingException e) {
359+
throw new RuntimeException(e);
360+
}
361+
}
362+
}
363+
364+
private SVNLogEntry getBranchFirstCommit(final String branchPath) throws SVNException {
365+
final List<SVNLogEntry> logEntries = new ArrayList<>();
366+
repository.log(new String[] { branchPath }, -1 /* start from head descending */,
367+
0, true, true, -1, new ISVNLogEntryHandler() {
368+
@Override
369+
public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
370+
logEntries.add(logEntry);
371+
}
372+
});
373+
return logEntries.get(logEntries.size() - 1);
374+
}
375+
376+
377+
private List<VCSDiffEntry> getDiffEntries(final String srcBranchName, final String dstBranchName,
378+
final IVCSLockedWorkingCopy wc) throws SVNException {
379+
final SvnOperationFactory svnOperationFactory = new SvnOperationFactory();
380+
final SvnDiffSummarize summarizeDiff = svnOperationFactory.createDiffSummarize();
381+
final List<VCSDiffEntry> res = new ArrayList<>();
382+
383+
summarizeDiff.setSources(
384+
SvnTarget.fromURL(getBranchUrl(dstBranchName), SVNRevision.HEAD),
385+
SvnTarget.fromURL(getBranchUrl(srcBranchName), SVNRevision.HEAD));
386+
387+
summarizeDiff.setReceiver(new ISvnObjectReceiver<SvnDiffStatus>() {
388+
public void receive(SvnTarget target, SvnDiffStatus diffStatus) throws SVNException {
389+
if (diffStatus.getPath().length() == 0) {
390+
return;
391+
}
392+
VCSDiffEntry entry = new VCSDiffEntry(diffStatus.getPath(),
393+
SVNChangeTypeToVCSChangeType(diffStatus.getModificationType()));
394+
res.add(entry);
395+
}
396+
397+
private VCSChangeType SVNChangeTypeToVCSChangeType(SVNStatusType modificationType) {
398+
if (SVNStatusType.STATUS_ADDED.equals(modificationType)) {
399+
return VCSChangeType.ADD;
400+
} else if (SVNStatusType.STATUS_DELETED.equals(modificationType)) {
401+
return VCSChangeType.DELETE;
402+
} else if (SVNStatusType.STATUS_MODIFIED.equals(modificationType)) {
403+
return VCSChangeType.MODIFY;
404+
} else {
405+
return VCSChangeType.UNKNOWN;
366406
}
367-
});
368-
diff.run();
369-
return res;
407+
}
408+
});
409+
410+
return res;
411+
}
412+
413+
@Override
414+
public List<VCSDiffEntry> getBranchesDiff(final String srcBranchName, final String dstBranchName) {
415+
try {
416+
try (IVCSLockedWorkingCopy wc = repo.getVCSLockedWorkingCopy()) {
417+
checkout(getBranchUrl(dstBranchName), wc.getFolder());
418+
List<VCSDiffEntry> entries = getDiffEntries(srcBranchName, dstBranchName, wc);
419+
fillUnifiedDiffs(srcBranchName, dstBranchName, entries, wc);
420+
return entries;
421+
}
370422
} catch (SVNException e) {
371423
throw new EVCSException(e);
372424
} catch (Exception e) {

0 commit comments

Comments
 (0)