blob: cfddcaa3e65d222265735256a6e4bb216c27b59d [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.openapi.vcs.impl;
import com.intellij.lifecycle.PeriodicalTasksCloser;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vcs.*;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.intellij.util.Processor;
import com.intellij.util.StringLenComparator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
public class VcsRootIterator {
// folder path to files to be excluded
private final Map<String, MyRootFilter> myOtherVcsFolders;
private final FileIndexFacade myExcludedFileIndex;
private final ProjectLevelVcsManager myVcsManager;
private final Project myProject;
public VcsRootIterator(final Project project, final AbstractVcs vcs) {
myProject = project;
myVcsManager = ProjectLevelVcsManager.getInstance(project);
myOtherVcsFolders = new HashMap<String, MyRootFilter>();
myExcludedFileIndex = PeriodicalTasksCloser.getInstance().safeGetService(project, FileIndexFacade.class);
final VcsRoot[] allRoots = myVcsManager.getAllVcsRoots();
final VirtualFile[] roots = myVcsManager.getRootsUnderVcs(vcs);
for (VirtualFile root : roots) {
final MyRootFilter rootPresentFilter = new MyRootFilter(root, vcs.getName());
rootPresentFilter.init(allRoots);
myOtherVcsFolders.put(root.getUrl(), rootPresentFilter);
}
}
public boolean acceptFolderUnderVcs(final VirtualFile vcsRoot, final VirtualFile file) {
final String vcsUrl = vcsRoot.getUrl();
final MyRootFilter rootFilter = myOtherVcsFolders.get(vcsUrl);
if ((rootFilter != null) && (!rootFilter.accept(file))) {
return false;
}
return !isIgnoredByVcs(myVcsManager, myProject, file);
}
private static boolean isIgnoredByVcs(final ProjectLevelVcsManager vcsManager, final Project project, final VirtualFile file) {
return ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
return !project.isDisposed() && vcsManager.isIgnored(file);
}
});
}
private static class MyRootFilter {
private final VirtualFile myRoot;
private final String myVcsName;
// virtual file URLs
private final List<String> myExcludedByOthers;
private MyRootFilter(final VirtualFile root, final String vcsName) {
myRoot = root;
myVcsName = vcsName;
myExcludedByOthers = new LinkedList<String>();
}
private void init(final VcsRoot[] allRoots) {
final String ourPath = myRoot.getUrl();
for (VcsRoot root : allRoots) {
final AbstractVcs vcs = root.getVcs();
if (vcs == null || Comparing.equal(vcs.getName(), myVcsName)) continue;
final VirtualFile path = root.getPath();
if (path != null) {
final String url = path.getUrl();
if (url.startsWith(ourPath)) {
myExcludedByOthers.add(url);
}
}
}
Collections.sort(myExcludedByOthers, StringLenComparator.getDescendingInstance());
}
public boolean accept(final VirtualFile vf) {
final String url = vf.getUrl();
for (String excludedByOtherVcs : myExcludedByOthers) {
// use the fact that they are sorted
if (url.length() > excludedByOtherVcs.length()) return true;
if (url.startsWith(excludedByOtherVcs)) return false;
}
return true;
}
}
public static void iterateVfUnderVcsRoot(final Project project,
final VirtualFile root,
final Processor<VirtualFile> processor) {
final MyRootIterator rootIterator = new MyRootIterator(project, root, null, processor, null);
rootIterator.iterate();
}
public static void iterateVcsRoot(final Project project,
final VirtualFile root,
final Processor<FilePath> processor) {
iterateVcsRoot(project, root, processor, null);
}
public static void iterateVcsRoot(final Project project,
final VirtualFile root,
final Processor<FilePath> processor,
@Nullable VirtualFileFilter directoryFilter) {
final MyRootIterator rootIterator = new MyRootIterator(project, root, processor, null, directoryFilter);
rootIterator.iterate();
}
private static class MyRootIterator {
private final Project myProject;
private final Processor<FilePath> myPathProcessor;
private final Processor<VirtualFile> myFileProcessor;
@Nullable private final VirtualFileFilter myDirectoryFilter;
private final VirtualFile myRoot;
private final MyRootFilter myRootPresentFilter;
private final ProjectLevelVcsManager myVcsManager;
private MyRootIterator(final Project project,
final VirtualFile root,
@Nullable final Processor<FilePath> pathProcessor,
@Nullable final Processor<VirtualFile> fileProcessor,
@Nullable VirtualFileFilter directoryFilter) {
myProject = project;
myPathProcessor = pathProcessor;
myFileProcessor = fileProcessor;
myDirectoryFilter = directoryFilter;
myRoot = root;
myVcsManager = ProjectLevelVcsManager.getInstance(project);
final AbstractVcs vcs = myVcsManager.getVcsFor(root);
myRootPresentFilter = vcs == null ? null : new MyRootFilter(root, vcs.getName());
if (myRootPresentFilter != null) {
myRootPresentFilter.init(myVcsManager.getAllVcsRoots());
}
}
public void iterate() {
VfsUtilCore.visitChildrenRecursively(myRoot, new VirtualFileVisitor(VirtualFileVisitor.NO_FOLLOW_SYMLINKS) {
@Override
public void afterChildrenVisited(@NotNull VirtualFile file) {
if (myDirectoryFilter != null) {
myDirectoryFilter.afterChildrenVisited(file);
}
}
@NotNull
@Override
public Result visitFileEx(@NotNull VirtualFile file) {
if (isIgnoredByVcs(myVcsManager, myProject, file)) return SKIP_CHILDREN;
if (myRootPresentFilter != null && !myRootPresentFilter.accept(file)) return SKIP_CHILDREN;
if (myProject.isDisposed() || !process(file)) return skipTo(myRoot);
if (myDirectoryFilter != null && file.isDirectory() && !myDirectoryFilter.shouldGoIntoDirectory(file)) return SKIP_CHILDREN;
return CONTINUE;
}
});
}
private boolean process(VirtualFile current) {
if (myPathProcessor != null) {
return myPathProcessor.process(new FilePathImpl(current));
}
else if (myFileProcessor != null) {
return myFileProcessor.process(current);
}
return false;
}
}
}