Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Delaigue2014-09-30 11:07:10 -0400
committerMatthias Sohn2016-03-25 18:53:33 -0400
commit88ab5e65fb3bd9d734526626efabd17971e35076 (patch)
tree71be633797f299c99dd6dc2b278455bc07c7ce15
parenta9973d46ed85a1e7956e9ceef4fad93aa49dfa90 (diff)
downloadegit-88ab5e65fb3bd9d734526626efabd17971e35076.tar.gz
egit-88ab5e65fb3bd9d734526626efabd17971e35076.tar.xz
egit-88ab5e65fb3bd9d734526626efabd17971e35076.zip
Distinguish unchanged/deleted files in logical models
Change-Id: Iba967102da2118fcf795bdd3e4bc56c9ef8abec2 Also-by: Arthur Daussy <arthur.daussy@obeo.fr> Signed-off-by: Laurent Delaigue <laurent.delaigue@obeo.fr>
-rw-r--r--org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeTest.java152
-rw-r--r--org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/TestRepository.java16
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitSyncCache.java6
-rw-r--r--org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/ThreeWayDiffEntry.java96
4 files changed, 258 insertions, 12 deletions
diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeTest.java
index ec2398121..7c0614c21 100644
--- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeTest.java
+++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/synchronize/GitResourceVariantTreeTest.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2010, Dariusz Luksza <dariusz@luksza.org>
+ * Copyright (C) 2010, 2015 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
@@ -14,15 +14,22 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.mapping.ResourceMapping;
+import org.eclipse.core.resources.mapping.ResourceMappingContext;
+import org.eclipse.core.resources.mapping.ResourceTraversal;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.egit.core.op.ConnectProviderOperation;
import org.eclipse.egit.core.project.RepositoryMapping;
@@ -31,12 +38,15 @@ import org.eclipse.egit.core.synchronize.dto.GitSynchronizeDataSet;
import org.eclipse.egit.core.test.GitTestCase;
import org.eclipse.egit.core.test.TestProject;
import org.eclipse.egit.core.test.TestRepository;
+import org.eclipse.egit.core.test.models.SampleModelProvider;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IType;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.team.core.variants.IResourceVariant;
+import org.eclipse.team.core.variants.IResourceVariantTree;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -220,6 +230,146 @@ public class GitResourceVariantTreeTest extends GitTestCase {
assertNull(grvt.getResourceVariant(mainJava));
}
+ @Test
+ public void shouldNotReturnNullOnSameResouceVariant() throws Exception {
+ String modifiedFileName = "changingFile."
+ + SampleModelProvider.SAMPLE_FILE_EXTENSION;
+ String unchangedFileName = "notChangingFile."
+ + SampleModelProvider.SAMPLE_FILE_EXTENSION;
+ String removedFileName = "toBeRemovedFile."
+ + SampleModelProvider.SAMPLE_FILE_EXTENSION;
+
+ File modifiedFile = testRepo.createFile(iProject, modifiedFileName);
+ File unchangedFile = testRepo.createFile(iProject, unchangedFileName);
+ File removedFile = testRepo.createFile(iProject, removedFileName);
+
+ testRepo.appendFileContent(modifiedFile, "My content is changing");
+ testRepo.appendFileContent(unchangedFile, "My content is constant");
+ testRepo.appendFileContent(removedFile, "I will be removed");
+
+ IFile iModifiedFile = testRepo.getIFile(iProject, modifiedFile);
+ IFile iUnchangedFile = testRepo.getIFile(iProject, unchangedFile);
+ IFile iRemovedFile = testRepo.getIFile(iProject, removedFile);
+
+ testRepo.trackAllFiles(iProject);
+
+ RevCommit firstCommit = testRepo.commit("C1");
+
+ testRepo.appendFileContent(modifiedFile, " My content has changed");
+ testRepo.track(modifiedFile);
+ testRepo.removeFromIndex(removedFile);
+
+ RevCommit secondCommit = testRepo.commit("C2");
+
+ //@formatter:off
+ // History (X means has changed)
+ //------------------------------------------------------------
+ // files C1 [HEAD] C2
+ // changingFile.sample |-----X----------|-------X-------|->
+ // notChangingFile.sample |-----X----------|---------------|->
+ // toBeRemovedFile.sample |-----X----------|-------X-------|->
+ //-------------------------------------------------------------
+ //@formatter:on
+
+ testRepo.checkoutBranch(firstCommit.getName());
+
+ iProject.refreshLocal(IResource.DEPTH_INFINITE,
+ new NullProgressMonitor());
+
+ // Now synchronize the two commits using our logical model provider
+ SampleModelProvider provider = new SampleModelProvider();
+ // Get the affected resources
+ ResourceMapping[] mappings = provider
+ .getMappings(iModifiedFile,
+ ResourceMappingContext.LOCAL_CONTEXT,
+ new NullProgressMonitor());
+
+ Set<IResource> includedResource = collectResources(mappings);
+ Set<IResource> expectedIncludedResources = new HashSet<IResource>();
+ expectedIncludedResources.add(iModifiedFile);
+ expectedIncludedResources.add(iUnchangedFile);
+ expectedIncludedResources.add(iRemovedFile);
+
+ assertEquals(expectedIncludedResources, includedResource);
+
+ // Synchronize the data
+ final GitSynchronizeData data = new GitSynchronizeData(
+ testRepo.getRepository(), firstCommit.getName(),
+ secondCommit.getName(), true, includedResource);
+ GitSynchronizeDataSet gitSynchDataSet = new GitSynchronizeDataSet(data);
+ final GitResourceVariantTreeSubscriber subscriber = new GitResourceVariantTreeSubscriber(
+ gitSynchDataSet);
+ subscriber.init(new NullProgressMonitor());
+
+ IResourceVariantTree sourceVariantTree = subscriber.getSourceTree();
+ assertNotNull(sourceVariantTree);
+
+ IResourceVariantTree remoteVariantTree = subscriber.getRemoteTree();
+ assertNotNull(remoteVariantTree);
+
+ // In the use case in which the file has been deleted the source variant is
+ // not null whereas the remote variant is null.It seems quite logic.
+ // However in the second use case we have the same result, the source variant is
+ // not null whereas the remote is null. In both cases the null value does
+ // not mean the same thing. In the first case, the null value means that
+ // the resource is no longer in the repository and in the second the
+ // null value means there is no change between the two versions.
+ // Using these values I am not able to distinguish both case.
+ // It is in contradiction with test #shouldReturnNullResourceVariant2()
+ // and test #shoulReturnSameResourceVariant(). However I haven't found
+ // another way to handle this case. Maybe something can be
+ // done with ThreeWayDiffEntry.scan(tw) to force including in the cache
+ // some entry even if they have not changed. For example,
+ // ThreeWayDiffEntry.scan(tw,includedSource) or maybe try preventing the variant
+ // tree to return null by walking throught the repository and looking for the file...
+
+ IResourceVariant unchangedSourceVariant = sourceVariantTree
+ .getResourceVariant(iUnchangedFile);
+ IResourceVariant unchangedRemoteVariant = remoteVariantTree
+ .getResourceVariant(iUnchangedFile);
+
+ assertNotNull(unchangedSourceVariant);
+ assertNotNull(unchangedRemoteVariant);
+
+ IResourceVariant removedSourceVariant = sourceVariantTree
+ .getResourceVariant(iRemovedFile);
+ IResourceVariant removedRemoteVariant = remoteVariantTree
+ .getResourceVariant(iRemovedFile);
+
+ assertNotNull(removedSourceVariant);
+ assertNull(removedRemoteVariant);
+
+ GitSubscriberResourceMappingContext context = new GitSubscriberResourceMappingContext(subscriber, gitSynchDataSet);
+ assertFalse(context.hasLocalChange(iUnchangedFile,
+ new NullProgressMonitor()));
+ assertFalse(context.hasRemoteChange(iUnchangedFile,
+ new NullProgressMonitor()));
+
+ assertFalse(context.hasLocalChange(iModifiedFile,
+ new NullProgressMonitor()));
+ assertTrue(context.hasRemoteChange(iModifiedFile,
+ new NullProgressMonitor()));
+
+ assertFalse(context.hasLocalChange(iRemovedFile,
+ new NullProgressMonitor()));
+ assertTrue(context.hasRemoteChange(iRemovedFile,
+ new NullProgressMonitor()));
+ }
+
+ private static Set<IResource> collectResources(ResourceMapping[] mappings)
+ throws CoreException {
+ final Set<IResource> resources = new HashSet<IResource>();
+ ResourceMappingContext context = ResourceMappingContext.LOCAL_CONTEXT;
+ for (ResourceMapping mapping : mappings) {
+ ResourceTraversal[] traversals = mapping.getTraversals(context,
+ new NullProgressMonitor());
+ for (ResourceTraversal traversal : traversals) {
+ resources.addAll(Arrays.asList(traversal.getResources()));
+ }
+ }
+ return resources;
+ }
+
/**
* Create and commit Main.java file in master branch, then create branch
* "test" checkout nearly created branch and modify Main.java file.
diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/TestRepository.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/TestRepository.java
index 62ecd00fe..1eccf133f 100644
--- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/TestRepository.java
+++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/TestRepository.java
@@ -3,6 +3,7 @@
* Copyright (C) 2010, Jens Baumgart <jens.baumgart@sap.com>
* Copyright (C) 2012, Robin Stocker <robin@nibor.org>
* Copyright (C) 2012, Fran├žois Rey <eclipse.org_@_francois_._rey_._name>
+ * Copyright (C) 2015, Obeo
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -362,6 +363,21 @@ public class TestRepository {
}
/**
+ * Remove the given resource form the index.
+ *
+ * @param file
+ * @throws NoFilepatternException
+ * @throws GitAPIException
+ */
+ public void removeFromIndex(File file) throws NoFilepatternException, GitAPIException {
+ String repoPath = getRepoRelativePath(new Path(file.getPath())
+ .toString());
+ try (Git git = new Git(repository)) {
+ git.rm().addFilepattern(repoPath).call();
+ }
+ }
+
+ /**
* Appends content to end of given file.
*
* @param file
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitSyncCache.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitSyncCache.java
index c34177c9a..af7d7ef99 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitSyncCache.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/GitSyncCache.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2011, 2013 Dariusz Luksza <dariusz@luksza.org> and others.
+ * Copyright (C) 2011, 2015 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
@@ -152,8 +152,8 @@ class GitSyncCache {
tw.addTree(dci);
fti.setDirCacheIterator(tw, 3);
}
- List<ThreeWayDiffEntry> diffEntrys = ThreeWayDiffEntry.scan(tw);
-
+ List<ThreeWayDiffEntry> diffEntrys = ThreeWayDiffEntry
+ .scan(tw, gsd);
for (ThreeWayDiffEntry diffEntry : diffEntrys)
repoCache.addMember(diffEntry);
} catch (Exception e) {
diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/ThreeWayDiffEntry.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/ThreeWayDiffEntry.java
index d3175e3e6..7adaff169 100644
--- a/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/ThreeWayDiffEntry.java
+++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/synchronize/ThreeWayDiffEntry.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (C) 2011, Dariusz Luksza <dariusz@luksza.org>
+ * Copyright (C) 2011, 2015 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
@@ -10,8 +10,16 @@ package org.eclipse.egit.core.synchronize;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.egit.core.synchronize.dto.GitSynchronizeData;
+import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.MutableObjectId;
@@ -64,20 +72,45 @@ public final class ThreeWayDiffEntry {
}
/**
- * Converts the TreeWalk into TreeWayDiffEntry headers.
+ * Convert the TreeWalk into {@link ThreeWayDiffEntry} instances.
*
* @param walk
- * the TreeWalk to walk through. Must have exactly three trees in
- * this order: local, base and remote and can't be recursive.
- * @return headers describing the changed file.
+ * the TreeWalk to walk through. Must have 3 or 4 trees in this
+ * order: local, base, remote, optionally a DirCacheIterator, and
+ * can't be recursive.
+ * @return A list, never null but possibly empty, of
+ * {@link ThreeWayDiffEntry} describing the changed file.
* @throws IOException
* the repository cannot be accessed.
* @throws IllegalArgumentException
- * when {@code walk} doen't have exactly three trees, or when
+ * when {@code walk} doen't have 3 or 4 trees, or when
* {@code walk} is recursive
*/
- public static List<ThreeWayDiffEntry> scan(TreeWalk walk)
+ public static @NonNull List<ThreeWayDiffEntry> scan(TreeWalk walk)
throws IOException {
+ return scan(walk, null);
+ }
+
+ /**
+ * Convert the TreeWalk into {@link ThreeWayDiffEntry} instances.
+ *
+ * @param walk
+ * the TreeWalk to walk through. Must have 3 or 4 trees in this
+ * order: local, base, remote, optionally a DirCacheIterator, and
+ * can't be recursive.
+ * @param gsd
+ * The {@link GitSynchronizeData} that contains info about the
+ * synchronization configuration and scope.
+ * @return A list, never null but possibly empty, of
+ * {@link ThreeWayDiffEntry} describing the changed file.
+ * @throws IOException
+ * the repository cannot be accessed.
+ * @throws IllegalArgumentException
+ * when {@code walk} doen't have 3 or 4 trees, or when
+ * {@code walk} is recursive
+ */
+ public static @NonNull List<ThreeWayDiffEntry> scan(TreeWalk walk,
+ GitSynchronizeData gsd) throws IOException {
if (walk.getTreeCount() != 3 && walk.getTreeCount() != 4)
throw new IllegalArgumentException(
"TreeWalk need to have three or four trees"); //$NON-NLS-1$
@@ -87,6 +120,7 @@ public final class ThreeWayDiffEntry {
List<ThreeWayDiffEntry> r = new ArrayList<ThreeWayDiffEntry>();
MutableObjectId idBuf = new MutableObjectId();
+ NeedEntry needEntry = new NeedEntry(gsd);
while (walk.next()) {
ThreeWayDiffEntry e = new ThreeWayDiffEntry();
@@ -101,8 +135,15 @@ public final class ThreeWayDiffEntry {
boolean localSameAsBase = e.localId.equals(e.baseId);
if (!A_ZERO.equals(e.localId) && localSameAsBase
- && e.baseId.equals(e.remoteId))
+ && e.baseId.equals(e.remoteId)) {
+ if (needEntry.apply(walk.getPathString())) {
+ e.direction = Direction.INCOMING;
+ e.changeType = ChangeType.IN_SYNC;
+ e.path = walk.getPathString();
+ r.add(e);
+ }
continue;
+ }
e.path = walk.getPathString();
boolean localIsMissing = walk.getFileMode(0) == FileMode.MISSING;
@@ -223,4 +264,43 @@ public final class ThreeWayDiffEntry {
return buf.toString();
}
+ private static class NeedEntry {
+ private final GitSynchronizeData gsd;
+
+ private Set<String> paths;
+
+ public NeedEntry(GitSynchronizeData gsd) {
+ this.gsd = gsd;
+ }
+
+ boolean apply(String pathString) {
+ if (gsd == null) {
+ // This means that all paths must be included
+ return true;
+ }
+ if (paths == null) {
+ initPaths();
+ }
+ return paths.contains(pathString);
+ }
+
+ private void initPaths() {
+ Set<IResource> resources = gsd.getIncludedResources();
+ if (resources != null && !resources.isEmpty()) {
+ paths = new HashSet<String>(resources.size());
+ final Path repositoryPath = new Path(gsd.getRepository()
+ .getWorkTree().getAbsolutePath());
+ for (IResource resource : gsd.getIncludedResources()) {
+ IPath resourceLocation = resource.getLocation();
+ if (resourceLocation != null) {
+ paths.add(resourceLocation.makeRelativeTo(
+ repositoryPath).toString());
+ }
+ }
+ } else {
+ paths = Collections.emptySet();
+ }
+ }
+ }
+
}

Back to the top