blob: ec4c51288cc2883bfddeb7c84ce397fa1b6da122 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.svn.diff;
import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.svn.WorkingCopyFormat;
import org.jetbrains.idea.svn.api.BaseSvnClient;
import org.jetbrains.idea.svn.commandLine.SvnBindException;
import org.jetbrains.idea.svn.info.Info;
import org.jetbrains.idea.svn.svnkit.SvnKitProgressCanceller;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.internal.wc.SVNCancellableEditor;
import org.tmatesoft.svn.core.internal.wc.SVNErrorManager;
import org.tmatesoft.svn.core.internal.wc.admin.SVNAdminAreaInfo;
import org.tmatesoft.svn.core.internal.wc.admin.SVNEntry;
import org.tmatesoft.svn.core.internal.wc.admin.SVNReporter;
import org.tmatesoft.svn.core.internal.wc.admin.SVNWCAccess;
import org.tmatesoft.svn.core.internal.wc17.SVNReporter17;
import org.tmatesoft.svn.core.internal.wc17.SVNWCContext;
import org.tmatesoft.svn.core.io.ISVNEditor;
import org.tmatesoft.svn.core.io.ISVNReporter;
import org.tmatesoft.svn.core.io.ISVNReporterBaton;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import org.tmatesoft.svn.core.wc.SVNEvent;
import org.tmatesoft.svn.core.wc.SVNRevision;
import org.tmatesoft.svn.core.wc2.SvnTarget;
import org.tmatesoft.svn.util.SVNDebugLog;
import org.tmatesoft.svn.util.SVNLogType;
import java.io.File;
import java.io.OutputStream;
import java.util.Collection;
import java.util.List;
/**
* @author Konstantin Kolosovsky.
*/
public class SvnKitDiffClient extends BaseSvnClient implements DiffClient {
@NotNull
@Override
public List<Change> compare(@NotNull SvnTarget target1, @NotNull SvnTarget target2) throws VcsException {
DiffExecutor executor = new DiffExecutor(target1, target2);
try {
executor.run();
}
catch (SVNException e) {
throw new SvnBindException(e);
}
return executor.getChanges();
}
@Override
public void unifiedDiff(@NotNull SvnTarget target1, @NotNull SvnTarget target2, @NotNull OutputStream output) throws VcsException {
assertUrl(target1);
assertUrl(target2);
try {
myVcs.getSvnKitManager().createDiffClient()
.doDiff(target1.getURL(), target1.getPegRevision(), target2.getURL(), target2.getPegRevision(), true, false, output);
}
catch (SVNException e) {
throw new SvnBindException(e);
}
}
private class DiffExecutor {
@NotNull private final SvnTarget myTarget1;
@NotNull private final SvnTarget myTarget2;
@NotNull private final List<Change> myChanges;
private DiffExecutor(@NotNull SvnTarget target1, @NotNull SvnTarget target2) {
this.myTarget1 = target1;
this.myTarget2 = target2;
myChanges = ContainerUtil.newArrayList();
}
@NotNull
public List<Change> getChanges() {
return myChanges;
}
public void run() throws SVNException {
assertUrl(myTarget1);
if (myTarget2.isFile()) {
assertDirectory(myTarget2);
WorkingCopyFormat format = myVcs.getWorkingCopyFormat(myTarget2.getFile());
myChanges.addAll(WorkingCopyFormat.ONE_DOT_SIX.equals(format) ? run16Diff() : run17Diff());
}
else {
myChanges.addAll(runUrlDiff());
}
}
private Collection<Change> runUrlDiff() throws SVNException {
SVNRepository sourceRepository = myVcs.getSvnKitManager().createRepository(myTarget1.getURL());
sourceRepository.setCanceller(new SvnKitProgressCanceller());
SvnDiffEditor diffEditor;
final long rev;
SVNRepository targetRepository = null;
try {
rev = sourceRepository.getLatestRevision();
// generate Map of path->Change
targetRepository = myVcs.getSvnKitManager().createRepository(myTarget2.getURL());
diffEditor = new SvnDiffEditor(sourceRepository, targetRepository, -1, false);
final ISVNEditor cancellableEditor = SVNCancellableEditor.newInstance(diffEditor, new SvnKitProgressCanceller(), null);
sourceRepository.diff(myTarget2.getURL(), rev, rev, null, true, true, false, new ISVNReporterBaton() {
public void report(ISVNReporter reporter) throws SVNException {
reporter.setPath("", null, rev, false);
reporter.finishReport();
}
}, cancellableEditor);
return diffEditor.getChangesMap().values();
}
finally {
sourceRepository.closeSession();
if (targetRepository != null) {
targetRepository.closeSession();
}
}
}
private Collection<Change> run17Diff() throws SVNException {
final Info info1 = myVcs.getInfo(myTarget2.getFile(), SVNRevision.HEAD);
if (info1 == null) {
SVNErrorMessage err =
SVNErrorMessage.create(SVNErrorCode.ENTRY_NOT_FOUND, "''{0}'' is not under version control", myTarget2);
SVNErrorManager.error(err, SVNLogType.WC);
}
else if (info1.getURL() == null) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", myTarget2);
SVNErrorManager.error(err, SVNLogType.WC);
}
final SVNReporter17 reporter17 =
new SVNReporter17(myTarget2.getFile(), new SVNWCContext(myVcs.getSvnKitManager().getSvnOptions(), new ISVNEventHandler() {
@Override
public void handleEvent(SVNEvent event, double progress) throws SVNException {
}
@Override
public void checkCancelled() throws SVNCancelException {
}
}), false, true, SVNDepth.INFINITY, false, false, true, false, SVNDebugLog.getDefaultLog());
SVNRepository repository = null;
SVNRepository repository2 = null;
try {
repository = myVcs.getSvnKitManager().createRepository(info1.getURL());
long rev = repository.getLatestRevision();
repository2 = myVcs.getSvnKitManager().createRepository(myTarget1.getURL());
SvnDiffEditor diffEditor = new SvnDiffEditor(myTarget2.getFile(), repository2, rev, true);
repository.diff(myTarget1.getURL(), rev, rev, null, true, SVNDepth.INFINITY, false, reporter17,
SVNCancellableEditor.newInstance(diffEditor, new SvnKitProgressCanceller(), null));
return diffEditor.getChangesMap().values();
}
finally {
if (repository != null) {
repository.closeSession();
}
if (repository2 != null) {
repository2.closeSession();
}
}
}
private Collection<Change> run16Diff() throws SVNException {
// here there's 1.6 copy so ok to use SVNWCAccess
final SVNWCAccess wcAccess = SVNWCAccess.newInstance(null);
wcAccess.setOptions(myVcs.getSvnKitManager().getSvnOptions());
SVNRepository repository = null;
SVNRepository repository2 = null;
try {
SVNAdminAreaInfo info = wcAccess.openAnchor(myTarget2.getFile(), false, SVNWCAccess.INFINITE_DEPTH);
File anchorPath = info.getAnchor().getRoot();
String target = "".equals(info.getTargetName()) ? null : info.getTargetName();
SVNEntry anchorEntry = info.getAnchor().getEntry("", false);
if (anchorEntry == null) {
SVNErrorMessage err =
SVNErrorMessage.create(SVNErrorCode.ENTRY_NOT_FOUND, "''{0}'' is not under version control", anchorPath);
SVNErrorManager.error(err, SVNLogType.WC);
}
else if (anchorEntry.getURL() == null) {
SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.ENTRY_MISSING_URL, "''{0}'' has no URL", anchorPath);
SVNErrorManager.error(err, SVNLogType.WC);
}
SVNURL anchorURL = anchorEntry.getSVNURL();
SVNReporter reporter = new SVNReporter(info, info.getAnchor().getFile(info.getTargetName()), false, true, SVNDepth.INFINITY,
false, false, true, SVNDebugLog.getDefaultLog());
repository = myVcs.getSvnKitManager().createRepository(anchorURL.toString());
long rev = repository.getLatestRevision();
repository2 =
myVcs.getSvnKitManager().createRepository((target == null) ? myTarget1.getURL() : myTarget1.getURL().removePathTail());
SvnDiffEditor diffEditor =
new SvnDiffEditor(target == null ? myTarget2.getFile() : myTarget2.getFile().getParentFile(), repository2, rev, true);
repository.diff(myTarget1.getURL(), rev, rev, target, true, true, false, reporter,
SVNCancellableEditor.newInstance(diffEditor, new SvnKitProgressCanceller(), null));
return diffEditor.getChangesMap().values();
}
finally {
wcAccess.close();
if (repository != null) {
repository.closeSession();
}
if (repository2 != null) {
repository2.closeSession();
}
}
}
}
}