1 package com
.intellij
.compiler
;
3 import com
.intellij
.compiler
.impl
.*;
4 import com
.intellij
.compiler
.impl
.javaCompiler
.JavaCompiler
;
5 import com
.intellij
.compiler
.impl
.packagingCompiler
.IncrementalPackagingCompiler
;
6 import com
.intellij
.compiler
.impl
.resourceCompiler
.ResourceCompiler
;
7 import com
.intellij
.compiler
.impl
.rmiCompiler
.RmicCompiler
;
8 import com
.intellij
.openapi
.compiler
.*;
9 import com
.intellij
.openapi
.compiler
.Compiler
;
10 import com
.intellij
.openapi
.extensions
.Extensions
;
11 import com
.intellij
.openapi
.fileTypes
.FileType
;
12 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
13 import com
.intellij
.openapi
.module
.Module
;
14 import com
.intellij
.openapi
.project
.Project
;
15 import com
.intellij
.openapi
.vfs
.LocalFileSystem
;
16 import com
.intellij
.openapi
.vfs
.VirtualFile
;
17 import com
.intellij
.packaging
.impl
.compiler
.IncrementalArtifactsCompiler
;
18 import com
.intellij
.util
.ArrayUtil
;
19 import com
.intellij
.util
.Chunk
;
20 import com
.intellij
.util
.containers
.ContainerUtil
;
21 import com
.intellij
.util
.graph
.CachingSemiGraph
;
22 import com
.intellij
.util
.graph
.Graph
;
23 import com
.intellij
.util
.graph
.GraphGenerator
;
24 import com
.intellij
.util
.messages
.MessageBus
;
25 import com
.intellij
.util
.messages
.MessageBusConnection
;
26 import org
.jetbrains
.annotations
.NotNull
;
27 import org
.jetbrains
.annotations
.Nullable
;
29 import java
.lang
.reflect
.Array
;
31 import java
.util
.concurrent
.Semaphore
;
33 public class CompilerManagerImpl
extends CompilerManager
{
34 private final Project myProject
;
36 private final List
<Compiler
> myCompilers
= new ArrayList
<Compiler
>();
37 private final List
<TranslatingCompiler
> myTranslators
= new ArrayList
<TranslatingCompiler
>();
39 private final List
<CompileTask
> myBeforeTasks
= new ArrayList
<CompileTask
>();
40 private final List
<CompileTask
> myAfterTasks
= new ArrayList
<CompileTask
>();
41 private final Set
<FileType
> myCompilableTypes
= new HashSet
<FileType
>();
42 private final CompilationStatusListener myEventPublisher
;
43 private final Semaphore myCompilationSemaphore
= new Semaphore(1, true);
44 private final Map
<Compiler
, Set
<FileType
>> myCompilerToInputTypes
= new HashMap
<Compiler
, Set
<FileType
>>();
45 private final Map
<Compiler
, Set
<FileType
>> myCompilerToOutputTypes
= new HashMap
<Compiler
, Set
<FileType
>>();
47 public CompilerManagerImpl(final Project project
, CompilerConfigurationImpl compilerConfiguration
, MessageBus messageBus
) {
49 myEventPublisher
= messageBus
.syncPublisher(CompilerTopics
.COMPILATION_STATUS
);
51 // predefined compilers
52 addTranslatingCompiler(new JavaCompiler(myProject
), new HashSet
<FileType
>(Arrays
.asList(StdFileTypes
.JAVA
)), new HashSet
<FileType
>(Arrays
.asList(StdFileTypes
.CLASS
)));
53 // todo: enable compiler later
54 //addCompiler(new AnnotationProcessingCompiler(project));
55 addCompiler(new ResourceCompiler(project
, compilerConfiguration
));
56 addCompiler(new RmicCompiler());
57 addCompiler(new IncrementalPackagingCompiler());
58 addCompiler(new IncrementalArtifactsCompiler());
60 for(Compiler compiler
: Extensions
.getExtensions(Compiler
.EP_NAME
, myProject
)) {
61 addCompiler(compiler
);
63 for(CompilerFactory factory
: Extensions
.getExtensions(CompilerFactory
.EP_NAME
, myProject
)) {
64 Compiler
[] compilers
= factory
.createCompilers(this);
65 for (Compiler compiler
: compilers
) {
66 addCompiler(compiler
);
70 addCompilableFileType(StdFileTypes
.JAVA
);
72 //addCompiler(new DummyTransformingCompiler()); // this one is for testing purposes only
73 //addCompiler(new DummySourceGeneratingCompiler(myProject)); // this one is for testing purposes only
76 ApplicationManager.getApplication().invokeLater(new Runnable() {
78 ApplicationManager.getApplication().runWriteAction(new Runnable() {
80 FileTypeManager.getInstance().registerFileType(DummyTranslatingCompiler.INPUT_FILE_TYPE, DummyTranslatingCompiler.FILETYPE_EXTENSION);
81 addTranslatingCompiler(
82 new DummyTranslatingCompiler(),
83 new HashSet<FileType>(Arrays.asList(DummyTranslatingCompiler.INPUT_FILE_TYPE)),
84 new HashSet<FileType>(Arrays.asList( StdFileTypes.JAVA))
94 public Semaphore
getCompilationSemaphore() {
95 return myCompilationSemaphore
;
98 public boolean isCompilationActive() {
99 return myCompilationSemaphore
.availablePermits() == 0;
102 public void addTranslatingCompiler(@NotNull final TranslatingCompiler compiler
, final Set
<FileType
> inputTypes
, final Set
<FileType
> outputTypes
) {
103 myTranslators
.add(compiler
);
104 myCompilerToInputTypes
.put(compiler
, inputTypes
);
105 myCompilerToOutputTypes
.put(compiler
, outputTypes
);
107 final List
<Chunk
<Compiler
>> chunks
= ModuleCompilerUtil
.getSortedChunks(createCompilerGraph((List
<Compiler
>)(List
)myTranslators
));
109 myTranslators
.clear();
110 for (Chunk
<Compiler
> chunk
: chunks
) {
111 for (Compiler chunkCompiler
: chunk
.getNodes()) {
112 myTranslators
.add((TranslatingCompiler
)chunkCompiler
);
118 public Set
<FileType
> getRegisteredInputTypes(@NotNull final TranslatingCompiler compiler
) {
119 final Set
<FileType
> inputs
= myCompilerToInputTypes
.get(compiler
);
120 return inputs
!= null? Collections
.unmodifiableSet(inputs
) : Collections
.<FileType
>emptySet();
124 public Set
<FileType
> getRegisteredOutputTypes(@NotNull final TranslatingCompiler compiler
) {
125 final Set
<FileType
> outs
= myCompilerToOutputTypes
.get(compiler
);
126 return outs
!= null? Collections
.unmodifiableSet(outs
) : Collections
.<FileType
>emptySet();
129 public final void addCompiler(@NotNull Compiler compiler
) {
130 if (compiler
instanceof TranslatingCompiler
) {
131 myTranslators
.add((TranslatingCompiler
)compiler
);
135 myCompilers
.add(compiler
);
139 public final void removeCompiler(@NotNull Compiler compiler
) {
140 if (compiler
instanceof TranslatingCompiler
) {
141 myTranslators
.remove(compiler
);
144 myCompilers
.remove(compiler
);
146 myCompilerToInputTypes
.remove(compiler
);
147 myCompilerToOutputTypes
.remove(compiler
);
151 public <T
extends Compiler
> T
[] getCompilers(@NotNull Class
<T
> compilerClass
) {
152 return getCompilers(compilerClass
, CompilerFilter
.ALL
);
156 public <T
extends Compiler
> T
[] getCompilers(@NotNull Class
<T
> compilerClass
, CompilerFilter filter
) {
157 final List
<T
> compilers
= new ArrayList
<T
>(myCompilers
.size());
158 for (final Compiler item
: myCompilers
) {
159 if (compilerClass
.isAssignableFrom(item
.getClass()) && filter
.acceptCompiler(item
)) {
160 compilers
.add((T
)item
);
163 for (final Compiler item
: myTranslators
) {
164 if (compilerClass
.isAssignableFrom(item
.getClass()) && filter
.acceptCompiler(item
)) {
165 compilers
.add((T
)item
);
168 final T
[] array
= (T
[])Array
.newInstance(compilerClass
, compilers
.size());
169 return compilers
.toArray(array
);
172 public void addCompilableFileType(@NotNull FileType type
) {
173 myCompilableTypes
.add(type
);
176 public void removeCompilableFileType(@NotNull FileType type
) {
177 myCompilableTypes
.remove(type
);
180 public boolean isCompilableFileType(@NotNull FileType type
) {
181 return myCompilableTypes
.contains(type
);
184 public final void addBeforeTask(@NotNull CompileTask task
) {
185 myBeforeTasks
.add(task
);
188 public final void addAfterTask(@NotNull CompileTask task
) {
189 myAfterTasks
.add(task
);
193 public CompileTask
[] getBeforeTasks() {
194 return myBeforeTasks
.toArray(new CompileTask
[myBeforeTasks
.size()]);
198 public CompileTask
[] getAfterTasks() {
199 return myAfterTasks
.toArray(new CompileTask
[myAfterTasks
.size()]);
202 public void compile(@NotNull VirtualFile
[] files
, CompileStatusNotification callback
, final boolean trackDependencies
) {
203 compile(createFilesCompileScope(files
), callback
, trackDependencies
);
206 public void compile(@NotNull Module module
, CompileStatusNotification callback
, final boolean trackDependencies
) {
207 compile(createModuleCompileScope(module
, false), callback
, trackDependencies
);
210 public void compile(@NotNull CompileScope scope
, CompileStatusNotification callback
, final boolean trackDependencies
) {
211 new CompileDriver(myProject
).compile(scope
, new ListenerNotificator(callback
), trackDependencies
);
214 public void make(CompileStatusNotification callback
) {
215 new CompileDriver(myProject
).make(createProjectCompileScope(myProject
), new ListenerNotificator(callback
));
218 public void make(@NotNull Module module
, CompileStatusNotification callback
) {
219 new CompileDriver(myProject
).make(createModuleCompileScope(module
, true), new ListenerNotificator(callback
));
222 public void make(@NotNull Project project
, @NotNull Module
[] modules
, CompileStatusNotification callback
) {
223 new CompileDriver(myProject
).make(createModuleGroupCompileScope(project
, modules
, true), new ListenerNotificator(callback
));
226 public void make(@NotNull CompileScope scope
, CompileStatusNotification callback
) {
227 new CompileDriver(myProject
).make(scope
, new ListenerNotificator(callback
));
230 public void make(@NotNull CompileScope scope
, CompilerFilter filter
, @Nullable CompileStatusNotification callback
) {
231 final CompileDriver compileDriver
= new CompileDriver(myProject
);
232 compileDriver
.setCompilerFilter(filter
);
233 compileDriver
.make(scope
, new ListenerNotificator(callback
));
236 public boolean isUpToDate(@NotNull final CompileScope scope
) {
237 return new CompileDriver(myProject
).isUpToDate(scope
);
240 public void rebuild(CompileStatusNotification callback
) {
241 new CompileDriver(myProject
).rebuild(new ListenerNotificator(callback
));
244 public void executeTask(@NotNull CompileTask task
, @NotNull CompileScope scope
, String contentName
, Runnable onTaskFinished
) {
245 final CompileDriver compileDriver
= new CompileDriver(myProject
);
246 compileDriver
.executeCompileTask(task
, scope
, contentName
, onTaskFinished
);
249 private final Map
<CompilationStatusListener
, MessageBusConnection
> myListenerAdapters
= new HashMap
<CompilationStatusListener
, MessageBusConnection
>();
251 public void addCompilationStatusListener(@NotNull final CompilationStatusListener listener
) {
252 final MessageBusConnection connection
= myProject
.getMessageBus().connect();
253 myListenerAdapters
.put(listener
, connection
);
254 connection
.subscribe(CompilerTopics
.COMPILATION_STATUS
, listener
);
257 public void removeCompilationStatusListener(@NotNull final CompilationStatusListener listener
) {
258 final MessageBusConnection connection
= myListenerAdapters
.remove(listener
);
259 if (connection
!= null) {
260 connection
.disconnect();
264 // Compiler tests support
266 private static List
<String
> ourDeletedPaths
;
267 private static List
<String
> ourRecompiledPaths
;
268 private static List
<String
> ourCompiledPaths
;
270 public static void testSetup() {
271 ourDeletedPaths
= new ArrayList
<String
>();
272 ourRecompiledPaths
= new ArrayList
<String
>();
273 ourCompiledPaths
= new ArrayList
<String
>();
277 * @param path a relative to output directory path
279 public static void addDeletedPath(String path
) {
280 ourDeletedPaths
.add(path
);
283 public static void addRecompiledPath(String path
) {
284 ourRecompiledPaths
.add(path
);
287 public static void addCompiledPath(String path
) {
288 ourCompiledPaths
.add(path
);
291 public static String
[] getPathsToDelete() {
292 return ArrayUtil
.toStringArray(ourDeletedPaths
);
295 public static String
[] getPathsToRecompile() {
296 return ArrayUtil
.toStringArray(ourRecompiledPaths
);
299 public static String
[] getPathsToCompile() {
300 return ArrayUtil
.toStringArray(ourCompiledPaths
);
303 public static void clearPathsToCompile() {
304 if (ourCompiledPaths
!= null) {
305 ourCompiledPaths
.clear();
309 public boolean isExcludedFromCompilation(@NotNull VirtualFile file
) {
310 return CompilerConfiguration
.getInstance(myProject
).isExcludedFromCompilation(file
);
313 private static final OutputToSourceMapping OUTPUT_TO_SOURCE_MAPPING
= new OutputToSourceMapping() {
314 public String
getSourcePath(final String outputPath
) {
315 final LocalFileSystem lfs
= LocalFileSystem
.getInstance();
316 final VirtualFile outputFile
= lfs
.findFileByPath(outputPath
);
318 final VirtualFile sourceFile
= outputFile
!= null ? TranslatingCompilerFilesMonitor
.getSourceFileByOutput(outputFile
) : null;
319 return sourceFile
!= null? sourceFile
.getPath() : null;
323 public OutputToSourceMapping
getJavaCompilerOutputMapping() {
324 return OUTPUT_TO_SOURCE_MAPPING
;
328 public CompileScope
createFilesCompileScope(@NotNull final VirtualFile
[] files
) {
329 CompileScope
[] scopes
= new CompileScope
[files
.length
];
330 for(int i
= 0; i
< files
.length
; i
++){
331 scopes
[i
] = new OneProjectItemCompileScope(myProject
, files
[i
]);
333 return new CompositeScope(scopes
);
337 public CompileScope
createModuleCompileScope(@NotNull final Module module
, final boolean includeDependentModules
) {
338 return new ModuleCompileScope(module
, includeDependentModules
);
342 public CompileScope
createModulesCompileScope(@NotNull final Module
[] modules
, final boolean includeDependentModules
) {
343 return new ModuleCompileScope(myProject
, modules
, includeDependentModules
);
347 public CompileScope
createModuleGroupCompileScope(@NotNull final Project project
, @NotNull final Module
[] modules
, final boolean includeDependentModules
) {
348 return new ModuleCompileScope(project
, modules
, includeDependentModules
);
352 public CompileScope
createProjectCompileScope(@NotNull final Project project
) {
353 return new ProjectCompileScope(project
);
356 private Graph
<Compiler
> createCompilerGraph(final List
<Compiler
> compilers
) {
357 return GraphGenerator
.create(CachingSemiGraph
.create(new GraphGenerator
.SemiGraph
<Compiler
>() {
358 public Collection
<Compiler
> getNodes() {
362 public Iterator
<Compiler
> getIn(Compiler compiler
) {
363 final Set
<FileType
> compilerInput
= myCompilerToInputTypes
.get(compiler
);
364 if (compilerInput
== null || compilerInput
.isEmpty()) {
365 return Collections
.<Compiler
>emptySet().iterator();
368 final Set
<Compiler
> inCompilers
= new HashSet
<Compiler
>();
370 for (Map
.Entry
<Compiler
, Set
<FileType
>> entry
: myCompilerToOutputTypes
.entrySet()) {
371 final Set
<FileType
> outputs
= entry
.getValue();
372 Compiler comp
= entry
.getKey();
373 if (outputs
!= null && ContainerUtil
.intersects(compilerInput
, outputs
)) {
374 inCompilers
.add(comp
);
377 return inCompilers
.iterator();
382 private class ListenerNotificator
implements CompileStatusNotification
{
383 private final CompileStatusNotification myDelegate
;
385 private ListenerNotificator(CompileStatusNotification delegate
) {
386 myDelegate
= delegate
;
389 public void finished(boolean aborted
, int errors
, int warnings
, final CompileContext compileContext
) {
390 myEventPublisher
.compilationFinished(aborted
, errors
, warnings
, compileContext
);
391 if (myDelegate
!= null) {
392 myDelegate
.finished(aborted
, errors
, warnings
, compileContext
);