invoke translating compilers per-module chunk
[fedora-idea.git] / plugins / groovy / src / org / jetbrains / plugins / groovy / compiler / GroovyCompilerBase.java
blob7c23640f104c9cc7228bbce8280ac16f9a2d5264
1 /*
2 * Copyright 2000-2009 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.
17 package org.jetbrains.plugins.groovy.compiler;
19 import com.intellij.compiler.CompilerConfiguration;
20 import com.intellij.compiler.impl.CompilerUtil;
21 import com.intellij.compiler.impl.FileSetCompileScope;
22 import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
23 import com.intellij.execution.ExecutionException;
24 import com.intellij.execution.configurations.GeneralCommandLine;
25 import com.intellij.openapi.application.ApplicationManager;
26 import com.intellij.openapi.application.PathManager;
27 import com.intellij.openapi.compiler.CompileContext;
28 import com.intellij.openapi.compiler.CompilerMessageCategory;
29 import com.intellij.openapi.compiler.CompilerPaths;
30 import com.intellij.openapi.compiler.TranslatingCompiler;
31 import com.intellij.openapi.compiler.ex.CompileContextEx;
32 import com.intellij.openapi.diagnostic.Logger;
33 import com.intellij.openapi.fileTypes.StdFileTypes;
34 import com.intellij.openapi.module.JavaModuleType;
35 import com.intellij.openapi.module.Module;
36 import com.intellij.openapi.project.Project;
37 import com.intellij.openapi.projectRoots.JavaSdkType;
38 import com.intellij.openapi.projectRoots.Sdk;
39 import com.intellij.openapi.projectRoots.SdkType;
40 import com.intellij.openapi.roots.ModuleFileIndex;
41 import com.intellij.openapi.roots.ModuleRootManager;
42 import com.intellij.openapi.roots.OrderRootType;
43 import com.intellij.openapi.roots.libraries.Library;
44 import com.intellij.openapi.util.Comparing;
45 import com.intellij.openapi.util.io.FileUtil;
46 import com.intellij.openapi.vfs.CharsetToolkit;
47 import com.intellij.openapi.vfs.LocalFileSystem;
48 import com.intellij.openapi.vfs.VfsUtil;
49 import com.intellij.openapi.vfs.VirtualFile;
50 import com.intellij.openapi.vfs.encoding.EncodingProjectManager;
51 import com.intellij.psi.PsiClass;
52 import com.intellij.psi.PsiFile;
53 import com.intellij.psi.PsiManager;
54 import com.intellij.util.Chunk;
55 import com.intellij.util.PathUtil;
56 import com.intellij.util.PathsList;
57 import com.intellij.util.SmartList;
58 import com.intellij.util.containers.ContainerUtil;
59 import org.jetbrains.groovy.compiler.rt.CompilerMessage;
60 import org.jetbrains.groovy.compiler.rt.GroovycRunner;
61 import org.jetbrains.plugins.groovy.GroovyFileType;
62 import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
63 import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
65 import java.io.*;
66 import java.nio.charset.Charset;
67 import java.util.*;
69 /**
70 * @author peter
72 public abstract class GroovyCompilerBase implements TranslatingCompiler {
73 private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.compiler.GroovyCompilerBase");
74 protected final Project myProject;
76 public GroovyCompilerBase(Project project) {
77 myProject = project;
80 protected void runGroovycCompiler(CompileContext compileContext, final Module module,
81 final List<VirtualFile> toCompile,
82 boolean forStubs,
83 VirtualFile outputDir,
84 OutputSink sink, boolean tests) {
85 GeneralCommandLine commandLine = new GeneralCommandLine();
86 final Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
87 assert sdk != null; //verified before
88 SdkType sdkType = sdk.getSdkType();
89 assert sdkType instanceof JavaSdkType;
90 commandLine.setExePath(((JavaSdkType)sdkType).getVMExecutablePath(sdk));
92 final PathsList classPathBuilder = new PathsList();
93 classPathBuilder.add(PathUtil.getJarPathForClass(GroovycRunner.class));
95 final ModuleChunk chunk = createChunk(module, compileContext);
97 final Library[] libraries = GroovyConfigUtils.getInstance().getSDKLibrariesByModule(module);
98 if (libraries.length > 0) {
99 classPathBuilder.addVirtualFiles(Arrays.asList(libraries[0].getFiles(OrderRootType.COMPILATION_CLASSES)));
102 classPathBuilder.addVirtualFiles(chunk.getCompilationClasspathFiles());
103 appendOutputPath(module, classPathBuilder, false);
104 if (tests) {
105 appendOutputPath(module, classPathBuilder, true);
108 final List<String> patchers = new SmartList<String>();
109 for (final GroovyCompilerExtension extension : GroovyCompilerExtension.EP_NAME.getExtensions()) {
110 extension.enhanceCompilationClassPath(chunk, classPathBuilder);
111 patchers.addAll(extension.getCompilationUnitPatchers(chunk));
114 if ("true".equals(System.getProperty("profile.groovy.compiler"))) {
115 commandLine.addParameter("-Djava.library.path=" + PathManager.getBinPath());
116 commandLine.addParameter("-Dprofile.groovy.compiler=true");
117 commandLine.addParameter("-agentlib:yjpagent=disablej2ee,disablecounts,disablealloc,sessionname=GroovyCompiler");
118 classPathBuilder.add(PathManager.findFileInLibDirectory("yjp-controller-api-redist.jar").getAbsolutePath());
121 commandLine.addParameter("-cp");
122 commandLine.addParameter(classPathBuilder.getPathsString());
125 commandLine.addParameter("-Xmx" + GroovyCompilerConfiguration.getInstance(myProject).getHeapSize() + "m");
126 commandLine.addParameter("-XX:+HeapDumpOnOutOfMemoryError");
128 //debug
129 //commandLine.addParameter("-Xdebug"); commandLine.addParameter("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5239");
131 // Setting up process encoding according to locale
132 final ArrayList<String> list = new ArrayList<String>();
133 CompilerUtil.addLocaleOptions(list, false);
134 commandLine.addParameters(list);
136 commandLine.addParameter(GroovycRunner.class.getName());
138 try {
139 File fileWithParameters = File.createTempFile("toCompile", "");
140 fillFileWithGroovycParameters(toCompile, fileWithParameters, outputDir, patchers, getMainOutput(compileContext, module, tests));
142 commandLine.addParameter(forStubs ? "stubs" : "groovyc");
143 commandLine.addParameter(fileWithParameters.getPath());
145 catch (IOException e) {
146 LOG.error(e);
149 GroovycOSProcessHandler processHandler;
151 try {
152 processHandler = new GroovycOSProcessHandler(compileContext, commandLine.createProcess(), commandLine.getCommandLineString(), sink);
154 processHandler.startNotify();
155 processHandler.waitFor();
157 final List<VirtualFile> toRecompile = new ArrayList<VirtualFile>();
158 Set<File> toRecompileFiles = processHandler.getToRecompileFiles();
159 for (File toRecompileFile : toRecompileFiles) {
160 final VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(toRecompileFile);
161 LOG.assertTrue(vFile != null);
162 toRecompile.add(vFile);
165 final List<CompilerMessage> messages = processHandler.getCompilerMessages();
166 for (CompilerMessage compilerMessage : messages) {
167 final CompilerMessageCategory category;
168 category = getMessageCategory(compilerMessage);
170 final String url = compilerMessage.getUrl();
172 compileContext.addMessage(category, compilerMessage.getMessage(), VfsUtil.pathToUrl(FileUtil.toSystemIndependentName(url)), compilerMessage.getLineNum(),
173 compilerMessage.getColumnNum());
176 boolean hasMessages = !messages.isEmpty();
178 StringBuffer unparsedBuffer = processHandler.getUnparsedOutput();
179 if (unparsedBuffer.length() != 0) {
180 compileContext.addMessage(CompilerMessageCategory.ERROR, unparsedBuffer.toString(), null, -1, -1);
181 hasMessages = true;
184 final int exitCode = processHandler.getProcess().exitValue();
185 if (!hasMessages && exitCode != 0) {
186 compileContext.addMessage(CompilerMessageCategory.ERROR, "Internal groovyc error: code " + exitCode, null, -1, -1);
189 List<OutputItem> outputItems = processHandler.getSuccessfullyCompiled();
190 if (forStubs) {
191 List<VirtualFile> stubFiles = new ArrayList<VirtualFile>();
192 for (final OutputItem outputItem : outputItems) {
193 final File stub = new File(outputItem.getOutputPath());
194 CompilerUtil.refreshIOFile(stub);
195 final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(stub);
196 ContainerUtil.addIfNotNull(file, stubFiles);
198 ((CompileContextEx)compileContext).addScope(new FileSetCompileScope(stubFiles, new Module[]{module}));
199 outputItems = Collections.emptyList();
202 sink.add(outputDir.getPath(), outputItems, toRecompile.toArray(new VirtualFile[toRecompile.size()]));
204 catch (ExecutionException e) {
205 LOG.error(e);
209 protected static VirtualFile getMainOutput(CompileContext compileContext, Module module, boolean tests) {
210 return tests ? compileContext.getModuleOutputDirectoryForTests(module) : compileContext.getModuleOutputDirectory(module);
213 private static CompilerMessageCategory getMessageCategory(CompilerMessage compilerMessage) {
214 String category;
215 category = compilerMessage.getCategory();
217 if (CompilerMessage.ERROR.equals(category)) return CompilerMessageCategory.ERROR;
218 if (CompilerMessage.INFORMATION.equals(category)) return CompilerMessageCategory.INFORMATION;
219 if (CompilerMessage.STATISTICS.equals(category)) return CompilerMessageCategory.STATISTICS;
220 if (CompilerMessage.WARNING.equals(category)) return CompilerMessageCategory.WARNING;
222 return CompilerMessageCategory.ERROR;
225 private void fillFileWithGroovycParameters(List<VirtualFile> virtualFiles, File f, VirtualFile outputDir, final List<String> patchers, VirtualFile finalOutputDir) {
226 if (LOG.isDebugEnabled()) {
227 LOG.debug("Running groovyc on: " + virtualFiles.toString());
230 FileOutputStream stream;
231 try {
232 stream = new FileOutputStream(f);
234 catch (FileNotFoundException e) {
235 LOG.error(e);
236 return;
239 final PrintStream printer = new PrintStream(stream);
241 for (final VirtualFile item : virtualFiles) {
242 printer.println(GroovycRunner.SRC_FILE);
243 printer.println(item.getPath());
244 ApplicationManager.getApplication().runReadAction(new Runnable() {
245 public void run() {
246 final PsiFile file = PsiManager.getInstance(myProject).findFile(item);
247 if (file instanceof GroovyFileBase) {
248 for (PsiClass psiClass : ((GroovyFileBase)file).getClasses()) {
249 printer.println(psiClass.getQualifiedName());
254 printer.println(GroovycRunner.END);
257 if (!patchers.isEmpty()) {
258 printer.println(GroovycRunner.PATCHERS);
259 for (final String patcher : patchers) {
260 printer.println(patcher);
262 printer.println(GroovycRunner.END);
265 final Charset ideCharset = EncodingProjectManager.getInstance(myProject).getDefaultCharset();
266 if (!Comparing.equal(CharsetToolkit.getDefaultSystemCharset(), ideCharset)) {
267 printer.println(GroovycRunner.ENCODING);
268 printer.println(ideCharset.name());
271 printer.println(GroovycRunner.OUTPUTPATH);
272 printer.println(PathUtil.getLocalPath(outputDir));
274 printer.println(GroovycRunner.FINAL_OUTPUTPATH);
275 printer.println(PathUtil.getLocalPath(finalOutputDir));
278 printer.close();
281 private static void appendOutputPath(Module module, PathsList compileClasspath, final boolean forTestClasses) {
282 String output = CompilerPaths.getModuleOutputPath(module, forTestClasses);
283 if (output != null) {
284 compileClasspath.add(FileUtil.toSystemDependentName(output));
288 private static ModuleChunk createChunk(Module module, CompileContext context) {
289 return new ModuleChunk((CompileContextEx)context, new Chunk<Module>(module), Collections.<Module, List<VirtualFile>>emptyMap());
292 public void compile(final CompileContext compileContext, Chunk<Module> moduleChunk, final VirtualFile[] virtualFiles, OutputSink sink) {
293 Map<Module, List<VirtualFile>> mapModulesToVirtualFiles;
294 if (moduleChunk.getNodes().size() == 1) {
295 mapModulesToVirtualFiles = Collections.singletonMap(moduleChunk.getNodes().iterator().next(), Arrays.asList(virtualFiles));
297 else {
298 mapModulesToVirtualFiles = CompilerUtil.buildModuleToFilesMap(compileContext, virtualFiles);
300 for (final Module module : moduleChunk.getNodes()) {
301 final List<VirtualFile> moduleFiles = mapModulesToVirtualFiles.get(module);
302 if (moduleFiles == null) {
303 continue;
306 final ModuleFileIndex index = ModuleRootManager.getInstance(module).getFileIndex();
307 final List<VirtualFile> toCompile = new ArrayList<VirtualFile>();
308 final List<VirtualFile> toCompileTests = new ArrayList<VirtualFile>();
309 final CompilerConfiguration configuration = CompilerConfiguration.getInstance(myProject);
311 if (module.getModuleType() instanceof JavaModuleType) {
312 for (final VirtualFile file : moduleFiles) {
313 final boolean shouldCompile = !configuration.isResourceFile(file) &&
314 (file.getFileType() == GroovyFileType.GROOVY_FILE_TYPE ||
315 file.getFileType() == StdFileTypes.JAVA);
316 if (shouldCompile) {
317 (index.isInTestSourceContent(file) ? toCompileTests : toCompile).add(file);
322 if (!toCompile.isEmpty()) {
323 compileFiles(compileContext, module, toCompile, sink, false);
325 if (!toCompileTests.isEmpty()) {
326 compileFiles(compileContext, module, toCompileTests, sink, true);
333 protected abstract void compileFiles(CompileContext compileContext, Module module,
334 List<VirtualFile> toCompile, OutputSink sink, boolean tests);
336 public boolean isCompilableFile(VirtualFile file, CompileContext context) {
337 final boolean result = GroovyFileType.GROOVY_FILE_TYPE.equals(file.getFileType());
338 if (result && LOG.isDebugEnabled()) {
339 LOG.debug("compilable file: " + file.getPath());
341 return result;