From 49480572da5418dfd15737725912bbf73acd5b48 Mon Sep 17 00:00:00 2001 From: Markus Duft Date: Fri, 13 Jul 2012 13:06:25 +0200 Subject: [PATCH] Introduce a method to find projects containing paths The code searches for IContainer's containing a certain path, by comparing all IProject's and the IWorkspaceRoot location with the given filename. This is much cheaper than calling IWorkspaceRoot.findContainersForLocationURI(). This is required by multiple changes Change-Id: I9c85247d6e0410bc0caefd6a4594373514e16562 Signed-off-by: Robin Rosenberg --- .../egit/core/internal/util/ProjectUtilTest.java | 114 +++++++++++++++++++++ .../egit/core/internal/util/ProjectUtil.java | 79 ++++++++++++++ 2 files changed, 193 insertions(+) diff --git a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/util/ProjectUtilTest.java b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/util/ProjectUtilTest.java index bd103f17a..e64ae1e4f 100644 --- a/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/util/ProjectUtilTest.java +++ b/org.eclipse.egit.core.test/src/org/eclipse/egit/core/internal/util/ProjectUtilTest.java @@ -12,6 +12,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasItem; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; @@ -22,9 +23,13 @@ import static org.mockito.Mockito.when; import java.io.File; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.egit.core.op.ConnectProviderOperation; @@ -65,6 +70,115 @@ public class ProjectUtilTest extends GitTestCase { } @Test + public void testGetProjectsContains() throws Exception { + TestProject prj2 = new TestProject(true, "Project-1-sub"); + + try { + repository.createFile(project.getProject(), "xxx"); + repository.createFile(project.getProject(), "zzz"); + repository.createFile(prj2.getProject(), "zzz"); + + project.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); + prj2.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); + + IProject[] projectsContaining = ProjectUtil.getProjectsContaining( + repository.getRepository(), + Collections.singleton("Project-1/xxx")); + IProject[] projectsEmpty = ProjectUtil.getProjectsContaining( + repository.getRepository(), Collections.singleton("yyy")); + IProject[] projectSelf = ProjectUtil.getProjectsContaining( + repository.getRepository(), + Collections.singleton("Project-1")); + Set files = new TreeSet(); + files.add("Project-1/xxx"); + files.add("Project-1/zzz"); + IProject[] multiFile = ProjectUtil.getProjectsContaining( + repository.getRepository(), files); + + files.clear(); + files.add("Project-1/xxx"); + files.add("Project-1-sub/zzz"); + IProject[] multiProject = ProjectUtil.getProjectsContaining( + repository.getRepository(), files); + IProject[] nonExistProject = ProjectUtil.getProjectsContaining( + repository.getRepository(), + Collections.singleton("Project-2")); + + assertEquals(1, projectsContaining.length); + assertEquals(0, projectsEmpty.length); + assertEquals(1, projectSelf.length); + assertEquals(1, multiFile.length); + assertEquals(2, multiProject.length); + assertEquals(0, nonExistProject.length); + + IProject p = projectsContaining[0]; + assertEquals("Project-1", p.getDescription().getName()); + } finally { + prj2.dispose(); + } + } + + @Test + public void testGetNestedProjectsContains() throws Exception { + TestProject prj2 = new TestProject(true, "Project-1/dir/Project-1-sub"); + + try { + repository.createFile(project.getProject(), "xxx"); + repository.createFile(project.getProject(), "zzz"); + repository.createFile(prj2.getProject(), "zzz"); + + project.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); + prj2.getProject().refreshLocal(IResource.DEPTH_INFINITE, null); + + IProject[] projectsContaining = ProjectUtil.getProjectsContaining( + repository.getRepository(), + Collections.singleton("Project-1/xxx")); + IProject[] projectsEmpty = ProjectUtil.getProjectsContaining( + repository.getRepository(), Collections.singleton("yyy")); + IProject[] projectSelf = ProjectUtil.getProjectsContaining( + repository.getRepository(), + Collections.singleton("Project-1")); + Set files = new TreeSet(); + files.add("Project-1/xxx"); + files.add("Project-1/zzz"); + IProject[] multiFile = ProjectUtil.getProjectsContaining( + repository.getRepository(), files); + + files.clear(); + files.add("Project-1/dir/Project-1-sub/zzz"); + files.add("Project-1/xxx"); + IProject[] multiProject = ProjectUtil.getProjectsContaining( + repository.getRepository(), files); + IProject[] nonExistProject = ProjectUtil.getProjectsContaining( + repository.getRepository(), + Collections.singleton("Project-2")); + + assertEquals(1, projectsContaining.length); + assertEquals(0, projectsEmpty.length); + assertEquals(1, projectSelf.length); + assertEquals(1, multiFile.length); + assertEquals(2, multiProject.length); + assertEquals(0, nonExistProject.length); + + IProject p = projectsContaining[0]; + assertEquals("Project-1", p.getDescription().getName()); + } finally { + prj2.dispose(); + } + } + + @Test + public void testFindContainer() throws Exception { + File tmp = new File("/tmp/file"); + File test1 = new File(project.getProject().getLocation().toFile(), "xxx"); + File test2 = new File(repository.getRepository().getWorkTree(), "xxx"); + + assertNull(ProjectUtil.findContainer(tmp)); + assertEquals(project.getProject(), ProjectUtil.findContainer(test1)); + assertEquals(ResourcesPlugin.getWorkspace().getRoot(), ProjectUtil.findContainer(test2)); + } + + @Test public void testGetValidOpenProjectsClosedProject() throws Exception { project.getProject().close(new NullProgressMonitor()); IProject[] projects = ProjectUtil.getValidOpenProjects(repository diff --git a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ProjectUtil.java b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ProjectUtil.java index 1d9cc84ac..f50957a85 100644 --- a/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ProjectUtil.java +++ b/org.eclipse.egit.core/src/org/eclipse/egit/core/internal/util/ProjectUtil.java @@ -15,14 +15,19 @@ package org.eclipse.egit.core.internal.util; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Comparator; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; @@ -251,6 +256,80 @@ public class ProjectUtil { } /** + * The method returns all projects containing at least one of the given + * paths. + * + * @param repository + * the repository who's working tree is used as base for lookup + * @param fileList + * the list of files/directories to lookup + * @return valid projects containing one of the paths + * @throws CoreException + */ + public static IProject[] getProjectsContaining(Repository repository, + Collection fileList) throws CoreException { + Set result = new LinkedHashSet(); + File workTree = repository.getWorkTree(); + + for (String member : fileList) { + File file = new File(workTree, member); + + IContainer container = findContainer(file); + if (container instanceof IProject) + result.add((IProject) container); + } + + return result.toArray(new IProject[result.size()]); + } + + /** + * Looks up the IContainer containing the given file, if available. This is + * done by path comparison, which is very cheap compared to + * IWorkspaceRoot.findContainersForLocationURI() + * + * @param file + * the path to lookup a container for + * @return the IContainer (either IProject or IWorkspaceRoot) or + * null if not found. + */ + public static IContainer findContainer(File file) { + String absFile = file.getAbsolutePath(); + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IProject[] allProjects = root.getProjects(); + + // Sorting makes us look into nested projects first + Arrays.sort(allProjects, new Comparator() { + public int compare(IProject o1, IProject o2) { + return -o1.getLocation().toFile() + .compareTo(o2.getLocation().toFile()); + } + + }); + + for (IProject prj : allProjects) + if (checkContainerMatch(prj, absFile)) + return prj; + + if (checkContainerMatch(root, absFile)) + return root; + + return null; + } + + private static boolean checkContainerMatch(IContainer container, + String absFile) { + String absPrj = container.getLocation().toFile().getAbsolutePath(); + if (absPrj.equals(absFile)) + return true; + if (absPrj.length() < absFile.length()) { + char sepChar = absFile.charAt(absPrj.length()); + if (sepChar == File.separatorChar && absFile.startsWith(absPrj)) + return true; + } + return false; + } + + /** * Find directories containing .project files recursively starting at given * directory * -- 2.11.4.GIT