get rid of intellij.build.toolbox.litegen parameter and use BuildOptions.TOOLBOX_LITE...
[idea/community.git] / jps / jps-builders / src / org / jetbrains / jps / builders / impl / BuildRootIndexImpl.java
1 /*
2  * Copyright 2000-2012 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 org.jetbrains.jps.builders.impl;
17
18 import com.intellij.openapi.util.Key;
19 import com.intellij.openapi.util.io.FileUtil;
20 import com.intellij.openapi.util.io.FileUtilRt;
21 import com.intellij.util.SmartList;
22 import gnu.trove.THashMap;
23 import org.jetbrains.annotations.NotNull;
24 import org.jetbrains.annotations.Nullable;
25 import org.jetbrains.jps.builders.*;
26 import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
27 import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor;
28 import org.jetbrains.jps.builders.storage.BuildDataPaths;
29 import org.jetbrains.jps.incremental.CompileContext;
30 import org.jetbrains.jps.incremental.TargetTypeRegistry;
31 import org.jetbrains.jps.indices.IgnoredFileIndex;
32 import org.jetbrains.jps.indices.ModuleExcludeIndex;
33 import org.jetbrains.jps.model.JpsModel;
34 import org.jetbrains.jps.service.JpsServiceManager;
35
36 import java.io.File;
37 import java.io.FileFilter;
38 import java.util.*;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.ConcurrentMap;
41
42 /**
43  * @author nik
44  */
45 public class BuildRootIndexImpl implements BuildRootIndex {
46   private static final Key<Map<File, BuildRootDescriptor>> ROOT_DESCRIPTOR_MAP = Key.create("_root_to_descriptor_map");
47   private static final Key<Map<BuildTarget<?>, List<? extends BuildRootDescriptor>>> TEMP_TARGET_ROOTS_MAP = Key.create("_module_to_root_map");
48   private final IgnoredFileIndex myIgnoredFileIndex;
49   private final HashMap<BuildTarget<?>, List<? extends BuildRootDescriptor>> myRootsByTarget;
50   private final THashMap<File,List<BuildRootDescriptor>> myRootToDescriptors;
51   private final ConcurrentMap<BuildRootDescriptor, FileFilter> myFileFilters;
52   
53   public BuildRootIndexImpl(BuildTargetRegistry targetRegistry, JpsModel model, ModuleExcludeIndex index,
54                             BuildDataPaths dataPaths, final IgnoredFileIndex ignoredFileIndex) {
55     myIgnoredFileIndex = ignoredFileIndex;
56     myRootsByTarget = new HashMap<>();
57     myRootToDescriptors = new THashMap<>(FileUtil.FILE_HASHING_STRATEGY);
58     myFileFilters = new ConcurrentHashMap<>(16, 0.75f, 1);
59     final Iterable<AdditionalRootsProviderService> rootsProviders = JpsServiceManager.getInstance().getExtensions(AdditionalRootsProviderService.class);
60     for (BuildTargetType<?> targetType : TargetTypeRegistry.getInstance().getTargetTypes()) {
61       for (BuildTarget<?> target : targetRegistry.getAllTargets(targetType)) {
62         addRoots(dataPaths, rootsProviders, target, model, index, ignoredFileIndex);
63       }
64     }
65   }
66
67   private <R extends BuildRootDescriptor> void addRoots(BuildDataPaths dataPaths, Iterable<? extends AdditionalRootsProviderService> rootsProviders,
68                                                         BuildTarget<R> target,
69                                                         JpsModel model,
70                                                         ModuleExcludeIndex index,
71                                                         IgnoredFileIndex ignoredFileIndex) {
72     List<R> descriptors = target.computeRootDescriptors(model, index, ignoredFileIndex, dataPaths);
73     for (AdditionalRootsProviderService<?> provider : rootsProviders) {
74       if (provider.getTargetTypes().contains(target.getTargetType())) {
75         //noinspection unchecked
76         AdditionalRootsProviderService<R> providerService = (AdditionalRootsProviderService<R>)provider;
77         final List<R> additionalRoots = providerService.getAdditionalRoots(target, dataPaths);
78         if (!additionalRoots.isEmpty()) {
79           descriptors = new ArrayList<>(descriptors);
80           descriptors.addAll(additionalRoots);
81         }
82       }
83     }
84     for (BuildRootDescriptor descriptor : descriptors) {
85       registerDescriptor(descriptor);
86     }
87     if (descriptors instanceof ArrayList<?>) {
88       ((ArrayList)descriptors).trimToSize();
89     }
90     myRootsByTarget.put(target, descriptors);
91   }
92
93   private void registerDescriptor(BuildRootDescriptor descriptor) {
94     List<BuildRootDescriptor> list = myRootToDescriptors.get(descriptor.getRootFile());
95     if (list == null) {
96       list = new SmartList<>();
97       myRootToDescriptors.put(descriptor.getRootFile(), list);
98     }
99     list.add(descriptor);
100   }
101
102   @NotNull
103   @Override
104   public <R extends BuildRootDescriptor> List<R> getRootDescriptors(@NotNull File root,
105                                                                     @Nullable Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
106                                                                     @Nullable CompileContext context) {
107     List<BuildRootDescriptor> descriptors = myRootToDescriptors.get(root);
108     List<R> result = new SmartList<>();
109     if (descriptors != null) {
110       for (BuildRootDescriptor descriptor : descriptors) {
111         if (types == null || types.contains(descriptor.getTarget().getTargetType())) {
112           //noinspection unchecked
113           result.add((R)descriptor);
114         }
115       }
116     }
117     if (context != null) {
118       final Map<File, BuildRootDescriptor> contextMap = ROOT_DESCRIPTOR_MAP.get(context);
119       if (contextMap != null) {
120         BuildRootDescriptor descriptor = contextMap.get(root);
121         if (descriptor != null && (types == null || types.contains(descriptor.getTarget().getTargetType()))) {
122           //noinspection unchecked
123           result.add((R)descriptor);
124         }
125       }
126     }
127     return result;
128   }
129
130   @NotNull
131   @Override
132   public <R extends BuildRootDescriptor> List<R> getTargetRoots(@NotNull BuildTarget<R> target, CompileContext context) {
133     //noinspection unchecked
134     List<R> roots = (List<R>)myRootsByTarget.get(target);
135     if (context != null) {
136       final List<R> tempDescriptors = getTempTargetRoots(target, context);
137       if (!tempDescriptors.isEmpty()) {
138         if (roots != null) {
139           roots = new ArrayList<>(roots);
140           roots.addAll(tempDescriptors);
141         }
142         else {
143           roots = tempDescriptors;
144         }
145       }
146     }
147     return roots != null? Collections.unmodifiableList(roots) : Collections.emptyList();
148   }
149
150   @NotNull
151   @Override
152   public <R extends BuildRootDescriptor> List<R> getTempTargetRoots(@NotNull BuildTarget<R> target, @NotNull CompileContext context) {
153     final Map<BuildTarget<?>, List<? extends BuildRootDescriptor>> contextMap = TEMP_TARGET_ROOTS_MAP.get(context);
154     //noinspection unchecked
155     final List<R> rootList = contextMap != null? (List<R>)contextMap.get(target) : null;
156     return rootList != null ? rootList : Collections.emptyList();
157   }
158
159   @Override
160   public <R extends BuildRootDescriptor> void associateTempRoot(@NotNull CompileContext context, @NotNull BuildTarget<R> target, @NotNull R root) {
161     Map<File, BuildRootDescriptor> rootToDescriptorMap = ROOT_DESCRIPTOR_MAP.get(context);
162     if (rootToDescriptorMap == null) {
163       rootToDescriptorMap = new THashMap<>(FileUtil.FILE_HASHING_STRATEGY);
164       ROOT_DESCRIPTOR_MAP.set(context, rootToDescriptorMap);
165     }
166
167     Map<BuildTarget<?>, List<? extends BuildRootDescriptor>> targetToRootMap = TEMP_TARGET_ROOTS_MAP.get(context);
168     if (targetToRootMap == null) {
169       targetToRootMap = new HashMap<>();
170       TEMP_TARGET_ROOTS_MAP.set(context, targetToRootMap);
171     }
172
173     final BuildRootDescriptor d = rootToDescriptorMap.get(root.getRootFile());
174     if (d != null) {
175       return;
176     }
177
178     //noinspection unchecked
179     List<R> targetRoots = (List<R>)targetToRootMap.get(target);
180     if (targetRoots == null) {
181       targetRoots = new ArrayList<>();
182       targetToRootMap.put(target, targetRoots);
183     }
184     rootToDescriptorMap.put(root.getRootFile(), root);
185     targetRoots.add(root);
186   }
187
188   @Override
189   @Nullable
190   public <R extends BuildRootDescriptor> R findParentDescriptor(@NotNull File file, @NotNull Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
191                                                                 @Nullable CompileContext context) {
192     File current = file;
193     int depth = 0;
194     while (current != null) {
195       final List<R> descriptors = filterDescriptorsByFile(getRootDescriptors(current, types, context), file, depth);
196       if (!descriptors.isEmpty()) {
197         return descriptors.get(0);
198       }
199       current = FileUtilRt.getParentFile(current);
200       depth++;
201     }
202     return null;
203   }
204
205   @Override
206   @NotNull
207   public <R extends BuildRootDescriptor> Collection<R> findAllParentDescriptors(@NotNull File file,
208                                                                                 @Nullable Collection<? extends BuildTargetType<? extends BuildTarget<R>>> types,
209                                                                                 @Nullable CompileContext context) {
210     File current = file;
211     List<R> result = null;
212     int depth = 0;
213     while (current != null) {
214       List<R> descriptors = filterDescriptorsByFile(getRootDescriptors(current, types, context), file, depth);
215       if (!descriptors.isEmpty()) {
216         if (result == null) {
217           result = descriptors;
218         }
219         else {
220           result = new ArrayList<>(result);
221           result.addAll(descriptors);
222         }
223       }
224       current = FileUtilRt.getParentFile(current);
225       depth++;
226     }
227     return result != null ? result : Collections.emptyList();
228   }
229
230   @NotNull
231   private <R extends BuildRootDescriptor> List<R> filterDescriptorsByFile(@NotNull List<R> descriptors, File file, int parentsToCheck) {
232     List<R> result = descriptors;
233     for (int i = 0; i < descriptors.size(); i++) {
234       R descriptor = descriptors.get(i);
235       if (isFileAccepted(file, descriptor) && isParentDirectoriesAccepted(file, parentsToCheck, descriptor)) {
236         if (result != descriptors) {
237           result.add(descriptor);
238         }
239       }
240       else if (result == descriptors) {
241         result = new ArrayList<>(descriptors.size() - 1);
242         for (int j = 0; j < i; j++) {
243           result.add(descriptors.get(j));
244         }
245       }
246     }
247     return result;
248   }
249
250   private boolean isParentDirectoriesAccepted(File file, int parentsToCheck, BuildRootDescriptor descriptor) {
251     File current = file;
252     while (parentsToCheck-- > 0) {
253       current = FileUtil.getParentFile(current);
254       if (!isDirectoryAccepted(current, descriptor)) {
255         return false;
256       }
257     }
258     return true;
259   }
260
261   @NotNull
262   @Override
263   public <R extends BuildRootDescriptor> Collection<R> findAllParentDescriptors(@NotNull File file, @Nullable CompileContext context) {
264     return findAllParentDescriptors(file, null, context);
265   }
266
267   @Override
268   @NotNull
269   public Collection<? extends BuildRootDescriptor> clearTempRoots(@NotNull CompileContext context) {
270     try {
271       final Map<File, BuildRootDescriptor> map = ROOT_DESCRIPTOR_MAP.get(context);
272       return map != null? map.values() : Collections.emptyList();
273     }
274     finally {
275       TEMP_TARGET_ROOTS_MAP.set(context, null);
276       ROOT_DESCRIPTOR_MAP.set(context, null);
277     }
278   }
279
280   @Override
281   @Nullable
282   public JavaSourceRootDescriptor findJavaRootDescriptor(@Nullable CompileContext context, File file) {
283     return findParentDescriptor(file, JavaModuleBuildTargetType.ALL_TYPES, context);
284   }
285
286   @NotNull
287   @Override
288   public FileFilter getRootFilter(@NotNull BuildRootDescriptor descriptor) {
289     FileFilter filter = myFileFilters.get(descriptor);
290     if (filter == null) {
291       filter = descriptor.createFileFilter();
292       myFileFilters.put(descriptor, filter);
293     }
294     return filter;
295   }
296
297   @Override
298   public boolean isFileAccepted(@NotNull File file, @NotNull BuildRootDescriptor descriptor) {
299     return !myIgnoredFileIndex.isIgnored(file.getName()) && getRootFilter(descriptor).accept(file);
300   }
301
302   @Override
303   public boolean isDirectoryAccepted(@NotNull File dir, @NotNull BuildRootDescriptor descriptor) {
304     return !myIgnoredFileIndex.isIgnored(dir.getName()) && !descriptor.getExcludedRoots().contains(dir);
305   }
306 }