diff options
author | Arthur Daussy | 2018-05-28 12:37:48 +0000 |
---|---|---|
committer | Laurent Goubet | 2018-06-04 12:32:40 +0000 |
commit | 1661e48676deb3a23e2f55275b2a6610923a6643 (patch) | |
tree | 1162cf12cb3b8f82f8ee4cb49be1e6dd5838224e /plugins | |
parent | ba2081707263032bfd73d7acab286bb1e8ae8e82 (diff) | |
download | org.eclipse.emf.compare-1661e48676deb3a23e2f55275b2a6610923a6643.tar.gz org.eclipse.emf.compare-1661e48676deb3a23e2f55275b2a6610923a6643.tar.xz org.eclipse.emf.compare-1661e48676deb3a23e2f55275b2a6610923a6643.zip |
[535200] Create a new TreeWalk instead reusing one
In order to avoid side effects this commits create a new TreeWalk to
create the TreeWalkResourceVariantTreeProvider instead of using the one
given by JGit
Bug: 535200
Change-Id: I1b8621a488db2dc4842d250b95e07312013e648a
Diffstat (limited to 'plugins')
4 files changed, 267 insertions, 121 deletions
diff --git a/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/merge/RecursiveModelMerger.java b/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/merge/RecursiveModelMerger.java index a64cc3de1..46d5ff2ca 100644 --- a/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/merge/RecursiveModelMerger.java +++ b/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/merge/RecursiveModelMerger.java @@ -52,6 +52,8 @@ import org.eclipse.jgit.lib.ProgressMonitor; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.merge.MergeResult; import org.eclipse.jgit.merge.RecursiveMerger; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; import org.eclipse.jgit.treewalk.FileTreeIterator; import org.eclipse.jgit.treewalk.TreeWalk; @@ -105,6 +107,12 @@ public class RecursiveModelMerger extends RecursiveMerger { */ private final Set<String> handledPaths = new HashSet<>(); + private AbstractTreeIterator aBaseTree; + + private RevTree aHeadTree; + + private RevTree aMergeTree; + /** * Default recursive model merger. * @@ -116,12 +124,30 @@ public class RecursiveModelMerger extends RecursiveMerger { } @Override + protected boolean mergeTrees(AbstractTreeIterator baseTree, RevTree headTree, RevTree mergeTree, + boolean ignoreConflicts) throws IOException { + // We need to keep track on all version to be merged to be able to build a new TreeWalk in + // #mergeTreeWalk + this.aBaseTree = baseTree; + this.aHeadTree = headTree; + this.aMergeTree = mergeTree; + return super.mergeTrees(baseTree, headTree, mergeTree, ignoreConflicts); + } + + @Override protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts) throws IOException { if (LOGGER.isInfoEnabled()) { LOGGER.info("STARTING Recursive model merge."); //$NON-NLS-1$ } - final TreeWalkResourceVariantTreeProvider variantTreeProvider = new TreeWalkResourceVariantTreeProvider( - getRepository(), treeWalk, T_BASE, T_OURS, T_THEIRS); + final TreeWalkResourceVariantTreeProvider variantTreeProvider = new TreeWalkResourceVariantTreeProvider.Builder()// + .setRepository(getRepository())// + .setaBaseTree(aBaseTree)// + .setHeadTree(aHeadTree)// + .setMergeTree(aMergeTree)// + .setDircache(dircache) // + .setReader(reader) // + .build(); + final GitResourceVariantTreeSubscriber subscriber = new GitResourceVariantTreeSubscriber( variantTreeProvider); final RemoteResourceMappingContext remoteMappingContext = new SubscriberResourceMappingContext( diff --git a/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/merge/TreeWalkResourceVariantTreeProvider.java b/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/merge/TreeWalkResourceVariantTreeProvider.java index 989b9e096..f6a220406 100644 --- a/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/merge/TreeWalkResourceVariantTreeProvider.java +++ b/plugins/org.eclipse.emf.compare.egit/src/org/eclipse/emf/compare/egit/internal/merge/TreeWalkResourceVariantTreeProvider.java @@ -29,11 +29,17 @@ import org.eclipse.core.runtime.Path; import org.eclipse.egit.core.GitProvider; import org.eclipse.egit.core.internal.util.ResourceUtil; import org.eclipse.emf.compare.egit.internal.storage.TreeParserResourceVariant; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheBuildIterator; +import org.eclipse.jgit.dircache.DirCacheBuilder; import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.CanonicalTreeParser; -import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.FileTreeIterator; +import org.eclipse.jgit.treewalk.NameConflictTreeWalk; import org.eclipse.team.core.RepositoryProvider; import org.eclipse.team.core.variants.IResourceVariantTree; @@ -59,117 +65,16 @@ public class TreeWalkResourceVariantTreeProvider implements GitResourceVariantTr private final Set<IResource> knownResources; - private final LinkedHashMap<IPath, IProject> map = new LinkedHashMap<IPath, IProject>(); + private final LinkedHashMap<IPath, IProject> map; - /** - * Constructs the resource variant trees by iterating over the given tree walk. This TreeWalk must contain - * at least three trees corresponding to the three "sides" we need. - * <p> - * The tree walk will be reset to its initial state when we are done with the iteration. - * </p> - * - * @param repository - * The repository this tree walk has been created for. - * @param treeWalk - * The tree walk to iterate over. - * @param baseIndex - * Index of the ancestor tree in the given TreeWalk (value returned by - * {@link TreeWalk#addTree(AbstractTreeIterator)}) - * @param ourIndex - * Index of our tree in the given TreeWalk (value returned by - * {@link TreeWalk#addTree(AbstractTreeIterator)}) - * @param theirIndex - * Index of their tree in the given TreeWalk (value returned by - * {@link TreeWalk#addTree(AbstractTreeIterator)}) - * @throws IOException - * if we somehow cannot iterate over the treewalk. - */ - public TreeWalkResourceVariantTreeProvider(Repository repository, TreeWalk treeWalk, int baseIndex, - int ourIndex, int theirIndex) throws IOException { - // Record the initial state of this tree walk before iterating - final AbstractTreeIterator[] initialTrees = new AbstractTreeIterator[treeWalk.getTreeCount()]; - for (int i = 0; i < treeWalk.getTreeCount(); i++) { - initialTrees[i] = treeWalk.getTree(i, AbstractTreeIterator.class); - } - - final GitResourceVariantCache baseCache = new GitResourceVariantCache(); - final GitResourceVariantCache theirsCache = new GitResourceVariantCache(); - final GitResourceVariantCache oursCache = new GitResourceVariantCache(); - - while (treeWalk.next()) { - final int modeBase = treeWalk.getRawMode(baseIndex); - final int modeOurs = treeWalk.getRawMode(ourIndex); - final int modeTheirs = treeWalk.getRawMode(theirIndex); - if (!hasSignificantDifference(modeBase, modeOurs, modeTheirs)) { - // conflict on file modes, leave the default merger handle it - continue; - } + private TreeWalkResourceVariantTreeProvider(Builder builder) { - final CanonicalTreeParser base = treeWalk.getTree(baseIndex, CanonicalTreeParser.class); - final CanonicalTreeParser ours = treeWalk.getTree(ourIndex, CanonicalTreeParser.class); - final CanonicalTreeParser theirs = treeWalk.getTree(theirIndex, CanonicalTreeParser.class); - - final int nonZeroMode = modeBase != 0 ? modeBase : modeOurs != 0 ? modeOurs : modeTheirs; - final IResource resource = getResourceHandleForLocation(repository, treeWalk.getPathString(), - FileMode.fromBits(nonZeroMode) == FileMode.TREE); - - // Resource variants only make sense for IResources. - if (resource != null) { - IPath workspacePath = resource.getFullPath(); - if (modeBase != 0) { - baseCache.setVariant(resource, - TreeParserResourceVariant.create(repository, base, workspacePath)); - } - if (modeOurs != 0) { - oursCache.setVariant(resource, - TreeParserResourceVariant.create(repository, ours, workspacePath)); - } - if (modeTheirs != 0) { - theirsCache.setVariant(resource, - TreeParserResourceVariant.create(repository, theirs, workspacePath)); - } - } - - if (treeWalk.isSubtree()) { - treeWalk.enterSubtree(); - } - } - - // TODO any better way to reset the tree walk after an iteration? - treeWalk.reset(); - for (int i = 0; i < initialTrees.length; i++) { - initialTrees[i].reset(); - treeWalk.addTree(initialTrees[i]); - } - - baseTree = new GitCachedResourceVariantTree(baseCache); - theirsTree = new GitCachedResourceVariantTree(theirsCache); - oursTree = new GitCachedResourceVariantTree(oursCache); - - roots = new LinkedHashSet<IResource>(); - roots.addAll(baseCache.getRoots()); - roots.addAll(oursCache.getRoots()); - roots.addAll(theirsCache.getRoots()); - - knownResources = new LinkedHashSet<IResource>(); - knownResources.addAll(baseCache.getKnownResources()); - knownResources.addAll(oursCache.getKnownResources()); - knownResources.addAll(theirsCache.getKnownResources()); - } - - private boolean hasSignificantDifference(int modeBase, int modeOurs, int modeTheirs) { - if (modeBase == 0) { - if (FileMode.fromBits(modeOurs | modeTheirs) != FileMode.MISSING) { - return true; - } else { - return (FileMode.fromBits(modeOurs) == FileMode.TREE - && FileMode.fromBits(modeTheirs) != FileMode.TREE) - || (FileMode.fromBits(modeOurs) != FileMode.TREE - && FileMode.fromBits(modeTheirs) == FileMode.TREE); - } - } - return FileMode.fromBits(modeBase & modeOurs) != FileMode.MISSING - || FileMode.fromBits(modeBase & modeTheirs) != FileMode.MISSING; + this.map = builder.map; + this.baseTree = builder.baseTree; + this.theirsTree = builder.theirsTree; + this.oursTree = builder.oursTree; + this.roots = builder.roots; + this.knownResources = builder.knownResources; } public IResourceVariantTree getBaseTree() { @@ -206,6 +111,26 @@ public class TreeWalkResourceVariantTreeProvider implements GitResourceVariantTr */ public IResource getResourceHandleForLocation(Repository repository, String repoRelativePath, boolean isFolder) { + return getResourceHandleForLocation(repository, repoRelativePath, isFolder, map); + + } + + /** + * Returns a resource handle for this path in the workspace. Note that neither the resource nor the result + * need exist in the workspace : this may return inexistent or otherwise non-accessible IResources. + * + * @param repository + * The repository within which is tracked this file. + * @param repoRelativePath + * Repository-relative path of the file we need an handle for. + * @param isFolder + * <code>true</code> if the file being sought is a folder. + * @param map + * a to keeps tracks of IPath to IProject + * @return The resource handle for the given path in the workspace. + */ + private static IResource getResourceHandleForLocation(Repository repository, String repoRelativePath, + boolean isFolder, LinkedHashMap<IPath, IProject> map) { IResource resource = null; final String workDir = repository.getWorkTree().getAbsolutePath(); @@ -271,5 +196,171 @@ public class TreeWalkResourceVariantTreeProvider implements GitResourceVariantTr return resource; } + + public static class Builder { + + private Repository repository; + + private AbstractTreeIterator aBaseTree; + + private RevTree headTree; + + private RevTree mergeTree; + + private DirCache dircache; + + private ObjectReader reader; + + private IResourceVariantTree baseTree; + + private IResourceVariantTree oursTree; + + private IResourceVariantTree theirsTree; + + private Set<IResource> roots; + + private Set<IResource> knownResources; + + private GitResourceVariantCache baseCache; + + private GitResourceVariantCache theirsCache; + + private GitResourceVariantCache oursCache; + + private LinkedHashMap<IPath, IProject> map; + + /** + * @param repository + * The repository this tree walk has been created for. + * @return + */ + public Builder setRepository(Repository repository) { + this.repository = repository; + return this; + } + + public Builder setaBaseTree(AbstractTreeIterator aBaseTree) { + this.aBaseTree = aBaseTree; + return this; + } + + public Builder setHeadTree(RevTree headTree) { + this.headTree = headTree; + return this; + } + + public Builder setMergeTree(RevTree mergeTree) { + this.mergeTree = mergeTree; + return this; + } + + public Builder setDircache(DirCache dircache) { + this.dircache = dircache; + return this; + } + + public Builder setReader(ObjectReader reader) { + this.reader = reader; + return this; + } + + public TreeWalkResourceVariantTreeProvider build() throws IOException { + + DirCacheBuilder aBuilder = dircache.builder(); + DirCacheBuildIterator buildIt = new DirCacheBuildIterator(aBuilder); + + this.map = new LinkedHashMap<>(); + + try (NameConflictTreeWalk treeWalk = new NameConflictTreeWalk(repository, reader)) { + + int baseIndex = treeWalk.addTree(aBaseTree); + int ourIndex = treeWalk.addTree(headTree); + int theirIndex = treeWalk.addTree(mergeTree); + int dciPos = treeWalk.addTree(buildIt); + FileTreeIterator aWorkingTreeIterator = new FileTreeIterator(repository); + treeWalk.addTree(aWorkingTreeIterator); + aWorkingTreeIterator.setDirCacheIterator(treeWalk, dciPos); + + this.baseCache = new GitResourceVariantCache(); + this.theirsCache = new GitResourceVariantCache(); + this.oursCache = new GitResourceVariantCache(); + + while (treeWalk.next()) { + final int modeBase = treeWalk.getRawMode(baseIndex); + final int modeOurs = treeWalk.getRawMode(ourIndex); + final int modeTheirs = treeWalk.getRawMode(theirIndex); + if (!hasSignificantDifference(modeBase, modeOurs, modeTheirs)) { + // conflict on file modes, leave the default merger handle it + continue; + } + + final CanonicalTreeParser base = treeWalk.getTree(baseIndex, CanonicalTreeParser.class); + final CanonicalTreeParser ours = treeWalk.getTree(ourIndex, CanonicalTreeParser.class); + final CanonicalTreeParser theirs = treeWalk.getTree(theirIndex, + CanonicalTreeParser.class); + + final int nonZeroMode = modeBase != 0 ? modeBase : modeOurs != 0 ? modeOurs : modeTheirs; + final IResource resource = getResourceHandleForLocation(repository, + treeWalk.getPathString(), FileMode.fromBits(nonZeroMode) == FileMode.TREE, map); + + // Resource variants only make sense for IResources. + if (resource != null) { + IPath workspacePath = resource.getFullPath(); + if (modeBase != 0) { + baseCache.setVariant(resource, + TreeParserResourceVariant.create(repository, base, workspacePath)); + } + if (modeOurs != 0) { + oursCache.setVariant(resource, + TreeParserResourceVariant.create(repository, ours, workspacePath)); + } + if (modeTheirs != 0) { + theirsCache.setVariant(resource, + TreeParserResourceVariant.create(repository, theirs, workspacePath)); + } + } + + if (treeWalk.isSubtree()) { + treeWalk.enterSubtree(); + } + } + + baseTree = new GitCachedResourceVariantTree(baseCache); + theirsTree = new GitCachedResourceVariantTree(theirsCache); + oursTree = new GitCachedResourceVariantTree(oursCache); + + roots = new LinkedHashSet<>(); + roots.addAll(baseCache.getRoots()); + roots.addAll(oursCache.getRoots()); + roots.addAll(theirsCache.getRoots()); + + knownResources = new LinkedHashSet<>(); + knownResources.addAll(baseCache.getKnownResources()); + knownResources.addAll(oursCache.getKnownResources()); + knownResources.addAll(theirsCache.getKnownResources()); + } finally { + // Needs reset since it might be used elsewhere + aBaseTree.reset(); + } + + return new TreeWalkResourceVariantTreeProvider(this); + } + + private boolean hasSignificantDifference(int modeBase, int modeOurs, int modeTheirs) { + if (modeBase == 0) { + if (FileMode.fromBits(modeOurs | modeTheirs) != FileMode.MISSING) { + return true; + } else { + return (FileMode.fromBits(modeOurs) == FileMode.TREE + && FileMode.fromBits(modeTheirs) != FileMode.TREE) + || (FileMode.fromBits(modeOurs) != FileMode.TREE + && FileMode.fromBits(modeTheirs) == FileMode.TREE); + } + } + return FileMode.fromBits(modeBase & modeOurs) != FileMode.MISSING + || FileMode.fromBits(modeBase & modeTheirs) != FileMode.MISSING; + } + + } } // CHECKSTYLE:ON diff --git a/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/GitResourceVariantTreeSubscriberTest.java b/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/GitResourceVariantTreeSubscriberTest.java index bc71ef82a..e333a818c 100644 --- a/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/GitResourceVariantTreeSubscriberTest.java +++ b/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/GitResourceVariantTreeSubscriberTest.java @@ -25,6 +25,7 @@ import org.eclipse.emf.compare.egit.internal.merge.GitResourceVariantTreeSubscri import org.eclipse.emf.compare.egit.internal.merge.TreeWalkResourceVariantTreeProvider; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.NameConflictTreeWalk; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.team.core.diff.IDiff; @@ -249,10 +250,17 @@ public class GitResourceVariantTreeSubscriberTest extends VariantsTestCase { RevTree sourceTree = walk.parseTree(repo.resolve(MASTER)); RevTree remoteTree = walk.parseTree(repo.resolve(BRANCH)); TreeWalk treeWalk = new NameConflictTreeWalk(repo); - treeWalk.addTree(baseTree); + int baseTreeIteratorIndex = treeWalk.addTree(baseTree); treeWalk.addTree(sourceTree); treeWalk.addTree(remoteTree); - return new TreeWalkResourceVariantTreeProvider(repo, treeWalk, 0, 1, 2); + return new TreeWalkResourceVariantTreeProvider.Builder()// + .setRepository(repo)// + .setaBaseTree(treeWalk.getTree(baseTreeIteratorIndex, AbstractTreeIterator.class))// + .setHeadTree(sourceTree)// + .setMergeTree(remoteTree)// + .setDircache(repo.readDirCache())// + .setReader(repo.newObjectReader())// + .build(); } finally { walk.close(); } @@ -279,10 +287,17 @@ public class GitResourceVariantTreeSubscriberTest extends VariantsTestCase { RevTree sourceTree = walk.parseTree(repo.resolve(MASTER)); RevTree remoteTree = walk.parseTree(repo.resolve(BRANCH)); TreeWalk treeWalk = new NameConflictTreeWalk(repo); - treeWalk.addTree(baseTree); + int baseTreeIteratorIndex = treeWalk.addTree(baseTree); treeWalk.addTree(sourceTree); treeWalk.addTree(remoteTree); - return new TreeWalkResourceVariantTreeProvider(repo, treeWalk, 0, 1, 2); + return new TreeWalkResourceVariantTreeProvider.Builder()// + .setRepository(repo)// + .setaBaseTree(treeWalk.getTree(baseTreeIteratorIndex, AbstractTreeIterator.class))// + .setHeadTree(sourceTree)// + .setMergeTree(remoteTree)// + .setDircache(repo.readDirCache())// + .setReader(repo.newObjectReader())// + .build(); } finally { walk.close(); } @@ -314,10 +329,17 @@ public class GitResourceVariantTreeSubscriberTest extends VariantsTestCase { RevTree sourceTree = walk.parseTree(repo.resolve(MASTER)); RevTree remoteTree = walk.parseTree(repo.resolve(BRANCH)); TreeWalk treeWalk = new NameConflictTreeWalk(repo); - treeWalk.addTree(baseTree); + int baseTreeIteratorIndex = treeWalk.addTree(baseTree); treeWalk.addTree(sourceTree); treeWalk.addTree(remoteTree); - return new TreeWalkResourceVariantTreeProvider(repo, treeWalk, 0, 1, 2); + return new TreeWalkResourceVariantTreeProvider.Builder()// + .setRepository(repo)// + .setaBaseTree(treeWalk.getTree(baseTreeIteratorIndex, AbstractTreeIterator.class))// + .setHeadTree(sourceTree)// + .setMergeTree(remoteTree)// + .setDircache(repo.readDirCache())// + .setReader(repo.newObjectReader())// + .build(); } finally { walk.close(); } diff --git a/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/TreeWalkResourceVariantTreeProviderTest.java b/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/TreeWalkResourceVariantTreeProviderTest.java index 25f82715d..663dec97c 100644 --- a/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/TreeWalkResourceVariantTreeProviderTest.java +++ b/plugins/org.eclipse.emf.compare.ide.ui.tests.git/src/org/eclipse/emf/compare/ide/ui/tests/merge/TreeWalkResourceVariantTreeProviderTest.java @@ -20,6 +20,7 @@ import org.eclipse.emf.compare.egit.internal.merge.TreeWalkResourceVariantTreePr import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.AbstractTreeIterator; import org.eclipse.jgit.treewalk.NameConflictTreeWalk; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.team.core.variants.IResourceVariant; @@ -57,11 +58,17 @@ public class TreeWalkResourceVariantTreeProviderTest extends VariantsTestCase { RevTree sourceTree = walk.parseTree(repo.resolve(MASTER)); RevTree remoteTree = walk.parseTree(repo.resolve(BRANCH)); TreeWalk treeWalk = new NameConflictTreeWalk(repo); - treeWalk.addTree(baseTree); + int baseTreeIndex = treeWalk.addTree(baseTree); treeWalk.addTree(sourceTree); treeWalk.addTree(remoteTree); - TreeWalkResourceVariantTreeProvider treeProvider = new TreeWalkResourceVariantTreeProvider(repo, - treeWalk, 0, 1, 2); + TreeWalkResourceVariantTreeProvider treeProvider = new TreeWalkResourceVariantTreeProvider.Builder()// + .setaBaseTree(treeWalk.getTree(baseTreeIndex, AbstractTreeIterator.class))// + .setDircache(repo.readDirCache())// + .setHeadTree(sourceTree)// + .setMergeTree(remoteTree)// + .setRepository(repo)// + .setReader(repo.newObjectReader())// + .build(); assertEquals(1, treeProvider.getRoots().size()); assertTrue(treeProvider.getRoots().contains(iProject)); |