summaryrefslogtreecommitdiffstatsabout
diff options
context:
space:
mode:
authorLaurent Goubet2013-03-15 06:26:42 (EDT)
committer Matthias Sohn2013-04-13 19:07:15 (EDT)
commitf2d4ffcfc3fc57e81f7629df4267b91574761aea (patch)
tree38300a802825295628775de4d2f46b9c906f77f9
parent3c3ad5342f07fd37a2e9b1167fb6d49db678813d (diff)
downloadegit-f2d4ffcfc3fc57e81f7629df4267b91574761aea.zip
egit-f2d4ffcfc3fc57e81f7629df4267b91574761aea.tar.gz
egit-f2d4ffcfc3fc57e81f7629df4267b91574761aea.tar.bz2
Use the source revision instead of local data for synchronizationsrefs/changes/90/11190/6
EGit allows for comparisons with three remote revisions (notably through "synchronize with each other" with two branches selected in the repository explorer). However, Team always uses the local data as the "source" (or left) side of a comparison. This patch allows us to use the actual source commit instead of the local file when needed. This also changes GitModelSynchronizeParticipant#asCompareInput() since we can use the cached content fetched by the subscriber context instead of re-fetching it from the remote. CQ: 7175 Bug: 403363 Change-Id: I23e0f1e75b9c6d476f8ed5a24deac7cc7b64dd42 Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
-rwxr-xr-xorg.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriberTest.java51
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java3
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties1
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitLocalResourceVariant.java60
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTree.java6
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriber.java280
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitSourceResourceVariantTree.java72
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java3
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/GitModelSynchronizeParticipant.java111
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties1
10 files changed, 517 insertions, 71 deletions
diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriberTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriberTest.java
index 186a527..501d9e2 100755
--- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriberTest.java
+++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriberTest.java
@@ -74,14 +74,34 @@ public class GitResourceVariantTreeSubscriberTest extends GitTestCase {
}
@Test
+ public void testSyncLocalAndBranch() throws Exception {
+ // Note that HEAD is on master
+ GitResourceVariantTreeSubscriber grvts = createGitResourceVariantTreeSubscriber(
+ Constants.HEAD, BRANCH, true);
+ grvts.init(new NullProgressMonitor());
+
+ IResourceVariant actualSource = getSourceVariant(grvts, changedFile,
+ true);
+ IResourceVariant actualBase = getBaseVariant(grvts, changedFile);
+ IResourceVariant actualRemote = getRemoteVariant(grvts, changedFile);
+
+ assertVariantIsLocal(actualSource, changedFile);
+ assertVariantMatchCommit(actualBase, initialCommit);
+ assertVariantMatchCommit(actualRemote, commitBranch);
+ }
+
+ @Test
public void testSyncMasterAndBranch() throws Exception {
GitResourceVariantTreeSubscriber grvts = createGitResourceVariantTreeSubscriber(
- MASTER, BRANCH);
+ MASTER, BRANCH, false);
grvts.init(new NullProgressMonitor());
+ IResourceVariant actualSource = getSourceVariant(grvts, changedFile,
+ false);
IResourceVariant actualBase = getBaseVariant(grvts, changedFile);
IResourceVariant actualRemote = getRemoteVariant(grvts, changedFile);
+ assertVariantMatchCommit(actualSource, commitMaster);
assertVariantMatchCommit(actualBase, initialCommit);
assertVariantMatchCommit(actualRemote, commitBranch);
}
@@ -89,16 +109,24 @@ public class GitResourceVariantTreeSubscriberTest extends GitTestCase {
@Test
public void testSyncBranchAndMaster() throws Exception {
GitResourceVariantTreeSubscriber grvts = createGitResourceVariantTreeSubscriber(
- BRANCH, MASTER);
+ BRANCH, MASTER, false);
grvts.init(new NullProgressMonitor());
+ IResourceVariant actualSource = getSourceVariant(grvts, changedFile,
+ false);
IResourceVariant actualBase = getBaseVariant(grvts, changedFile);
IResourceVariant actualRemote = getRemoteVariant(grvts, changedFile);
+ assertVariantMatchCommit(actualSource, commitBranch);
assertVariantMatchCommit(actualBase, initialCommit);
assertVariantMatchCommit(actualRemote, commitMaster);
}
+ private void assertVariantIsLocal(IResourceVariant variant, IResource local) {
+ assertTrue(variant instanceof GitLocalResourceVariant);
+ assertEquals(local, ((GitLocalResourceVariant) variant).getResource());
+ }
+
private void assertVariantMatchCommit(IResourceVariant variant,
RevCommit commit) {
assertTrue(variant instanceof GitRemoteResource);
@@ -106,13 +134,28 @@ public class GitResourceVariantTreeSubscriberTest extends GitTestCase {
}
private GitResourceVariantTreeSubscriber createGitResourceVariantTreeSubscriber(
- String src, String dst) throws IOException {
+ String src, String dst, boolean includeLocal) throws IOException {
GitSynchronizeData gsd = new GitSynchronizeData(
- testRepo.getRepository(), src, dst, false);
+ testRepo.getRepository(), src, dst, includeLocal);
GitSynchronizeDataSet gsds = new GitSynchronizeDataSet(gsd);
return new GitResourceVariantTreeSubscriber(gsds);
}
+ private IResourceVariant getSourceVariant(
+ GitResourceVariantTreeSubscriber subscriber, IResource resource,
+ boolean includeLocal) throws TeamException {
+ IResourceVariantTree tree = subscriber.getSourceTree();
+ assertNotNull(tree);
+ assertTrue(tree instanceof GitSourceResourceVariantTree);
+ IResourceVariant resourceVariant = tree.getResourceVariant(resource);
+ assertNotNull(resourceVariant);
+ if (includeLocal)
+ assertTrue(resourceVariant instanceof GitLocalResourceVariant);
+ else
+ assertTrue(resourceVariant instanceof GitRemoteResource);
+ return resourceVariant;
+ }
+
private IResourceVariant getBaseVariant(
GitResourceVariantTreeSubscriber subscriber, IResource resource)
throws TeamException {
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
index f719917..0e481a0 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/CoreText.java
@@ -369,6 +369,9 @@ public class CoreText extends NLS {
public static String GitResourceVariantTree_fetchingVariant;
/** */
+ public static String GitResourceVariantTreeSubscriber_CouldNotFindSourceVariant;
+
+ /** */
public static String GitBranchResourceVariantTreeSubscriber_gitRepository;
/** */
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
index 8e4552b..d73a377 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/coretext.properties
@@ -168,6 +168,7 @@ GitProjectData_repositoryChangedJobName=Git repository changed job
GitProjectData_repositoryChangedTaskName=Git repository changed
GitResourceVariantTreeSubscriber_fetchTaskName=Fetching data from git repositories
+GitResourceVariantTreeSubscriber_CouldNotFindSourceVariant=Could not find source variant for resource: {0}
GitSyncObjectCache_noData=Cache doesn''t contain data for key: {0}
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitLocalResourceVariant.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitLocalResourceVariant.java
new file mode 100644
index 0000000..9e32888
--- /dev/null
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitLocalResourceVariant.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent Goubet <laurent.goubet@obeo.fr> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egit.core.synchronize;
+
+import java.util.Date;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IStorage;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.team.core.TeamException;
+import org.eclipse.team.core.variants.IResourceVariant;
+
+/**
+ * Used by the GitSourceVariantTree when it needs to include local changes.
+ * <p>
+ * Mimics Team's LocalResourceVariant.
+ * </p>
+ */
+class GitLocalResourceVariant implements IResourceVariant {
+ private final IResource resource;
+
+ GitLocalResourceVariant(IResource resource) {
+ this.resource = resource;
+ }
+
+ public byte[] asBytes() {
+ return getContentIdentifier().getBytes();
+ }
+
+ public String getContentIdentifier() {
+ return new Date(resource.getLocalTimeStamp()).toString();
+ }
+
+ public IStorage getStorage(IProgressMonitor monitor) throws TeamException {
+ if (resource.getType() == IResource.FILE)
+ return (IFile) resource;
+ return null;
+ }
+
+ public boolean isContainer() {
+ return resource.getType() != IResource.FILE;
+ }
+
+ public String getName() {
+ return resource.getName();
+ }
+
+ IResource getResource() {
+ return resource;
+ }
+}
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTree.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTree.java
index 189604d..87a87a4 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTree.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTree.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010 IBM Corporation and others.
+ * Copyright (c) 2010, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -8,6 +8,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Dariusz Luksza <dariusz@luksza.org>
+ * Laurent Goubet <laurent.goubet@obeo.fr> - 403363
*******************************************************************************/
package org.eclipse.egit.core.synchronize;
@@ -40,10 +41,9 @@ abstract class GitResourceVariantTree extends ResourceVariantTree {
private final GitSyncCache gitCache;
- private final GitSynchronizeDataSet gsds;
-
private final Map<IResource, IResourceVariant> cache = new WeakHashMap<IResource, IResourceVariant>();
+ protected final GitSynchronizeDataSet gsds;
GitResourceVariantTree(ResourceVariantByteStore store,
GitSyncCache gitCache, GitSynchronizeDataSet gsds) {
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriber.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriber.java
index dee4c3d..be87d38 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriber.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeSubscriber.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2010-2012 IBM Corporation and others.
+ * Copyright (c) 2010, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -9,6 +9,7 @@
* IBM Corporation - initial API and implementation
* Dariusz Luksza <dariusz@luksza.org>
* Fran├žois Rey - gracefully ignore linked resources
+ * Laurent Goubet <laurent.goubet@obeo.fr> - 403363
*******************************************************************************/
package org.eclipse.egit.core.synchronize;
@@ -22,23 +23,35 @@ import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.egit.core.Activator;
import org.eclipse.egit.core.CoreText;
+import org.eclipse.egit.core.internal.storage.WorkspaceFileRevision;
import org.eclipse.egit.core.project.RepositoryMapping;
import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData;
import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet;
+import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.osgi.util.NLS;
import org.eclipse.team.core.TeamException;
+import org.eclipse.team.core.diff.IDiff;
+import org.eclipse.team.core.diff.ITwoWayDiff;
+import org.eclipse.team.core.diff.provider.ThreeWayDiff;
+import org.eclipse.team.core.history.IFileRevision;
+import org.eclipse.team.core.mapping.provider.ResourceDiff;
import org.eclipse.team.core.synchronize.SyncInfo;
import org.eclipse.team.core.variants.IResourceVariant;
import org.eclipse.team.core.variants.IResourceVariantComparator;
import org.eclipse.team.core.variants.IResourceVariantTree;
import org.eclipse.team.core.variants.ResourceVariantTreeSubscriber;
+import org.eclipse.team.internal.core.mapping.ResourceVariantFileRevision;
+import org.eclipse.team.internal.core.mapping.SyncInfoToDiffConverter;
/**
*
@@ -46,6 +59,9 @@ import org.eclipse.team.core.variants.ResourceVariantTreeSubscriber;
public class GitResourceVariantTreeSubscriber extends
ResourceVariantTreeSubscriber {
+ /** A resource variant tree of the source branch. */
+ private GitSourceResourceVariantTree sourceTree;
+
/**
* A resource variant tree of the remote branch(es).
*/
@@ -62,6 +78,8 @@ public class GitResourceVariantTreeSubscriber extends
private GitSyncCache cache;
+ private GitSyncInfoToDiffConverter syncInfoConverter = new GitSyncInfoToDiffConverter();
+
/**
* @param data
*/
@@ -202,6 +220,7 @@ public class GitResourceVariantTreeSubscriber extends
gsds = data;
roots = null;
+ sourceTree = null;
baseTree = null;
remoteTree = null;
}
@@ -210,6 +229,8 @@ public class GitResourceVariantTreeSubscriber extends
* Disposes nested resources
*/
public void dispose() {
+ if (sourceTree != null)
+ sourceTree.dispose();
if (baseTree != null)
baseTree.dispose();
if (remoteTree != null)
@@ -218,6 +239,234 @@ public class GitResourceVariantTreeSubscriber extends
}
@Override
+ public IDiff getDiff(IResource resource) throws CoreException {
+ final GitSynchronizeData syncData = gsds.getData(resource.getProject());
+ if (syncData.shouldIncludeLocal())
+ return super.getDiff(resource);
+
+ SyncInfo info = getSyncInfo(resource);
+ if (info == null || info.getKind() == SyncInfo.IN_SYNC)
+ return null;
+ return syncInfoConverter.getDeltaFor(info);
+ }
+
+ /**
+ * The default implementation of SyncInfoToDiffConverter uses inaccurate
+ * information with regards to some of EGit features.
+ * <p>
+ * SyncInfoToDiffConverter#asFileRevision(IResourceVariant) is called when a
+ * user double-clicks a revision from the synchronize view (among others).
+ * However, the default implementation returns an IFileRevision with no
+ * comment, author or timestamp information (this can be observed by
+ * commenting this implementation out and launching
+ * HistoryTest#queryHistoryThroughTeam()).
+ * </p>
+ * <p>
+ * SyncInfoToDiffConverter#getDeltaFor(SyncInfo) had been originally thought
+ * by Team to be used for synchronizations that considered local changes.
+ * This is not always the case with EGit. For example, a user might try and
+ * compare two refs together from the Git repository explorer (right click >
+ * synchronize with each other). In such a case, the local files must not be
+ * taken into account (i.e. we must respect the value of our
+ * GitSynchronizeData#shouldIncludeLocal(). Most of the private methods here
+ * were copy/pasted from the super implementation.
+ * </p>
+ */
+ private class GitSyncInfoToDiffConverter extends SyncInfoToDiffConverter {
+ @Override
+ public IDiff getDeltaFor(SyncInfo info) {
+ if (info.getComparator().isThreeWay()) {
+ ITwoWayDiff local = getLocalDelta(info);
+ ITwoWayDiff remote = getRemoteDelta(info);
+ return new ThreeWayDiff(local, remote);
+ } else {
+ if (info.getKind() != SyncInfo.IN_SYNC) {
+ IResourceVariant remote = info.getRemote();
+ IResource local = info.getLocal();
+
+ int kind;
+ if (remote == null)
+ kind = IDiff.REMOVE;
+ else if (!local.exists())
+ kind = IDiff.ADD;
+ else
+ kind = IDiff.CHANGE;
+
+ if (local.getType() == IResource.FILE) {
+ IFileRevision after = asFileState(remote);
+ IFileRevision before = getLocalFileRevision((IFile) local);
+ return new ResourceDiff(info.getLocal(), kind, 0,
+ before, after);
+ }
+ // For folders, we don't need file states
+ return new ResourceDiff(info.getLocal(), kind);
+ }
+ return null;
+ }
+ }
+
+ private ITwoWayDiff getLocalDelta(SyncInfo info) {
+ int direction = SyncInfo.getDirection(info.getKind());
+ if (direction == SyncInfo.OUTGOING
+ || direction == SyncInfo.CONFLICTING) {
+ IResourceVariant ancestor = info.getBase();
+ IResource local = info.getLocal();
+
+ int kind;
+ if (ancestor == null)
+ kind = IDiff.ADD;
+ else if (!local.exists())
+ kind = IDiff.REMOVE;
+ else
+ kind = IDiff.CHANGE;
+
+ if (local.getType() == IResource.FILE) {
+ IFileRevision before = asFileState(ancestor);
+ IFileRevision after = getLocalFileRevision((IFile) local);
+ return new ResourceDiff(info.getLocal(), kind, 0, before,
+ after);
+ }
+ // For folders, we don't need file states
+ return new ResourceDiff(info.getLocal(), kind);
+
+ }
+ return null;
+ }
+
+ /**
+ * Depending on the Synchronize data, this will return either the local
+ * file or the "source" revision.
+ *
+ * @param local
+ * The local file.
+ * @return The file revision that should be considered for the local
+ * (left) side a delta
+ */
+ protected IFileRevision getLocalFileRevision(IFile local) {
+ final GitSynchronizeData data = gsds.getData(local.getProject());
+ if (data.shouldIncludeLocal())
+ return new WorkspaceFileRevision(local);
+
+ try {
+ return asFileState(getSourceTree().getResourceVariant(local));
+ } catch (TeamException e) {
+ String error = NLS
+ .bind(CoreText.GitResourceVariantTreeSubscriber_CouldNotFindSourceVariant,
+ local.getName());
+ Activator.logError(error, e);
+ // fall back to the working tree version
+ return new WorkspaceFileRevision(local);
+ }
+ }
+
+ /*
+ * copy-pasted from the private implementation in
+ * SyncInfoToDiffConverter
+ */
+ private ITwoWayDiff getRemoteDelta(SyncInfo info) {
+ int direction = SyncInfo.getDirection(info.getKind());
+ if (direction == SyncInfo.INCOMING
+ || direction == SyncInfo.CONFLICTING) {
+ IResourceVariant ancestor = info.getBase();
+ IResourceVariant remote = info.getRemote();
+
+ int kind;
+ if (ancestor == null)
+ kind = IDiff.ADD;
+ else if (remote == null)
+ kind = IDiff.REMOVE;
+ else
+ kind = IDiff.CHANGE;
+
+ // For folders, we don't need file states
+ if (info.getLocal().getType() == IResource.FILE) {
+ IFileRevision before = asFileState(ancestor);
+ IFileRevision after = asFileState(remote);
+ return new ResourceDiff(info.getLocal(), kind, 0, before,
+ after);
+ }
+
+ return new ResourceDiff(info.getLocal(), kind);
+ }
+ return null;
+ }
+
+ /*
+ * copy-pasted from the private implementation in
+ * SyncInfoToDiffConverter
+ */
+ private IFileRevision asFileState(final IResourceVariant variant) {
+ if (variant == null)
+ return null;
+ return asFileRevision(variant);
+ }
+
+ @Override
+ protected ResourceVariantFileRevision asFileRevision(
+ IResourceVariant variant) {
+ return new GitResourceVariantFileRevision(variant);
+ }
+ }
+
+ /**
+ * The default implementation of ResourceVariantFileRevision has no author,
+ * comment, timestamp... or any information that could be provided by the
+ * Git resource variant. This implementation uses the variant's information.
+ */
+ private class GitResourceVariantFileRevision extends
+ ResourceVariantFileRevision {
+ private final IResourceVariant variant;
+
+ public GitResourceVariantFileRevision(IResourceVariant variant) {
+ super(variant);
+ this.variant = variant;
+ }
+
+ @Override
+ public String getContentIdentifier() {
+ // Use the same ID as would CommitFileRevision
+ if (variant instanceof GitRemoteResource)
+ return ((GitRemoteResource) variant).getCommitId().getId()
+ .getName();
+
+ return super.getContentIdentifier();
+ }
+
+ @Override
+ public long getTimestamp() {
+ if (variant instanceof GitRemoteResource) {
+ final PersonIdent author = ((GitRemoteResource) variant)
+ .getCommitId().getAuthorIdent();
+ if (author != null)
+ return author.getWhen().getTime();
+ }
+
+ return super.getTimestamp();
+ }
+
+ @Override
+ public String getAuthor() {
+ if (variant instanceof GitRemoteResource) {
+ final PersonIdent author = ((GitRemoteResource) variant)
+ .getCommitId().getAuthorIdent();
+ if (author != null)
+ return author.getName();
+ }
+
+ return super.getAuthor();
+ }
+
+ @Override
+ public String getComment() {
+ if (variant instanceof GitRemoteResource)
+ return ((GitRemoteResource) variant).getCommitId()
+ .getFullMessage();
+
+ return super.getComment();
+ }
+ }
+
+ @Override
public String getName() {
return CoreText.GitBranchResourceVariantTreeSubscriber_gitRepository;
}
@@ -227,6 +476,35 @@ public class GitResourceVariantTreeSubscriber extends
return new GitResourceVariantComparator(gsds);
}
+ /**
+ * As opposed to the other repository providers, EGit allows for
+ * synchronization between three remote branches. This will return the
+ * "source" tree for such synchronization use cases.
+ *
+ * @return The source tree of this subscriber.
+ */
+ protected IResourceVariantTree getSourceTree() {
+ if (sourceTree == null)
+ sourceTree = new GitSourceResourceVariantTree(cache, gsds);
+
+ return sourceTree;
+ }
+
+ /**
+ * This can be used to retrieve the version of the given resource
+ * corresponding to the source tree of this subscriber.
+ *
+ * @param resource
+ * The resource for which we need a variant.
+ * @return The revision of the given resource cached in the source tree of
+ * this subscriber.
+ * @throws TeamException
+ */
+ public IFileRevision getSourceFileRevision(IFile resource)
+ throws TeamException {
+ return syncInfoConverter.getLocalFileRevision(resource);
+ }
+
@Override
protected IResourceVariantTree getBaseTree() {
if (baseTree == null)
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitSourceResourceVariantTree.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitSourceResourceVariantTree.java
new file mode 100644
index 0000000..a84719c
--- /dev/null
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitSourceResourceVariantTree.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Obeo.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Laurent Goubet <laurent.goubet@obeo.fr> - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.egit.core.synchronize;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData;
+import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.team.core.TeamException;
+import org.eclipse.team.core.variants.IResourceVariant;
+import org.eclipse.team.core.variants.SessionResourceVariantByteStore;
+
+class GitSourceResourceVariantTree extends GitResourceVariantTree {
+ public GitSourceResourceVariantTree(GitSyncCache cache,
+ GitSynchronizeDataSet gsds) {
+ super(new SessionResourceVariantByteStore(), cache, gsds);
+ }
+
+ @Override
+ protected IResourceVariant fetchVariant(IResource resource, int depth,
+ IProgressMonitor monitor) throws TeamException {
+ if (resource != null) {
+ GitSynchronizeData data = gsds.getData(resource.getProject());
+ if (data != null && data.shouldIncludeLocal())
+ return new GitLocalResourceVariant(resource);
+ }
+
+ return super.fetchVariant(resource, depth, monitor);
+ }
+
+ @Override
+ protected IResourceVariant[] fetchMembers(IResourceVariant variant,
+ IProgressMonitor progress) throws TeamException {
+ if (variant instanceof GitLocalResourceVariant
+ && ((GitLocalResourceVariant) variant).getResource() instanceof IContainer) {
+ IContainer resource = (IContainer) ((GitLocalResourceVariant) variant)
+ .getResource();
+ try {
+ IResource[] children = resource.members();
+ IResourceVariant[] result = new IResourceVariant[children.length];
+ for (int i = 0; i < children.length; i++)
+ result[i] = new GitLocalResourceVariant(children[i]);
+ return result;
+ } catch (CoreException e) {
+ // fall back to using remote data
+ }
+ }
+ return super.fetchMembers(variant, progress);
+ }
+
+ @Override
+ protected ObjectId getObjectId(ThreeWayDiffEntry diffEntry) {
+ return diffEntry.getLocalId().toObjectId();
+ }
+
+ @Override
+ protected RevCommit getCommitId(GitSynchronizeData gsd) {
+ return gsd.getSrcRevCommit();
+ }
+} \ No newline at end of file
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
index 94c2dae..4c00348 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/UIText.java
@@ -4758,6 +4758,9 @@ public class UIText extends NLS {
/** */
public static String GitModelSynchronizeParticipant_initialScopeName;
+ /** */
+ public static String GitModelSynchronizeParticipant_noCachedSourceVariant;
+
static {
initializeMessages(BUNDLE_NAME, UIText.class);
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/GitModelSynchronizeParticipant.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/GitModelSynchronizeParticipant.java
index f8937fa..26d8ea6 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/GitModelSynchronizeParticipant.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/synchronize/GitModelSynchronizeParticipant.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2010, 2012 Dariusz Luksza <dariusz@luksza.org> and others.
+ * Copyright (C) 2010, 2013 Dariusz Luksza <dariusz@luksza.org> and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -13,7 +13,6 @@
*******************************************************************************/
package org.eclipse.egit.ui.internal.synchronize;
-import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
@@ -24,6 +23,7 @@ import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.ResourceNode;
import org.eclipse.compare.structuremergeviewer.ICompareInput;
import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IEncodedStorage;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
@@ -47,20 +47,23 @@ import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData;
import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.UIPreferences;
+import org.eclipse.egit.ui.internal.FileRevisionTypedElement;
import org.eclipse.egit.ui.internal.UIText;
-import org.eclipse.egit.ui.internal.synchronize.compare.ComparisonDataSource;
-import org.eclipse.egit.ui.internal.synchronize.compare.GitCompareInput;
import org.eclipse.egit.ui.internal.synchronize.model.GitModelBlob;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.revwalk.RevCommit;
-import org.eclipse.jgit.treewalk.TreeWalk;
-import org.eclipse.jgit.treewalk.filter.PathFilter;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.team.core.TeamException;
+import org.eclipse.team.core.history.IFileRevision;
+import org.eclipse.team.core.mapping.ISynchronizationContext;
import org.eclipse.team.core.mapping.ISynchronizationScopeManager;
import org.eclipse.team.core.mapping.provider.MergeContext;
import org.eclipse.team.core.mapping.provider.SynchronizationScopeManager;
+import org.eclipse.team.core.subscribers.Subscriber;
+import org.eclipse.team.core.subscribers.SubscriberMergeContext;
+import org.eclipse.team.internal.ui.mapping.ResourceDiffCompareInput;
import org.eclipse.team.ui.TeamUI;
import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration;
import org.eclipse.team.ui.synchronize.ModelSynchronizeParticipant;
@@ -220,35 +223,48 @@ public class GitModelSynchronizeParticipant extends ModelSynchronizeParticipant
@Override
public ICompareInput asCompareInput(Object object) {
- ICompareInput compareInput = super.asCompareInput(object);
-
- if (compareInput != null) {
- // note, ResourceDiffCompareInput maybe returned from super;
- // it always has the local resource on the left side!
- // this is only ok if we are comparing with the working tree
-
- // handle file comparison outside working tree
- ITypedElement left = compareInput.getLeft();
- if (left instanceof ResourceNode) {
- // the left side can only be a resource node if
- // we are comparing against the local working tree
- IResource resource = ((ResourceNode) left).getResource();
- if (resource.getType() == IResource.FILE) {
- GitSynchronizeData gsd = gsds
- .getData(resource.getProject());
- if (gsd != null && !gsd.shouldIncludeLocal())
- return getFileFromGit(gsd, resource.getLocation());
+ final ICompareInput input = super.asCompareInput(object);
+ final ISynchronizationContext ctx = getContext();
+
+ if (input instanceof ResourceDiffCompareInput && ctx instanceof SubscriberMergeContext) {
+ // Team only considers local resources as "left"
+ // We'll use the cached data instead as left could be remote
+ final IResource resource = ((ResourceNode) input.getLeft())
+ .getResource();
+ final Subscriber subscriber = ((SubscriberMergeContext)ctx).getSubscriber();
+
+ if (resource instanceof IFile
+ && subscriber instanceof GitResourceVariantTreeSubscriber) {
+ try {
+ final IFileRevision revision = ((GitResourceVariantTreeSubscriber) subscriber)
+ .getSourceFileRevision((IFile) resource);
+ final ITypedElement newSource = new FileRevisionTypedElement(
+ revision,
+ getLocalEncoding(resource));
+ ((ResourceDiffCompareInput) input).setLeft(newSource);
+ } catch (TeamException e) {
+ // Keep the input from super as-is
+ String error = NLS
+ .bind(UIText.GitModelSynchronizeParticipant_noCachedSourceVariant,
+ resource.getName());
+ Activator.logError(error, e);
}
}
- } else {
- IResource resource = AdapterUtils.adapt(object, IResource.class);
- if (resource.getType() == IResource.FILE) {
- GitSynchronizeData gsd = gsds.getData(resource.getProject());
- return getFileFromGit(gsd, resource.getLocation());
- }
}
- return compareInput;
+ return input;
+ }
+
+ private static String getLocalEncoding(IResource resource) {
+ if (resource instanceof IEncodedStorage) {
+ IEncodedStorage es = (IEncodedStorage) resource;
+ try {
+ return es.getCharset();
+ } catch (CoreException e) {
+ Activator.logError(e.getMessage(), e);
+ }
+ }
+ return null;
}
@Override
@@ -334,37 +350,6 @@ public class GitModelSynchronizeParticipant extends ModelSynchronizeParticipant
mappings, context, true);
}
- private ICompareInput getFileFromGit(GitSynchronizeData gsd, IPath location) {
- Repository repo = gsd.getRepository();
- File workTree = repo.getWorkTree();
- String repoRelativeLocation = Repository.stripWorkDir(workTree,
- location.toFile());
-
- TreeWalk tw = new TreeWalk(repo);
- tw.setRecursive(true);
- tw.setFilter(PathFilter.create(repoRelativeLocation.toString()));
- RevCommit baseCommit = gsd.getSrcRevCommit();
- RevCommit remoteCommit = gsd.getDstRevCommit();
-
- try {
- int baseNth = tw.addTree(baseCommit.getTree());
- int remoteNth = tw.addTree(remoteCommit.getTree());
-
- if (tw.next()) {
- ComparisonDataSource baseData = new ComparisonDataSource(
- baseCommit, tw.getObjectId(baseNth));
- ComparisonDataSource remoteData = new ComparisonDataSource(
- remoteCommit, tw.getObjectId(remoteNth));
- return new GitCompareInput(repo, baseData, baseData,
- remoteData, repoRelativeLocation);
- }
- } catch (IOException e) {
- Activator.logError(e.getMessage(), e);
- }
-
- return null;
- }
-
private void restoreSynchronizationData(IMemento[] children) {
for (IMemento child : children) {
String containerPath = child.getString(CONTAINER_PATH_KEY);
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
index 7afd61d..9ce96ac 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
@@ -1672,3 +1672,4 @@ RepositoryStatistics_SpaceNeededOnFilesystem=Space needed on filesystem
RepositoryStatistics_PackedObjects=Packed objects
GitModelSynchronizeParticipant_initialScopeName=Git
+GitModelSynchronizeParticipant_noCachedSourceVariant=Could not locate cached source variant for resource: {0}