9fd2bf1dca403364e7698f323c63770eea18594b
[idea/community.git] / platform / vcs-impl / src / com / intellij / openapi / vcs / impl / VcsRootIterator.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.vcs.impl;
17
18 import com.intellij.lifecycle.PeriodicalTasksCloser;
19 import com.intellij.openapi.project.Project;
20 import com.intellij.openapi.roots.ExcludedFileIndex;
21 import com.intellij.openapi.util.Comparing;
22 import com.intellij.openapi.vcs.*;
23 import com.intellij.openapi.vfs.VirtualFile;
24 import com.intellij.util.PairProcessor;
25 import com.intellij.util.Processor;
26 import com.intellij.util.StringLenComparator;
27 import org.jetbrains.annotations.Nullable;
28
29 import java.util.*;
30
31 public class VcsRootIterator {
32   // folder path to files to be excluded
33   private final Map<String, MyRootFilter> myOtherVcsFolders;
34   private final ExcludedFileIndex myExcludedFileIndex;
35
36   public VcsRootIterator(final Project project, final AbstractVcs vcs) {
37     final ProjectLevelVcsManager plVcsManager = ProjectLevelVcsManager.getInstance(project);
38     myOtherVcsFolders = new HashMap<String, MyRootFilter>();
39     myExcludedFileIndex = PeriodicalTasksCloser.getInstance().safeGetService(project, ExcludedFileIndex.class);
40
41     final VcsRoot[] allRoots = plVcsManager.getAllVcsRoots();
42     final VirtualFile[] roots = plVcsManager.getRootsUnderVcs(vcs);
43     for (VirtualFile root : roots) {
44       final MyRootFilter rootPresentFilter = new MyRootFilter(root, vcs.getName());
45       rootPresentFilter.init(allRoots);
46       myOtherVcsFolders.put(root.getUrl(), rootPresentFilter);
47     }
48   }
49
50   public boolean acceptFolderUnderVcs(final VirtualFile vcsRoot, final VirtualFile file) {
51     final String vcsUrl = vcsRoot.getUrl();
52     final MyRootFilter rootFilter = myOtherVcsFolders.get(vcsUrl);
53     if ((rootFilter != null) && (! rootFilter.accept(file))) {
54       return false;
55     }
56     if (myExcludedFileIndex.isExcludedFile(file)) return false;
57     return true;
58   }
59
60   private static class MyRootFilter {
61     private final VirtualFile myRoot;
62     private final String myVcsName;
63
64     // virtual file URLs
65     private final List<String> myExcludedByOtherVcss;
66
67     private MyRootFilter(final VirtualFile root, final String vcsName) {
68       myRoot = root;
69       myVcsName = vcsName;
70
71       myExcludedByOtherVcss = new LinkedList<String>();
72     }
73
74     private void init(final VcsRoot[] allRoots) {
75       final String ourPath = myRoot.getUrl();
76
77       for (VcsRoot root : allRoots) {
78         if (Comparing.equal(root.vcs.getName(), myVcsName)) continue;
79         final String url = root.path.getUrl();
80         if (url.startsWith(ourPath)) {
81           myExcludedByOtherVcss.add(url);
82         }
83       }
84
85       Collections.sort(myExcludedByOtherVcss, StringLenComparator.getDescendingInstance());
86     }
87
88     public boolean accept(final VirtualFile vf) {
89       final String url = vf.getUrl();
90       for (String excludedByOtherVcs : myExcludedByOtherVcss) {
91         // use the fact that they are sorted
92         if (url.length() > excludedByOtherVcs.length()) return true;
93         if (url.startsWith(excludedByOtherVcs)) return false;
94       }
95       return true;
96     }
97   }
98
99   public static boolean iterateVcsRoot(final Project project, final VirtualFile root, final Processor<FilePath> processor) {
100     return iterateVcsRoot(project, root, processor, null);
101   }
102
103   public static boolean iterateVcsRoot(final Project project, final VirtualFile root, final Processor<FilePath> processor,
104                                        @Nullable PairProcessor<VirtualFile, VirtualFile[]> directoryFilter) {
105     final MyRootIterator rootIterator = new MyRootIterator(project, root, processor, directoryFilter);
106     return rootIterator.iterate();
107   }
108
109   private static class MyRootIterator {
110     private final Processor<FilePath> myProcessor;
111     @Nullable private final PairProcessor<VirtualFile, VirtualFile[]> myDirectoryFilter;
112     private final LinkedList<VirtualFile> myQueue;
113     private final MyRootFilter myRootPresentFilter;
114     private final ExcludedFileIndex myExcludedFileIndex;
115
116     private MyRootIterator(final Project project, final VirtualFile root, final Processor<FilePath> processor,
117                            @Nullable PairProcessor<VirtualFile, VirtualFile[]> directoryFilter) {
118       myProcessor = processor;
119       myDirectoryFilter = directoryFilter;
120
121       final ProjectLevelVcsManager plVcsManager = ProjectLevelVcsManager.getInstance(project);
122       final AbstractVcs vcs = plVcsManager.getVcsFor(root);
123       myRootPresentFilter = (vcs == null) ? null : new MyRootFilter(root, vcs.getName());
124       myExcludedFileIndex = PeriodicalTasksCloser.getInstance().safeGetService(project, ExcludedFileIndex.class);
125
126       myQueue = new LinkedList<VirtualFile>();
127       myQueue.add(root);
128     }
129
130     public boolean iterate() {
131       while (! myQueue.isEmpty()) {
132         final VirtualFile current = myQueue.removeFirst();
133         if (! myProcessor.process(new FilePathImpl(current))) return false;
134
135         if (current.isDirectory()) {
136           final VirtualFile[] files = current.getChildren();
137           if (myDirectoryFilter != null && ! myDirectoryFilter.process(current, files)) continue;
138
139           for (VirtualFile child : files) {
140             if (myRootPresentFilter != null && (! myRootPresentFilter.accept(child))) continue;
141             if (myExcludedFileIndex.isExcludedFile(child)) continue;
142             myQueue.add(child);
143           }
144         }
145       }
146       return true;
147     }
148   }
149 }