From 983c74084e5c5fd832f5ee0e2ebac464f850a8bd Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Wed, 16 Dec 2015 16:47:38 +0100 Subject: [PATCH] [performance] Remove ContainerTreeIterator and AdaptableFileTreeIterator Don't hook any extra Eclipse based iterators to jgit tree traversal: 1) Eclipse IResource API can't handle "unusual" links (unresolved or recursive), see bug 290318. This is a major functional deficiency for repositories which make use of links. 2) The assumption that Eclipse IResource API traverses the file system faster as java.io does not hold on Windows/Linux/Mac/NFS with modern (7+) Java, see bug 484498 comments 10 and 14,15,17. The opposite is true: especially on Linux the java.io access is considerably faster as IResource API or what the ContainerTreeIterator makes of it. AdaptableFileTreeIterator/ContainerTreeIterator use is replaced with default FileTreeIterator, tests adopted or removed. Bug: 484498 Change-Id: I026abee1706e6fbcd470cc7262b9fc1e59a7fe8b Signed-off-by: Andrey Loskutov Signed-off-by: Matthias Sohn --- .../core/test/AdaptableFileTreeIteratorTest.java | 88 ----- .../ContainerTreeIteratorResourceFilterTest.java | 250 ------------ .../egit/core/test/LinkedResourcesTest.java | 4 +- .../SubmoduleAndContainerTreeIteratorTest.java | 8 +- .../egit/core/AdaptableFileTreeIterator.java | 88 ----- .../eclipse/egit/core/ContainerTreeIterator.java | 429 --------------------- .../src/org/eclipse/egit/core/IteratorService.java | 21 +- .../eclipse/egit/core/op/AddToIndexOperation.java | 5 +- .../egit/ui/internal/dialogs/CommitDialog.java | 6 +- .../egit/ui/internal/dialogs/CompareTreeView.java | 11 +- .../ui/internal/merge/GitCompareEditorInput.java | 6 +- 11 files changed, 17 insertions(+), 899 deletions(-) delete mode 100644 org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/AdaptableFileTreeIteratorTest.java delete mode 100644 org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/ContainerTreeIteratorResourceFilterTest.java delete mode 100644 org.eclipse.egit.core/src/org/eclipse/egit/core/AdaptableFileTreeIterator.java delete mode 100644 org.eclipse.egit.core/src/org/eclipse/egit/core/ContainerTreeIterator.java diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/AdaptableFileTreeIteratorTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/AdaptableFileTreeIteratorTest.java deleted file mode 100644 index 3740339e9..000000000 --- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/AdaptableFileTreeIteratorTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2009, Tor Arne Vestbø - * - * 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 - *******************************************************************************/ -package org.eclipse.egit.core.test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.util.Collections; -import java.util.Set; - -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.egit.core.AdaptableFileTreeIterator; -import org.eclipse.egit.core.ContainerTreeIterator; -import org.eclipse.egit.core.op.ConnectProviderOperation; -import org.eclipse.egit.core.project.RepositoryMapping; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.storage.file.FileRepositoryBuilder; -import org.eclipse.jgit.treewalk.TreeWalk; -import org.eclipse.jgit.treewalk.WorkingTreeIterator; -import org.eclipse.jgit.treewalk.filter.PathFilterGroup; -import org.junit.Before; -import org.junit.Test; - -public class AdaptableFileTreeIteratorTest extends GitTestCase { - - private Repository repository; - - private File file; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - repository = FileRepositoryBuilder.create(gitDir); - repository.create(); - - file = new File(project.getProject().getLocation().toFile(), "a.txt"); - final Writer fileWriter = new OutputStreamWriter(new FileOutputStream( - file), "UTF-8"); - fileWriter.write("aaaaaaaaaaa"); - fileWriter.close(); - - final ConnectProviderOperation operation = new ConnectProviderOperation( - project.getProject(), gitDir); - operation.execute(null); - } - - @Test - public void testFileTreeToContainerAdaptation() throws IOException { - final IWorkspaceRoot root = project.getProject().getWorkspace() - .getRoot(); - - try (final TreeWalk treeWalk = new TreeWalk(repository)) { - treeWalk.addTree(new AdaptableFileTreeIterator(repository, root)); - treeWalk.setRecursive(true); - - final IFile eclipseFile = project.getProject() - .getFile(file.getName()); - final RepositoryMapping mapping = RepositoryMapping - .getMapping(eclipseFile); - final Set repositoryPaths = Collections - .singleton(mapping.getRepoRelativePath(eclipseFile)); - - assertEquals(1, repositoryPaths.size()); - treeWalk.setFilter( - PathFilterGroup.createFromStrings(repositoryPaths)); - - assertTrue(treeWalk.next()); - - final WorkingTreeIterator iterator = treeWalk.getTree(0, - WorkingTreeIterator.class); - assertTrue(iterator instanceof ContainerTreeIterator); - } - } -} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/ContainerTreeIteratorResourceFilterTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/ContainerTreeIteratorResourceFilterTest.java deleted file mode 100644 index 0389a70c6..000000000 --- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/ContainerTreeIteratorResourceFilterTest.java +++ /dev/null @@ -1,250 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2012, Robin Stocker - * - * 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 - *******************************************************************************/ -package org.eclipse.egit.core.test; - -import static org.eclipse.core.resources.IResourceFilterDescription.EXCLUDE_ALL; -import static org.eclipse.core.resources.IResourceFilterDescription.FILES; -import static org.eclipse.core.resources.IResourceFilterDescription.FOLDERS; -import static org.eclipse.core.resources.IResourceFilterDescription.INHERITABLE; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.eclipse.core.resources.FileInfoMatcherDescription; -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.Path; -import org.eclipse.egit.core.AdaptableFileTreeIterator; -import org.eclipse.egit.core.ContainerTreeIterator; -import org.eclipse.egit.core.op.ConnectProviderOperation; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.storage.file.FileRepositoryBuilder; -import org.eclipse.jgit.treewalk.AbstractTreeIterator; -import org.eclipse.jgit.treewalk.TreeWalk; -import org.junit.Before; -import org.junit.Test; - -/** - * Test for how {@link ContainerTreeIterator} handles filtered resources. - *

- * The tricky thing is that they are not returned from API like - * {@link IContainer#members()}. So we have to fall back to using an - * {@link AdaptableFileTreeIterator} if there may be resource filters active. - *

- * In case of nested projects where the subproject is filtered in the parent - * project with resource filters, we want the nested project to be walked with - * {@link ContainerTreeIterator} again. That is, it should "recover" from - * falling back to {@link AdaptableFileTreeIterator}. - */ -public class ContainerTreeIteratorResourceFilterTest extends GitTestCase { - - private Repository repository; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - repository = FileRepositoryBuilder.create(gitDir); - repository.create(); - - connectProject(project.getProject()); - } - - @Test - public void simpleNonInheritableFilter() throws Exception { - IProject p = project.getProject(); - IFile filtered = testUtils.addFileToProject(p, "filtered.txt", ""); - IFile unfiltered = testUtils.addFileToProject(p, "unfiltered.txt", ""); - assertTrue("IFile should exist before filtering.", filtered.exists()); - assertTrue("IFile should exist before filtering.", unfiltered.exists()); - - createFilter(p, EXCLUDE_ALL | FILES, "filtered.txt"); - assertFalse("IFile should no longer exist after filtering.", filtered.exists()); - assertTrue("IFile should exist after filtering.", unfiltered.exists()); - - List entries = walkTree(); - - assertThat(entries, hasItem(containerTreeEntry("Project-1/filtered.txt"))); - assertThat(entries, hasItem(containerTreeEntry("Project-1/unfiltered.txt"))); - } - - @Test - public void simpleNonInheritableFolderFilter() throws Exception { - IProject p = project.getProject(); - IFile filtered = testUtils.addFileToProject(p, "folder/filtered.txt", ""); - IFile unfiltered = testUtils.addFileToProject(p, "folder2/unfiltered.txt", ""); - - createFilter(p, EXCLUDE_ALL | FOLDERS, "folder"); - assertFalse("IFile should no longer exist after filtering.", filtered.exists()); - assertTrue("IFile should exist after filtering.", unfiltered.exists()); - - List entries = walkTree(); - - assertThat(entries, hasItem(adaptableFileTreeEntry("Project-1/folder/filtered.txt"))); - assertThat(entries, hasItem(containerTreeEntry("Project-1/folder2/unfiltered.txt"))); - } - - @Test - public void inheritableFilter() throws Exception { - IProject p = project.getProject(); - IFile filtered1 = testUtils.addFileToProject(p, "folder1/filtered.txt", ""); - IFile filtered2 = testUtils.addFileToProject(p, "folder1/folder2/filtered.txt", ""); - IFile unfiltered = testUtils.addFileToProject(p, "folder1/folder2/unfiltered.txt", ""); - - createFilter(p, EXCLUDE_ALL | FILES | INHERITABLE, "filtered.txt"); - assertFalse("IFile should no longer exist after filtering.", filtered1.exists()); - assertFalse("IFile should no longer exist after filtering.", filtered2.exists()); - assertTrue("IFile should exist after filtering.", unfiltered.exists()); - - List entries = walkTree(); - - assertThat(entries, hasItem(containerTreeEntry("Project-1/folder1/filtered.txt"))); - assertThat(entries, hasItem(containerTreeEntry("Project-1/folder1/folder2/filtered.txt"))); - assertThat(entries, hasItem(containerTreeEntry("Project-1/folder1/folder2/unfiltered.txt"))); - } - - @Test - public void directlyNestedProject() throws Exception { - IProject p = project.getProject(); - testUtils.addFileToProject(p, "file.txt", ""); - - TestProject testProject2 = new TestProject(true, "Project-1/Project-2"); - testUtils.addFileToProject(testProject2.getProject(), "project2.txt", ""); - - createFilter(p, EXCLUDE_ALL | FOLDERS, "Project-2"); - - List entries = walkTree(); - - assertThat(entries, hasItem(containerTreeEntry("Project-1/file.txt"))); - // Should be handled by container tree iterator because it exists, even - // when it's not returned by members() of Project-1. - assertThat(entries, hasItem(containerTreeEntry("Project-1/Project-2/project2.txt"))); - } - - @Test - public void nestedProject() throws Exception { - IProject p = project.getProject(); - testUtils.addFileToProject(p, "folder1/file.txt", ""); - testUtils.addFileToProject(p, "folder1/subfolder/filtered.txt", ""); - - TestProject testProject2 = new TestProject(true, "Project-1/folder1/subfolder/Project-2"); - connectProject(testProject2.getProject()); - IFile project2File = testUtils.addFileToProject(testProject2.getProject(), "project2.txt", ""); - assertThat(project2File.getProject(), is(testProject2.getProject())); - - createFilter(p.getFolder("folder1"), EXCLUDE_ALL | FOLDERS, "subfolder"); - assertFalse("IFolder should be filtered", - p.getFolder(new Path("folder1/subfolder")).exists()); - - List entries = walkTree(); - - assertThat(entries, hasItem(containerTreeEntry("Project-1/folder1/file.txt"))); - assertThat(entries, hasItem(adaptableFileTreeEntry("Project-1/folder1/subfolder/filtered.txt"))); - // Should be handled by container tree iterator again, because the project exists. - assertThat(entries, hasItem(containerTreeEntry("Project-1/folder1/subfolder/Project-2/project2.txt"))); - - testProject2.dispose(); - } - - private static void createFilter(IContainer container, int type, String regexFilterArguments) throws CoreException { - FileInfoMatcherDescription matcherDescription = new FileInfoMatcherDescription( - "org.eclipse.core.resources.regexFilterMatcher", - regexFilterArguments); - container.createFilter(type, matcherDescription, 0, null); - } - - private void connectProject(IProject p) throws CoreException { - final ConnectProviderOperation operation = new ConnectProviderOperation( - p, gitDir); - operation.execute(null); - } - - private List walkTree() throws IOException { - try (TreeWalk treeWalk = new TreeWalk(repository)) { - ContainerTreeIterator tree = new ContainerTreeIterator(repository, - project.getProject()); - int treeIndex = treeWalk.addTree(tree); - treeWalk.setRecursive(true); - List entries = new ArrayList(); - while (treeWalk.next()) { - AbstractTreeIterator it = treeWalk.getTree(treeIndex, - AbstractTreeIterator.class); - Entry entry = new Entry(treeWalk.getPathString(), - it.getClass()); - entries.add(entry); - } - return entries; - } - } - - private static Entry containerTreeEntry(String path) { - return new Entry(path, ContainerTreeIterator.class); - } - - private static Entry adaptableFileTreeEntry(String path) { - return new Entry(path, AdaptableFileTreeIterator.class); - } - - // Value object (case class). - private static class Entry { - private final String path; - private Class iteratorClass; - - public Entry(String path, Class iteratorClass) { - this.path = path; - this.iteratorClass = iteratorClass; - } - - @Override - public String toString() { - return path + " (" + iteratorClass.getSimpleName() + ")"; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((iteratorClass == null) ? 0 : iteratorClass.hashCode()); - result = prime * result + ((path == null) ? 0 : path.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Entry other = (Entry) obj; - if (iteratorClass == null) { - if (other.iteratorClass != null) - return false; - } else if (!iteratorClass.equals(other.iteratorClass)) - return false; - if (path == null) { - if (other.path != null) - return false; - } else if (!path.equals(other.path)) - return false; - return true; - } - } -} diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/LinkedResourcesTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/LinkedResourcesTest.java index aa713e213..670057ed8 100644 --- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/LinkedResourcesTest.java +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/LinkedResourcesTest.java @@ -25,10 +25,10 @@ import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.egit.core.Activator; -import org.eclipse.egit.core.ContainerTreeIterator; import org.eclipse.egit.core.GitProvider; import org.eclipse.egit.core.IteratorService; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.team.core.RepositoryProvider; import org.junit.After; @@ -176,7 +176,7 @@ public class LinkedResourcesTest { // Test iterator WorkingTreeIterator iterator = IteratorService .createInitialIterator(repository1.repository); - assertTrue(iterator instanceof ContainerTreeIterator); + assertTrue(iterator instanceof FileTreeIterator); while (!iterator.eof()) { assertFalse(iterator.getEntryPathString().startsWith("link2")); iterator.next(1); diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/SubmoduleAndContainerTreeIteratorTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/SubmoduleAndContainerTreeIteratorTest.java index fc49bb5e6..a3b4bdb6f 100644 --- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/SubmoduleAndContainerTreeIteratorTest.java +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/test/SubmoduleAndContainerTreeIteratorTest.java @@ -17,13 +17,13 @@ import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.egit.core.Activator; -import org.eclipse.egit.core.AdaptableFileTreeIterator; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.Status; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.treewalk.FileTreeIterator; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -45,7 +45,7 @@ public class SubmoduleAndContainerTreeIteratorTest { private IFile parentFile; - private AdaptableFileTreeIterator treeIt; + private FileTreeIterator treeIt; @Before public void setUp() throws Exception { @@ -78,9 +78,7 @@ public class SubmoduleAndContainerTreeIteratorTest { parentRepository.trackAllFiles(parentProject); parentRepository.commit("Initial commit"); - treeIt = new AdaptableFileTreeIterator( - parentRepository.getRepository(), parentFile.getWorkspace() - .getRoot()); + treeIt = new FileTreeIterator(parentRepository.getRepository()); } @After diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/AdaptableFileTreeIterator.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/AdaptableFileTreeIterator.java deleted file mode 100644 index 9cb8ed446..000000000 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/AdaptableFileTreeIterator.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2009, Tor Arne Vestbø - * - * 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 - *******************************************************************************/ - -package org.eclipse.egit.core; - -import java.io.File; -import java.io.IOException; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.lib.ObjectReader; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.treewalk.AbstractTreeIterator; -import org.eclipse.jgit.treewalk.FileTreeIterator; -import org.eclipse.jgit.treewalk.WorkingTreeIterator; -import org.eclipse.jgit.util.FS; - -/** - * Java IO file tree iterator that can adapt to a {@link ContainerTreeIterator} - *

- * The iterator automatically adapts to a {@link ContainerTreeIterator} when - * recursing into directories that are accessible from the given workspace root. - * - * @see org.eclipse.jgit.treewalk.FileTreeIterator - * @see org.eclipse.egit.core.ContainerTreeIterator - */ -public class AdaptableFileTreeIterator extends FileTreeIterator { - - IWorkspaceRoot root; - - /** - * Create a new iterator to traverse the work tree of the given repository - *

- * The iterator will automatically adapt to a {@link ContainerTreeIterator} - * when encountering directories what can be mapped into the given workspace - * root. - * - * @param repository - * the repository this iterator should traverse the working tree - * of - * @param workspaceRoot - * the workspace root to check resource mapping against. - */ - public AdaptableFileTreeIterator(final Repository repository, - final IWorkspaceRoot workspaceRoot) { - super(repository); - root = workspaceRoot; - } - - /** - * Create a new iterator to traverse a subdirectory. - *

- * The iterator will automatically adapt to a {@link ContainerTreeIterator} - * when encountering directories what can be mapped into the given workspace - * root. - * - * @param path - * the subdirectory. This should be a directory contained within - * the parent directory. - * @param parent - * the parent iterator we were created from. - * @param workspaceRoot - * the workspace root to check resource mapping against. - */ - protected AdaptableFileTreeIterator(final WorkingTreeIterator parent, - File path, final IWorkspaceRoot workspaceRoot) { - super(parent, path, FS.DETECTED); - root = workspaceRoot; - } - - @Override - public AbstractTreeIterator createSubtreeIterator(ObjectReader repo) - throws IncorrectObjectTypeException, IOException { - final File currentFile = ((FileEntry) current()).getFile(); - IContainer container = IteratorService.findContainer(root, currentFile); - if (container != null) - return new ContainerTreeIterator(this, container); - return new AdaptableFileTreeIterator(this, currentFile, root); - } - -} diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/ContainerTreeIterator.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/ContainerTreeIterator.java deleted file mode 100644 index c894e3b2c..000000000 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/ContainerTreeIterator.java +++ /dev/null @@ -1,429 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2008, 2013 Google Inc. 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 - * http://www.eclipse.org/legal/epl-v10.html - *******************************************************************************/ - -package org.eclipse.egit.core; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.eclipse.core.resources.IContainer; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.IResourceFilterDescription; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; -import org.eclipse.egit.core.internal.CoreText; -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.FileMode; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectReader; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.treewalk.AbstractTreeIterator; -import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry; -import org.eclipse.jgit.treewalk.WorkingTreeIterator; -import org.eclipse.jgit.treewalk.WorkingTreeOptions; -import org.eclipse.jgit.util.FS; - -/** - * Adapts an Eclipse {@link IContainer} for use in a TreeWalk. - *

- * This iterator converts an Eclipse IContainer object into something that a - * TreeWalk instance can iterate over in parallel with any other Git tree data - * structure, such as another working directory tree from outside of the - * workspace or a stored tree from a Repository object database. - *

- * Modification times provided by this iterator are obtained from the cache - * Eclipse uses to track external resource modification. This can be faster, but - * requires the user refresh their workspace when external modifications take - * place. This is not really a concern as it is common practice to need to do a - * workspace refresh after externally modifying a file. - * - * @see org.eclipse.jgit.treewalk.TreeWalk - */ -public class ContainerTreeIterator extends WorkingTreeIterator { - - private static String computePrefix(final Repository repository, - final IContainer base) { - File workTree = repository.getWorkTree(); - IPath location = base.getLocation(); - if (location == null) - throw new IllegalArgumentException( - "Location of container not found: " + base); //$NON-NLS-1$ - Path workTreePath = new Path(workTree.getAbsolutePath()); - IPath relativePath = location.makeRelativeTo(workTreePath); - return relativePath.toString(); - } - - private final IContainer node; - - /** - * Construct a new iterator from a container in the workspace. - *

- * The iterator will support traversal over the named container, but only if - * it is contained within a project which has the Git repository provider - * connected and this resource is mapped into a Git repository. During the - * iteration the paths will be automatically generated to match the proper - * repository paths for this container's children. - * - * @param repository - * repository the given base is mapped to - * @param base - * the part of the workspace the iterator will walk over. - */ - public ContainerTreeIterator(final Repository repository, final IContainer base) { - super(computePrefix(repository, base), repository.getConfig().get( - WorkingTreeOptions.KEY)); - node = base; - init(entries(false)); - initRootIterator(repository); - } - - /** - * Construct a new iterator from the workspace root. - *

- * The iterator will support traversal over workspace projects that have - * a Git repository provider connected and is mapped into a Git repository. - * During the iteration the paths will be automatically generated to match - * the proper repository paths for this container's children. - * - * @param repository - * repository the given base is mapped to - * @param root - * the workspace root to walk over. - */ - public ContainerTreeIterator(final Repository repository, final IWorkspaceRoot root) { - super("", repository.getConfig().get(WorkingTreeOptions.KEY)); //$NON-NLS-1$ - node = root; - init(entries(false)); - initRootIterator(repository); - } - - /** - * Construct a new iterator from a container in the workspace, with a given - * parent iterator. - *

- * The iterator will support traversal over the named container, but only if - * it is contained within a project which has the Git repository provider - * connected and this resource is mapped into a Git repository. During the - * iteration the paths will be automatically generated to match the proper - * repository paths for this container's children. - * - * @param p - * the parent iterator we were created from. - * @param base - * the part of the workspace the iterator will walk over. - */ - public ContainerTreeIterator(final WorkingTreeIterator p, - final IContainer base) { - this(p, base, false); - } - - private ContainerTreeIterator(final WorkingTreeIterator p, - final IContainer base, final boolean hasInheritedResourceFilters) { - super(p); - node = base; - init(entries(hasInheritedResourceFilters)); - } - - @Override - public AbstractTreeIterator createSubtreeIterator(ObjectReader reader) - throws IncorrectObjectTypeException, IOException { - if (FileMode.TREE.equals(mode)) { - if (current() instanceof ResourceEntry) { - ResourceEntry resourceEntry = (ResourceEntry) current(); - return new ContainerTreeIterator(this, - (IContainer) resourceEntry.rsrc, - resourceEntry.hasInheritedResourceFilters); - } else if (current() instanceof FileEntry) { - FileEntry fileEntry = (FileEntry) current(); - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - return new AdaptableFileTreeIterator(this, fileEntry.getFile(), root); - } else { - throw new IllegalStateException("Unknown entry type: " + current()); //$NON-NLS-1$ - } - } else - throw new IncorrectObjectTypeException(ObjectId.zeroId(), - Constants.TYPE_TREE); - } - - /** - * Get the ResourceEntry for the current entry. - * - * @return the current entry - */ - public ResourceEntry getResourceEntry() { - return (ResourceEntry) current(); - } - - private Entry[] entries(final boolean hasInheritedResourceFilters) { - final IResource[] resources; - try { - resources = node.members(IContainer.INCLUDE_HIDDEN); - } catch (CoreException err) { - return EOF; - } - - List entries = new ArrayList(resources.length); - - boolean inheritableResourceFilter = addFilteredEntriesIfFiltersActive( - hasInheritedResourceFilters, resources, entries); - - for (IResource resource : resources) - if (!resource.isLinked()) - entries.add(new ResourceEntry(resource, inheritableResourceFilter)); - - return entries.toArray(new Entry[entries.size()]); - } - - /** - * Add entries for filtered resources. - * - * @param hasInheritedResourceFilters - * true if resource filters of parents could be active, false - * otherwise - * @param memberResources - * the resources returned from members() that do not have to be - * added as entries again - * @param entries - * where entries should be added to - * @return true if we now have resource filters that are inherited, false if - * there are no resource filters which are inherited. - */ - private boolean addFilteredEntriesIfFiltersActive( - final boolean hasInheritedResourceFilters, - final IResource[] memberResources, final List entries) { - // Inheritable resource filters must be propagated. - boolean inheritableResourceFilter = hasInheritedResourceFilters; - IResourceFilterDescription[] filters; - try { - filters = node.getFilters(); - } catch (CoreException e) { - // Should not happen, but assume we have no filters then. - filters = new IResourceFilterDescription[] {}; - } - - if (filters.length != 0 || hasInheritedResourceFilters) { - if (!inheritableResourceFilter) { - for (IResourceFilterDescription filter : filters) { - boolean inheritable = (filter.getType() & IResourceFilterDescription.INHERITABLE) != 0; - if (inheritable) - inheritableResourceFilter = true; - } - } - - Set resourceEntries = new HashSet(); - for (IResource resource : memberResources) - // Make sure linked resources are ignored here. - // This is particularly important in the case of a linked - // resource which targets a normally filtered/hidden file - // within the same location. In such case, ignoring it here - // ensures the actual target gets included in the code below. - if (!resource.isLinked()) { - IPath location = resource.getLocation(); - if (location != null) - resourceEntries.add(location.toFile()); - } - - addFilteredEntries(resourceEntries, entries); - } - return inheritableResourceFilter; - } - - private void addFilteredEntries(final Set existingResourceEntries, - final List addToEntries) { - IPath containerLocation = node.getLocation(); - if (containerLocation == null) - return; - - File folder = containerLocation.toFile(); - File[] children = folder.listFiles(); - if (children == null) - return; - - for (File child : children) { - if (existingResourceEntries.contains(child)) - continue; // ok if linked resources are ignored earlier on - IPath childLocation = new Path(child.getAbsolutePath()); - IWorkspaceRoot root = node.getWorkspace().getRoot(); - IContainer container = root.getContainerForLocation(childLocation); - // Check if the container is accessible in the workspace. - // This may seem strange, as it was not returned from - // members() above, but it's the case for nested projects - // that are filtered directly. - if (container != null && container.isAccessible()) - // Resource filters does not cross the non-member line - // -> stop inheriting resource filter here (false) - addToEntries.add(new ResourceEntry(container, false)); - else - addToEntries.add(new FileEntry(child, FS.DETECTED)); - } - } - - /** - * Wrapper for a resource in the Eclipse workspace - */ - static public class ResourceEntry extends Entry { - final IResource rsrc; - final boolean hasInheritedResourceFilters; - - private final FileMode fileMode; - - private long length = -1; - - ResourceEntry(final IResource f, final boolean hasInheritedResourceFilters) { - rsrc = f; - this.hasInheritedResourceFilters = hasInheritedResourceFilters; - - FileMode mode = null; - try { - File file = asFile(); - if (file == null) - mode = FileMode.MISSING; - else if (FS.DETECTED.supportsSymlinks() - && FS.DETECTED.isSymLink(file)) - mode = FileMode.SYMLINK; - else { - switch (f.getType()) { - case IResource.FILE: - if (FS.DETECTED.supportsExecute() - && FS.DETECTED.canExecute(file)) - mode = FileMode.EXECUTABLE_FILE; - else - mode = FileMode.REGULAR_FILE; - break; - case IResource.PROJECT: - case IResource.FOLDER: { - final IContainer c = (IContainer) f; - if (c.findMember(Constants.DOT_GIT) != null) - mode = FileMode.GITLINK; - else - mode = FileMode.TREE; - break; - } - default: - mode = FileMode.MISSING; - break; - } - } - } catch (IOException e) { - mode = FileMode.MISSING; - } - this.fileMode = mode; - } - - @Override - public FileMode getMode() { - return fileMode; - } - - @Override - public String getName() { - if (rsrc.getType() == IResource.PROJECT) - return rsrc.getLocation().lastSegment(); - else - return rsrc.getName(); - } - - @Override - public long getLength() { - if (length < 0) - if (rsrc instanceof IFile || fileMode == FileMode.SYMLINK - || fileMode == FileMode.GITLINK) { - try { - File file = asFile(); - if (file != null) - length = FS.DETECTED.length(file); - else - length = 0; - } catch (IOException e) { - length = 0; - } - } else - length = 0; - return length; - } - - @Override - public long getLastModified() { - if (fileMode == FileMode.SYMLINK) { - try { - File file = asFile(); - if (file != null) - return FS.DETECTED.lastModified(file); - return 0; - } catch (IOException e) { - return 0; - } - } - return rsrc.getLocalTimeStamp(); - } - - @Override - public InputStream openInputStream() throws IOException { - if (fileMode == FileMode.SYMLINK) { - File file = asFile(); - if (file == null) - throw new IOException(MessageFormat.format( - CoreText.ContainerTreeIterator_DeletedFile, rsrc)); - return new ByteArrayInputStream(FS.DETECTED.readSymLink(file) - .getBytes(Constants.CHARACTER_ENCODING)); - } else { - if (rsrc.getType() == IResource.FILE) - try { - return ((IFile) rsrc).getContents(true); - } catch (CoreException err) { - final IOException ioe = new IOException(err.getMessage()); - ioe.initCause(err); - throw ioe; - } - } - throw new IOException("Not a regular file: " + rsrc); //$NON-NLS-1$ - } - - /** - * Get the underlying resource of this entry. - * - * @return the underlying resource - */ - public IResource getResource() { - return rsrc; - } - - /** - * @return file of the resource or null - */ - private File asFile() { - return ContainerTreeIterator.asFile(rsrc); - } - } - - private static File asFile(IResource resource) { - final IPath location = resource.getLocation(); - return location != null ? location.toFile() : null; - } - - @Override - protected byte[] idSubmodule(Entry e) { - File nodeFile = asFile(node); - if (nodeFile != null) - return idSubmodule(nodeFile, e); - return super.idSubmodule(e); - } -} diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/IteratorService.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/IteratorService.java index 2d931968a..a14f2302b 100644 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/IteratorService.java +++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/IteratorService.java @@ -13,10 +13,10 @@ import java.io.File; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Path; import org.eclipse.egit.core.project.RepositoryMapping; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.WorkingTreeIterator; /** @@ -31,27 +31,14 @@ public class IteratorService { * repository work tree folder. * * @param repository - * @return

  • a {@link ContainerTreeIterator} if the work tree folder of - * the given repository resides in a project shared with Git
  • an - * {@link AdaptableFileTreeIterator} otherwise
  • {@code null} if the - * workspace is closed. + * @return a {@link FileTreeIterator} or {@code null} if repository is bare */ public static WorkingTreeIterator createInitialIterator( Repository repository) { - IWorkspaceRoot root; - try { - root = ResourcesPlugin.getWorkspace().getRoot(); - } catch (IllegalStateException e) { - // workspace is closed + if (repository.isBare()) { return null; } - File workTree = repository.getWorkTree(); - if (!workTree.exists()) - return null; - IContainer container = findContainer(root, workTree); - if (container != null) - return new ContainerTreeIterator(repository, container); - return new AdaptableFileTreeIterator(repository, root); + return new FileTreeIterator(repository); } /** diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/op/AddToIndexOperation.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/op/AddToIndexOperation.java index 1b0adec48..1a2ebfee9 100644 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/op/AddToIndexOperation.java +++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/op/AddToIndexOperation.java @@ -21,7 +21,6 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.egit.core.Activator; -import org.eclipse.egit.core.AdaptableFileTreeIterator; import org.eclipse.egit.core.internal.CoreText; import org.eclipse.egit.core.internal.job.RuleUtil; import org.eclipse.egit.core.project.RepositoryMapping; @@ -107,9 +106,7 @@ public class AddToIndexOperation implements IEGitOperation { if (command == null) { Repository repo = map.getRepository(); Git git = new Git(repo); - AdaptableFileTreeIterator it = new AdaptableFileTreeIterator(repo, - resource.getWorkspace().getRoot()); - command = git.add().setWorkingTreeIterator(it); + command = git.add(); addCommands.put(map, command); } String filepattern = map.getRepoRelativePath(resource); diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java index f397dcde3..2e2e8d6a5 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CommitDialog.java @@ -29,13 +29,11 @@ import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.JobChangeAdapter; -import org.eclipse.egit.core.AdaptableFileTreeIterator; import org.eclipse.egit.core.internal.util.ResourceUtil; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.UIPreferences; @@ -93,6 +91,7 @@ import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.IndexDiff; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryState; +import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.filter.PathFilterGroup; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; @@ -1309,8 +1308,7 @@ public class CommitDialog extends TitleAreaDialog { * @throws IOException */ private Status getFileStatus(String path) throws IOException { - AdaptableFileTreeIterator fileTreeIterator = new AdaptableFileTreeIterator( - repository, ResourcesPlugin.getWorkspace().getRoot()); + FileTreeIterator fileTreeIterator = new FileTreeIterator(repository); IndexDiff indexDiff = new IndexDiff(repository, Constants.HEAD, fileTreeIterator); Set repositoryPaths = Collections.singleton(path); indexDiff.setFilter(PathFilterGroup.createFromStrings(repositoryPaths)); diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CompareTreeView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CompareTreeView.java index 99b560e4d..a8555342a 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CompareTreeView.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/dialogs/CompareTreeView.java @@ -28,12 +28,9 @@ import org.eclipse.compare.ITypedElement; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; -import org.eclipse.egit.core.AdaptableFileTreeIterator; -import org.eclipse.egit.core.ContainerTreeIterator; import org.eclipse.egit.core.internal.CompareCoreUtils; import org.eclipse.egit.core.internal.storage.GitFileRevision; import org.eclipse.egit.core.internal.storage.WorkingTreeFileRevision; @@ -535,8 +532,7 @@ public class CompareTreeView extends ViewPart implements IMenuListener, IShowInS int baseTreeIndex; if (baseCommit == null) { checkIgnored = true; - baseTreeIndex = tw.addTree(new AdaptableFileTreeIterator( - repository, ResourcesPlugin.getWorkspace().getRoot())); + baseTreeIndex = tw.addTree(new FileTreeIterator(repository)); } else baseTreeIndex = tw.addTree(new CanonicalTreeParser(null, repository.newObjectReader(), baseCommit.getTree())); @@ -696,10 +692,9 @@ public class CompareTreeView extends ViewPart implements IMenuListener, IShowInS private long getEntrySize(TreeWalk tw, AbstractTreeIterator iterator) throws MissingObjectException, IncorrectObjectTypeException, IOException { - if (iterator instanceof ContainerTreeIterator) - return ((ContainerTreeIterator) iterator).getEntryContentLength(); - if (iterator instanceof FileTreeIterator) + if (iterator instanceof FileTreeIterator) { return ((FileTreeIterator) iterator).getEntryContentLength(); + } try { return tw.getObjectReader().getObjectSize( iterator.getEntryObjectId(), Constants.OBJ_BLOB); diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/merge/GitCompareEditorInput.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/merge/GitCompareEditorInput.java index 93bc55de8..e93f688ee 100644 --- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/merge/GitCompareEditorInput.java +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/merge/GitCompareEditorInput.java @@ -24,11 +24,9 @@ import org.eclipse.compare.structuremergeviewer.Differencer; import org.eclipse.compare.structuremergeviewer.IDiffContainer; import org.eclipse.compare.structuremergeviewer.IDiffElement; import org.eclipse.core.resources.IResource; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; -import org.eclipse.egit.core.AdaptableFileTreeIterator; import org.eclipse.egit.core.internal.CompareCoreUtils; import org.eclipse.egit.core.internal.storage.GitFileRevision; import org.eclipse.egit.core.project.RepositoryMapping; @@ -43,6 +41,7 @@ import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; +import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.WorkingTreeIterator; import org.eclipse.jgit.treewalk.filter.OrTreeFilter; @@ -261,8 +260,7 @@ public class GitCompareEditorInput extends CompareEditorInput { if (baseCommit == null) { // compare workspace with something checkIgnored = true; - baseTreeIndex = tw.addTree(new AdaptableFileTreeIterator( - repository, ResourcesPlugin.getWorkspace().getRoot())); + baseTreeIndex = tw.addTree(new FileTreeIterator(repository)); } else baseTreeIndex = tw.addTree(new CanonicalTreeParser(null, repository.newObjectReader(), baseCommit.getTree())); -- 2.11.4.GIT