Commit 3e4d3dfb authored by Florent Angebault's avatar Florent Angebault

OTRS#2016093010000012 : svn diff before svn summarize + ignore ancestry.

parent bd63c557
......@@ -11,26 +11,13 @@
package org.eclipse.team.svn.ui.operation;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.CompareEditorInput;
......@@ -48,7 +35,6 @@ import org.eclipse.team.svn.core.connector.ISVNConnector;
import org.eclipse.team.svn.core.connector.ISVNDiffStatusCallback;
import org.eclipse.team.svn.core.connector.ISVNEntryStatusCallback;
import org.eclipse.team.svn.core.connector.SVNChangeStatus;
import org.eclipse.team.svn.core.connector.SVNConnectorException;
import org.eclipse.team.svn.core.connector.SVNDepth;
import org.eclipse.team.svn.core.connector.SVNDiffStatus;
import org.eclipse.team.svn.core.connector.SVNEntry;
......@@ -263,8 +249,6 @@ public class CompareResourcesInternalOperation extends AbstractActionOperation {
this.protectStep(new IUnprotectedOperation() {
public void run(IProgressMonitor monitor) throws Exception {
final Map<SVNDiffStatus, IResource> localChangesMap = new LinkedHashMap<SVNDiffStatus, IResource>();
final Map<SVNDiffStatus, IResource> remoteChangesMap = new LinkedHashMap<SVNDiffStatus, IResource>();
final IContainer compareRoot =
CompareResourcesInternalOperation.this.local instanceof ILocalFolder ?
(IContainer)CompareResourcesInternalOperation.this.local.getResource() :
......@@ -273,7 +257,10 @@ public class CompareResourcesInternalOperation extends AbstractActionOperation {
SVNEntryRevisionReference refPrev = new SVNEntryRevisionReference(FileUtility.getWorkingCopyPath(CompareResourcesInternalOperation.this.local.getResource()), null, SVNRevision.WORKING);
final SVNEntryRevisionReference refNext = SVNUtility.getEntryRevisionReference(CompareResourcesInternalOperation.this.remote);
proxy.diffStatusTwo(refPrev, refNext, SVNDepth.INFINITY, ISVNConnector.Options.NONE, null, new ISVNDiffStatusCallback() {
// does not work with BASE working copy revision (not implemented yet exception)
final FakeOutputStream diffPathCollector = new FakeOutputStream();
proxy.diffTwo(refPrev, refNext, rootPath.toFile().getAbsolutePath(), diffPathCollector, SVNDepth.INFINITY, ISVNConnector.Options.IGNORE_ANCESTRY, null, ISVNConnector.DiffOptions.NONE, new SVNProgressMonitor(CompareResourcesInternalOperation.this, monitor, null, false));
proxy.diffStatusTwo(refPrev, refNext, SVNDepth.INFINITY, ISVNConnector.Options.IGNORE_ANCESTRY, null, new ISVNDiffStatusCallback() {
public void next(SVNDiffStatus status) {
IPath tPath = new Path(status.pathPrev);
tPath = tPath.removeFirstSegments(rootPath.segmentCount());
......@@ -282,92 +269,74 @@ public class CompareResourcesInternalOperation extends AbstractActionOperation {
resource = status.nodeKind == SVNEntry.Kind.FILE ? compareRoot.getFile(tPath) : compareRoot.getFolder(tPath);
}
ILocalResource local = SVNRemoteStorage.instance().asLocalResource(resource);
if (!IStateFilter.SF_NOTEXISTS.accept(local)
&& IStateFilter.SF_ANY_CHANGE.accept(local)) {
localChangesMap.put(status, resource);
} else
if (!IStateFilter.SF_ANY_CHANGE.accept(local) || IStateFilter.SF_NOTEXISTS.accept(local)) {
// it seems the status is calculated relatively to the working copy, so deletion and addition changes should actually be reversed
int change =
status.textStatus == SVNDiffStatus.Kind.ADDED ?
SVNDiffStatus.Kind.DELETED :
(status.textStatus == SVNDiffStatus.Kind.DELETED ? SVNDiffStatus.Kind.ADDED : status.textStatus);
String pathPrev = CompareResourcesInternalOperation.this.ancestor.getUrl() + status.pathNext.substring(refNext.path.length());
SVNDiffStatus newStatus = new SVNDiffStatus(pathPrev, status.pathNext, status.nodeKind, change, status.propStatus);
remoteChangesMap.put(newStatus, resource);
// String pathPrev = CompareResourcesInternalOperation.this.ancestor.getUrl() + status.pathNext.substring(refNext.path.length());
// TODO could there be a case when relative paths are reported? If so - looks like a bug to me...
String pathPrev = status.pathNext.startsWith(refNext.path) ? status.pathNext.substring(refNext.path.length()) : status.pathNext;
if (!diffPathCollector.contains(pathPrev)) {
System.out.println("ignoring path because it has no real differences: " + pathPrev);
} else {
pathPrev = CompareResourcesInternalOperation.this.ancestor.getUrl() + pathPrev;
remoteChanges.add(new SVNDiffStatus(pathPrev, status.pathNext, status.nodeKind, change, status.propStatus));
}
}
}
}, new SVNProgressMonitor(CompareResourcesInternalOperation.this, monitor, null, false));
{
removeFalseDiffs(localChangesMap, proxy);
removeFalseDiffs(remoteChangesMap, proxy);
localChanges.addAll(localChangesMap.keySet());
remoteChanges.addAll(remoteChangesMap.keySet());
}
}
}, monitor, 100, 40);
}
/**
* In some cases, SVNDiffStatus reports files as being different although there are no real difference.
* This method removes such false positive result.
*/
private void removeFalseDiffs(Map<SVNDiffStatus, IResource> changes, ISVNConnector proxy) {
Iterator<SVNDiffStatus> itChanges = changes.keySet().iterator();
while (itChanges.hasNext()) {
SVNDiffStatus status = itChanges.next();
IResource resource = changes.get(status);
if (status.nodeKind == SVNEntry.Kind.FILE
&& !_reallyDifferent(proxy, resource, new SVNEntryRevisionReference(status.pathNext))) {
itChanges.remove();
System.out.format("Diff entry removed because no real differences were found: '%s' vs. '%s'%n", status.pathPrev, status.pathNext);
}
}
}
private boolean _reallyDifferent(ISVNConnector proxy, IResource localResource, SVNEntryRevisionReference remoteFile) {
try {
// 1. Get remote file content
OutputStream stream = new ByteArrayOutputStream();
String right = "";
try {
proxy.streamFileContent(remoteFile, 1000, stream, null);
right = stream.toString();
} catch (SVNConnectorException sce) {
// remote resource does not exist (probably)
right = "";
}
right = right.replace("\n", "").replace("\r", "").trim();
/**
* Workaround.
*
* This {@link OutputStream} parses the output of "svn diff" and only catches paths from
* the lines beginning with "Index: ".
*
* @author fangebault
*/
private static class FakeOutputStream extends OutputStream {
// 2. Get local file content
String left = "";
File loc = localResource.getRawLocation().toFile();
if (loc.exists()) {
InputStream in = new FileInputStream(loc);
BufferedReader r = new BufferedReader(new InputStreamReader(in));
char[] buf = new char[1024];
StringWriter w = new StringWriter();
int readCount = -1;
while (-1 != (readCount = r.read(buf))) {
w.write(buf, 0, readCount);
boolean lineStart = true;
boolean indexLine = false;
Set<String> paths = new LinkedHashSet<String>();
StringBuilder w = new StringBuilder();
@Override
public void write(int b) throws IOException {
char c = (char) b;
if (c == 'I' && this.lineStart) {
this.indexLine = true;
this.w.append(c);
} else if (c == '\n' || c == '\r') {
if (this.indexLine) {
String path = "/" + this.w.toString().substring("Index: ".length());
this.paths.add(path);
this.w.replace(0, this.w.length(), "");
}
this.lineStart = true;
this.indexLine = false;
} else {
this.lineStart = false;
if (this.indexLine) {
this.w.append(c);
}
left = w.toString();
}
left = left.replace("\n", "").replace("\r", "").trim();
// 3. Compare contents
if (left.equals(right)) {
return false;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
}
private Set<String> getPaths() {
return this.paths;
}
public boolean contains(String path) {
return this.getPaths().contains(path);
}
}
protected boolean compareResultOK(CompareEditorInput input) {
final Shell shell = UIMonitorUtility.getShell();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment