2 * Copyright 2000-2010 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.compiler.impl;
18 import com.intellij.compiler.impl.newApi.*;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.compiler.*;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.progress.ProcessCanceledException;
23 import com.intellij.openapi.project.DumbService;
24 import com.intellij.openapi.project.Project;
25 import com.intellij.openapi.util.Pair;
26 import com.intellij.openapi.util.Ref;
27 import com.intellij.util.CommonProcessors;
28 import com.intellij.util.Processor;
29 import com.intellij.util.io.KeyDescriptor;
30 import gnu.trove.THashSet;
31 import gnu.trove.TObjectHashingStrategy;
32 import org.jetbrains.annotations.NotNull;
35 import java.io.IOException;
41 public class NewCompilerRunner {
42 private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.NewCompilerRunner");
43 private CompileContext myContext;
44 private final boolean myForceCompile;
45 private final boolean myOnlyCheckStatus;
46 private final NewCompiler<?,?>[] myCompilers;
47 private final Project myProject;
49 public NewCompilerRunner(CompileContext context, CompilerManager compilerManager, boolean forceCompile, boolean onlyCheckStatus) {
51 myForceCompile = forceCompile;
52 myOnlyCheckStatus = onlyCheckStatus;
53 myCompilers = compilerManager.getCompilers(NewCompiler.class);
54 myProject = myContext.getProject();
57 public boolean invokeCompilers(NewCompiler.CompileOrderPlace place) throws CompileDriver.ExitException {
58 boolean didSomething = false;
60 for (NewCompiler<?, ?> compiler : myCompilers) {
61 if (compiler.getOrderPlace().equals(place)) {
62 didSomething = invokeCompiler(compiler);
66 catch (IOException e) {
68 myContext.requestRebuildNextTime(e.getMessage());
69 throw new CompileDriver.ExitException(CompileDriver.ExitStatus.ERRORS);
71 catch (CompileDriver.ExitException e) {
74 catch (ProcessCanceledException e) {
79 myContext.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.exception", e.getMessage()), null, -1, -1);
84 private <T extends BuildTarget, Key, State> boolean invokeCompiler(NewCompiler<Key, State> compiler) throws IOException, CompileDriver.ExitException {
85 return invokeCompiler(compiler, compiler.createInstance(myContext));
88 private <T extends BuildTarget, Item extends CompileItem<Key, State>, Key, State>
89 boolean invokeCompiler(NewCompiler<Key, State> compiler, CompilerInstance<T, Item, Key, State> instance) throws IOException, CompileDriver.ExitException {
90 NewCompilerCache<Key, State> cache = CompilerCacheManager.getInstance(myProject).getNewCompilerCache(compiler);
91 NewCompilerPersistentData data = new NewCompilerPersistentData(getNewCompilerCacheDir(myProject, compiler), compiler.getVersion());
92 if (data.isVersionChanged()) {
93 LOG.info("Clearing cache for " + compiler.getDescription());
97 Set<String> targetsToRemove = new HashSet<String>(data.getAllTargets());
98 for (T target : instance.getAllTargets()) {
99 targetsToRemove.remove(target.getId());
101 if (!myOnlyCheckStatus) {
102 for (String target : targetsToRemove) {
103 int id = data.removeId(target);
104 if (LOG.isDebugEnabled()) {
105 LOG.debug("Removing obsolete target '" + target + "' (id=" + id + ")");
107 List<Key> keys = new ArrayList<Key>();
108 cache.processSources(id, new CommonProcessors.CollectProcessor<Key>(keys));
109 List<Pair<Key, State>> obsoleteSources = new ArrayList<Pair<Key, State>>();
110 for (Key key : keys) {
111 final State state = cache.getState(id, key);
112 obsoleteSources.add(Pair.create(key, state));
114 instance.processObsoleteTarget(target, obsoleteSources);
115 if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
118 for (Key key : keys) {
119 cache.remove(id, key);
124 boolean didSomething = false;
125 for (T target : instance.getSelectedTargets()) {
126 int id = data.getId(target.getId());
127 didSomething |= processTarget(target, id, compiler, instance, cache);
134 public static File getNewCompilerCacheDir(Project project, NewCompiler<?, ?> compiler) {
135 return new File(CompilerPaths.getCacheStoreDirectory(project), compiler.getId());
138 private <T extends BuildTarget, Item extends CompileItem<Key, State>, Key, State>
139 boolean processTarget(T target, final int targetId, final NewCompiler<Key, State> compiler, final CompilerInstance<T, Item, Key, State> instance,
140 final NewCompilerCache<Key, State> cache) throws IOException, CompileDriver.ExitException {
141 if (LOG.isDebugEnabled()) {
142 LOG.debug("Processing target '" + target + "' (id=" + targetId + ")");
144 final List<Item> items = instance.getItems(target);
145 if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) return true;
147 final List<Pair<Item, State>> toProcess = new ArrayList<Pair<Item, State>>();
148 final THashSet<Key> keySet = new THashSet<Key>(new SourceItemHashingStrategy<Key>(compiler));
149 final Ref<IOException> exception = Ref.create(null);
150 DumbService.getInstance(myProject).waitForSmartMode();
151 ApplicationManager.getApplication().runReadAction(new Runnable() {
155 for (Item item : items) {
156 final Key key = item.getKey();
158 State output = cache.getState(targetId, key);
159 if (myForceCompile || output == null || !item.isUpToDate(output)) {
160 toProcess.add(Pair.create(item, output));
164 catch (IOException e) {
169 if (!exception.isNull()) {
170 throw exception.get();
173 final List<Key> toRemove = new ArrayList<Key>();
174 cache.processSources(targetId, new Processor<Key>() {
176 public boolean process(Key key) {
177 if (!keySet.contains(key)) {
184 if (LOG.isDebugEnabled()) {
185 LOG.debug(toProcess.size() + " items will be processed, " + toRemove.size() + " items will be removed");
188 if (toProcess.isEmpty() && toRemove.isEmpty()) {
192 if (myOnlyCheckStatus) {
193 throw new CompileDriver.ExitException(CompileDriver.ExitStatus.CANCELLED);
196 List<Pair<Key, State>> obsoleteItems = new ArrayList<Pair<Key, State>>();
197 for (Key key : toRemove) {
198 obsoleteItems.add(Pair.create(key, cache.getState(targetId, key)));
201 final List<Item> processedItems = new ArrayList<Item>();
202 final List<File> toRefresh = new ArrayList<File>();
203 instance.processItems(target, toProcess, obsoleteItems, new CompilerInstance.OutputConsumer<Item>() {
205 public void addFileToRefresh(@NotNull File file) {
209 public void addProcessedItem(@NotNull Item sourceItem) {
210 processedItems.add(sourceItem);
213 if (myContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) {
217 for (Key key : toRemove) {
218 cache.remove(targetId, key);
220 CompilerUtil.refreshIOFiles(toRefresh);
221 for (Item item : processedItems) {
222 cache.putOutput(targetId, item.getKey(), item.computeState());
229 private class SourceItemHashingStrategy<S> implements TObjectHashingStrategy<S> {
230 private KeyDescriptor<S> myKeyDescriptor;
232 public SourceItemHashingStrategy(NewCompiler<S, ?> compiler) {
233 myKeyDescriptor = compiler.getItemKeyDescriptor();
237 public int computeHashCode(S object) {
238 return myKeyDescriptor.getHashCode(object);
242 public boolean equals(S o1, S o2) {
243 return myKeyDescriptor.isEqual(o1, o2);