diff --git a/ide-compiler-runner/ide-compiler-runner.iml b/ide-compiler-runner/ide-compiler-runner.iml
index 8aa91671dfd..4707ed53d80 100644
--- a/ide-compiler-runner/ide-compiler-runner.iml
+++ b/ide-compiler-runner/ide-compiler-runner.iml
@@ -8,6 +8,8 @@
+
+
diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/CompilerEnvironment.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerEnvironment.java
similarity index 98%
rename from idea/src/org/jetbrains/jet/plugin/compiler/CompilerEnvironment.java
rename to ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerEnvironment.java
index cb6faad0bec..8a059e5cd69 100644
--- a/idea/src/org/jetbrains/jet/plugin/compiler/CompilerEnvironment.java
+++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerEnvironment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.jetbrains.jet.plugin.compiler;
+package org.jetbrains.jet.compiler.runner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
diff --git a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java
new file mode 100644
index 00000000000..96e73d79ec8
--- /dev/null
+++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/CompilerRunnerUtil.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright 2010-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.jet.compiler.runner;
+
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.Function;
+import com.intellij.util.containers.ContainerUtil;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
+import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
+import org.jetbrains.jet.cli.common.messages.MessageCollector;
+import org.jetbrains.jet.cli.common.messages.MessageRenderer;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.*;
+import java.lang.ref.SoftReference;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.*;
+
+import static org.jetbrains.jet.cli.common.messages.CompilerMessageLocation.NO_LOCATION;
+import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.*;
+
+public class CompilerRunnerUtil {
+ private static SoftReference ourClassLoaderRef = new SoftReference(null);
+
+ public static List kompilerClasspath(File kotlinHome, MessageCollector messageCollector) {
+ File libs = new File(kotlinHome, "lib");
+
+ if (!libs.exists() || libs.isFile()) {
+ messageCollector.report(ERROR, "Broken compiler at '" + libs.getAbsolutePath() + "'. Make sure plugin is properly installed", NO_LOCATION);
+ return Collections.emptyList();
+ }
+
+ ArrayList answer = new ArrayList();
+ answer.add(new File(libs, "kotlin-compiler.jar"));
+ return answer;
+ }
+
+ public static URLClassLoader getOrCreateClassLoader(File kotlinHome, MessageCollector messageCollector) {
+ URLClassLoader answer = ourClassLoaderRef.get();
+ if (answer == null) {
+ answer = createClassloader(kotlinHome, messageCollector);
+ ourClassLoaderRef = new SoftReference(answer);
+ }
+ return answer;
+ }
+
+ private static URLClassLoader createClassloader(File kotlinHome, MessageCollector messageCollector) {
+ List jars = kompilerClasspath(kotlinHome, messageCollector);
+ URL[] urls = new URL[jars.size()];
+ for (int i = 0; i < urls.length; i++) {
+ try {
+ urls[i] = jars.get(i).toURI().toURL();
+ }
+ catch (MalformedURLException e) {
+ throw new RuntimeException(e); // Checked exceptions are great! I love them, and I love brilliant library designers too!
+ }
+ }
+ return new URLClassLoader(urls, null);
+ }
+
+ static void handleProcessTermination(int exitCode, MessageCollector messageCollector) {
+ if (exitCode != 0 && exitCode != 1) {
+ messageCollector.report(ERROR, "Compiler terminated with exit code: " + exitCode, NO_LOCATION);
+ }
+ }
+
+ public static void parseCompilerMessagesFromReader(MessageCollector messageCollector, final Reader reader, OutputItemsCollector collector) {
+ // Sometimes the compiler can't output valid XML
+ // Example: error in command line arguments passed to the compiler
+ // having no -tags key (arguments are not parsed), the compiler doesn't know
+ // if it should put any tags in the output, so it will simply print the usage
+ // and the SAX parser will break.
+ // In this case, we want to read everything from this stream
+ // and report it as an IDE error.
+ final StringBuilder stringBuilder = new StringBuilder();
+ //noinspection IOResourceOpenedButNotSafelyClosed
+ Reader wrappingReader = new Reader() {
+
+ @Override
+ public int read(char[] cbuf, int off, int len) throws IOException {
+ int read = reader.read(cbuf, off, len);
+ stringBuilder.append(cbuf, off, len);
+ return read;
+ }
+
+ @Override
+ public void close() throws IOException {
+ // Do nothing:
+ // If the SAX parser sees a syntax error, it throws an exception
+ // and calls close() on the reader.
+ // We prevent hte reader from being closed here, and close it later,
+ // when all the text is read from it
+ }
+ };
+ try {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser parser = factory.newSAXParser();
+ parser.parse(new InputSource(wrappingReader), new CompilerOutputSAXHandler(messageCollector, collector));
+ }
+ catch (Throwable e) {
+
+ // Load all the text into the stringBuilder
+ try {
+ // This will not close the reader (see the wrapper above)
+ FileUtil.loadTextAndClose(wrappingReader);
+ }
+ catch (IOException ioException) {
+ reportException(messageCollector, ioException);
+ }
+ String message = stringBuilder.toString();
+ reportException(messageCollector, new IllegalStateException(message, e));
+ messageCollector.report(ERROR, message, NO_LOCATION);
+ }
+ finally {
+ try {
+ reader.close();
+ }
+ catch (IOException e) {
+ reportException(messageCollector, e);
+ }
+ }
+ }
+
+ public static int getReturnCodeFromObject(Object rc) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+ if ("org.jetbrains.jet.cli.common.ExitCode".equals(rc.getClass().getCanonicalName())) {
+ return (Integer)rc.getClass().getMethod("getCode").invoke(rc);
+ }
+ else {
+ throw new IllegalStateException("Unexpected return: " + rc);
+ }
+ }
+
+ public static Object invokeExecMethod(CompilerEnvironment environment,
+ PrintStream out,
+ MessageCollector messageCollector, String[] arguments, String name) throws Exception {
+ URLClassLoader loader = getOrCreateClassLoader(environment.getKotlinHome(), messageCollector);
+ Class> kompiler = Class.forName(name, true, loader);
+ Method exec = kompiler.getMethod("exec", PrintStream.class, String[].class);
+ return exec.invoke(kompiler.newInstance(), out, arguments);
+ }
+
+ public static void outputCompilerMessagesAndHandleExitCode(@NotNull MessageCollector messageCollector,
+ @NotNull OutputItemsCollector outputItemsCollector,
+ @NotNull Function compilerRun) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(outputStream);
+
+ int exitCode = compilerRun.fun(out);
+
+ BufferedReader reader = new BufferedReader(new StringReader(outputStream.toString()));
+ parseCompilerMessagesFromReader(messageCollector, reader, outputItemsCollector);
+ handleProcessTermination(exitCode, messageCollector);
+ }
+
+ private static class CompilerOutputSAXHandler extends DefaultHandler {
+ private static final Map CATEGORIES = new ContainerUtil.ImmutableMapBuilder()
+ .put("error", ERROR)
+ .put("warning", WARNING)
+ .put("logging", LOGGING)
+ .put("exception", ERROR)
+ .put("info", INFO)
+ .put("messages", INFO) // Root XML element
+ .build();
+
+ private final MessageCollector messageCollector;
+ private final OutputItemsCollector collector;
+
+ private final StringBuilder message = new StringBuilder();
+ private Stack tags = new Stack();
+ private String path;
+ private int line;
+ private int column;
+
+ public CompilerOutputSAXHandler(MessageCollector messageCollector, OutputItemsCollector collector) {
+ this.messageCollector = messageCollector;
+ this.collector = collector;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
+ tags.push(qName);
+
+ message.setLength(0);
+
+ String rawPath = attributes.getValue("path");
+ path = rawPath == null ? null : "file://" + rawPath;
+ line = safeParseInt(attributes.getValue("line"), -1);
+ column = safeParseInt(attributes.getValue("column"), -1);
+ }
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ if (tags.size() == 1) {
+ // We're directly inside the root tag:
+ String message = new String(ch, start, length);
+ if (!message.trim().isEmpty()) {
+ messageCollector.report(ERROR, "Unhandled compiler output: " + message, NO_LOCATION);
+ }
+ }
+ else {
+ message.append(ch, start, length);
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ if (tags.size() == 1) {
+ // We're directly inside the root tag:
+ return;
+ }
+ String qNameLowerCase = qName.toLowerCase();
+ CompilerMessageSeverity category = CATEGORIES.get(qNameLowerCase);
+ if (category == null) {
+ messageCollector.report(ERROR, "Unknown compiler message tag: " + qName, NO_LOCATION);
+ category = INFO;
+ }
+ String text = message.toString();
+
+ if (category == LOGGING) {
+ collector.learn(text);
+ }
+ else {
+ messageCollector.report(category, text, CompilerMessageLocation.create(path, line, column));
+ }
+ tags.pop();
+ }
+
+ private static int safeParseInt(@Nullable String value, int defaultValue) {
+ if (value == null) {
+ return defaultValue;
+ }
+ try {
+ return Integer.parseInt(value.trim());
+ }
+ catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+ }
+
+ public static void reportException(@NotNull MessageCollector messageCollector, @NotNull Throwable e) {
+ messageCollector.report(EXCEPTION, MessageRenderer.PLAIN.renderException(e), NO_LOCATION);
+ }
+}
diff --git a/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinCompilerRunner.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinCompilerRunner.java
new file mode 100644
index 00000000000..ab0212ce7f0
--- /dev/null
+++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/KotlinCompilerRunner.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2010-2012 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.jet.compiler.runner;
+
+import com.intellij.execution.configurations.GeneralCommandLine;
+import com.intellij.execution.configurations.SimpleJavaParameters;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.projectRoots.JavaSdkType;
+import com.intellij.openapi.projectRoots.JdkUtil;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.projectRoots.SimpleJavaSdkType;
+import com.intellij.openapi.util.io.FileUtil;
+import com.intellij.util.Function;
+import com.intellij.util.SystemProperties;
+import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
+import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
+import org.jetbrains.jet.cli.common.messages.MessageCollector;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.Arrays;
+
+public class KotlinCompilerRunner {
+ public static void runCompiler(
+ MessageCollector messageCollector,
+ CompilerEnvironment environment,
+ File scriptFile,
+ OutputItemsCollector collector,
+ boolean runOutOfProcess
+ ) {
+ if (runOutOfProcess) {
+ runOutOfProcess(messageCollector, collector, environment, scriptFile);
+ }
+ else {
+ runInProcess(messageCollector, collector, environment, scriptFile);
+ }
+ }
+
+ private static void runInProcess(final MessageCollector messageCollector,
+ OutputItemsCollector collector,
+ final CompilerEnvironment environment,
+ final File scriptFile) {
+ CompilerRunnerUtil.outputCompilerMessagesAndHandleExitCode(messageCollector, collector, new Function() {
+ @Override
+ public Integer fun(PrintStream stream) {
+ return execInProcess(environment, scriptFile, stream, messageCollector);
+ }
+ });
+ }
+
+ private static int execInProcess(CompilerEnvironment environment, File scriptFile, PrintStream out, MessageCollector messageCollector) {
+ try {
+ String compilerClassName = "org.jetbrains.jet.cli.jvm.K2JVMCompiler";
+ String[] arguments = commandLineArguments(environment.getOutput(), scriptFile);
+ messageCollector.report(CompilerMessageSeverity.INFO,
+ "Using kotlinHome=" + environment.getKotlinHome(),
+ CompilerMessageLocation.NO_LOCATION);
+ messageCollector.report(CompilerMessageSeverity.INFO,
+ "Invoking in-process compiler " + compilerClassName + " with arguments " + Arrays.asList(arguments),
+ CompilerMessageLocation.NO_LOCATION);
+ Object rc = CompilerRunnerUtil.invokeExecMethod(environment, out, messageCollector, arguments, compilerClassName);
+ // exec() returns a K2JVMCompiler.ExitCode object, that class is not accessible here,
+ // so we take it's contents through reflection
+ return CompilerRunnerUtil.getReturnCodeFromObject(rc);
+ }
+ catch (Throwable e) {
+ CompilerRunnerUtil.reportException(messageCollector, e);
+ return -1;
+ }
+ }
+
+ private static String[] commandLineArguments(File outputDir, File scriptFile) {
+ return new String[]{
+ "-module", scriptFile.getAbsolutePath(),
+ "-output", outputDir.getPath(),
+ "-tags", "-verbose", "-version",
+ "-noStdlib", "-noJdkAnnotations", "-noJdk"};
+ }
+
+ private static void runOutOfProcess(
+ final MessageCollector messageCollector,
+ final OutputItemsCollector itemCollector,
+ CompilerEnvironment environment,
+ File scriptFile
+ ) {
+ final SimpleJavaParameters params = new SimpleJavaParameters();
+ params.setJdk(new SimpleJavaSdkType().createJdk("tmp", SystemProperties.getJavaHome()));
+ params.setMainClass("org.jetbrains.jet.cli.jvm.K2JVMCompiler");
+
+ for (String arg : commandLineArguments(environment.getOutput(), scriptFile)) {
+ params.getProgramParametersList().add(arg);
+ }
+
+ for (File jar : CompilerRunnerUtil.kompilerClasspath(environment.getKotlinHome(), messageCollector)) {
+ params.getClassPath().add(jar);
+ }
+
+ params.getVMParametersList().addParametersString("-Djava.awt.headless=true -Xmx512m");
+ // params.getVMParametersList().addParametersString("-agentlib:yjpagent=sampling");
+
+ Sdk sdk = params.getJdk();
+
+ final GeneralCommandLine commandLine = JdkUtil.setupJVMCommandLine(
+ ((JavaSdkType) sdk.getSdkType()).getVMExecutablePath(sdk), params, false);
+
+ messageCollector.report(CompilerMessageSeverity.INFO,
+ "Invoking out-of-process compiler with arguments: " + commandLine,
+ CompilerMessageLocation.NO_LOCATION);
+
+ try {
+ final Process process = commandLine.createProcess();
+
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ CompilerRunnerUtil
+ .parseCompilerMessagesFromReader(messageCollector, new InputStreamReader(process.getInputStream()), itemCollector);
+ }
+ });
+
+ ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ FileUtil.loadBytes(process.getErrorStream());
+ }
+ catch (IOException e) {
+ // Don't care
+ }
+ }
+ });
+
+ int exitCode = process.waitFor();
+ CompilerRunnerUtil.handleProcessTermination(exitCode, messageCollector);
+ }
+ catch (Exception e) {
+ messageCollector.report(CompilerMessageSeverity.ERROR,
+ "[Internal Error] " + e.getLocalizedMessage(),
+ CompilerMessageLocation.NO_LOCATION);
+ return;
+ }
+ }
+
+}
diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/OutputItemsCollector.java b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/OutputItemsCollector.java
similarity index 94%
rename from idea/src/org/jetbrains/jet/plugin/compiler/OutputItemsCollector.java
rename to ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/OutputItemsCollector.java
index 49bf2881b77..1212759691d 100644
--- a/idea/src/org/jetbrains/jet/plugin/compiler/OutputItemsCollector.java
+++ b/ide-compiler-runner/src/org/jetbrains/jet/compiler/runner/OutputItemsCollector.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.jetbrains.jet.plugin.compiler;
+package org.jetbrains.jet.compiler.runner;
/**
* @author abreslav
diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/CompilerUtils.java b/idea/src/org/jetbrains/jet/plugin/compiler/CompilerUtils.java
index c31a99c6327..e3b2f5bb3c0 100644
--- a/idea/src/org/jetbrains/jet/plugin/compiler/CompilerUtils.java
+++ b/idea/src/org/jetbrains/jet/plugin/compiler/CompilerUtils.java
@@ -16,166 +16,28 @@
package org.jetbrains.jet.plugin.compiler;
-import com.google.common.collect.ImmutableMap;
import com.intellij.compiler.impl.javaCompiler.OutputItemImpl;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.TranslatingCompiler;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
-import jet.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
-import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
-import org.jetbrains.jet.cli.common.messages.MessageCollector;
-import org.jetbrains.jet.cli.common.messages.MessageRenderer;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.helpers.DefaultHandler;
+import org.jetbrains.jet.compiler.runner.CompilerEnvironment;
+import org.jetbrains.jet.compiler.runner.OutputItemsCollector;
-import javax.xml.parsers.SAXParser;
-import javax.xml.parsers.SAXParserFactory;
-import java.io.*;
-import java.lang.ref.SoftReference;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.*;
-
-import static org.jetbrains.jet.cli.common.messages.CompilerMessageLocation.NO_LOCATION;
-import static org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
/**
* @author Pavel Talanov
*/
public final class CompilerUtils {
- private static SoftReference ourClassLoaderRef = new SoftReference(null);
-
private CompilerUtils() {
}
- public static List kompilerClasspath(File kotlinHome, MessageCollector messageCollector) {
- File libs = new File(kotlinHome, "lib");
-
- if (!libs.exists() || libs.isFile()) {
- messageCollector.report(ERROR, "Broken compiler at '" + libs.getAbsolutePath() + "'. Make sure plugin is properly installed", NO_LOCATION);
- return Collections.emptyList();
- }
-
- ArrayList answer = new ArrayList();
- answer.add(new File(libs, "kotlin-compiler.jar"));
- return answer;
- }
-
- public static URLClassLoader getOrCreateClassLoader(File kotlinHome, MessageCollector messageCollector) {
- URLClassLoader answer = ourClassLoaderRef.get();
- if (answer == null) {
- answer = createClassloader(kotlinHome, messageCollector);
- ourClassLoaderRef = new SoftReference(answer);
- }
- return answer;
- }
-
- private static URLClassLoader createClassloader(File kotlinHome, MessageCollector messageCollector) {
- List jars = kompilerClasspath(kotlinHome, messageCollector);
- URL[] urls = new URL[jars.size()];
- for (int i = 0; i < urls.length; i++) {
- try {
- urls[i] = jars.get(i).toURI().toURL();
- }
- catch (MalformedURLException e) {
- throw new RuntimeException(e); // Checked exceptions are great! I love them, and I love brilliant library designers too!
- }
- }
- return new URLClassLoader(urls, null);
- }
-
- static void handleProcessTermination(int exitCode, MessageCollector messageCollector) {
- if (exitCode != 0 && exitCode != 1) {
- messageCollector.report(ERROR, "Compiler terminated with exit code: " + exitCode, NO_LOCATION);
- }
- }
-
- public static void parseCompilerMessagesFromReader(MessageCollector messageCollector, final Reader reader, OutputItemsCollector collector) {
- // Sometimes the compiler can't output valid XML
- // Example: error in command line arguments passed to the compiler
- // having no -tags key (arguments are not parsed), the compiler doesn't know
- // if it should put any tags in the output, so it will simply print the usage
- // and the SAX parser will break.
- // In this case, we want to read everything from this stream
- // and report it as an IDE error.
- final StringBuilder stringBuilder = new StringBuilder();
- //noinspection IOResourceOpenedButNotSafelyClosed
- Reader wrappingReader = new Reader() {
-
- @Override
- public int read(char[] cbuf, int off, int len) throws IOException {
- int read = reader.read(cbuf, off, len);
- stringBuilder.append(cbuf, off, len);
- return read;
- }
-
- @Override
- public void close() throws IOException {
- // Do nothing:
- // If the SAX parser sees a syntax error, it throws an exception
- // and calls close() on the reader.
- // We prevent hte reader from being closed here, and close it later,
- // when all the text is read from it
- }
- };
- try {
- SAXParserFactory factory = SAXParserFactory.newInstance();
- SAXParser parser = factory.newSAXParser();
- parser.parse(new InputSource(wrappingReader), new CompilerOutputSAXHandler(messageCollector, collector));
- }
- catch (Throwable e) {
-
- // Load all the text into the stringBuilder
- try {
- // This will not close the reader (see the wrapper above)
- FileUtil.loadTextAndClose(wrappingReader);
- }
- catch (IOException ioException) {
- reportException(messageCollector, ioException);
- }
- String message = stringBuilder.toString();
- reportException(messageCollector, new IllegalStateException(message, e));
- messageCollector.report(ERROR, message, NO_LOCATION);
- }
- finally {
- try {
- reader.close();
- }
- catch (IOException e) {
- reportException(messageCollector, e);
- }
- }
- }
-
- public static int getReturnCodeFromObject(Object rc) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
- if ("org.jetbrains.jet.cli.common.ExitCode".equals(rc.getClass().getCanonicalName())) {
- return (Integer)rc.getClass().getMethod("getCode").invoke(rc);
- }
- else {
- throw new IllegalStateException("Unexpected return: " + rc);
- }
- }
-
- public static Object invokeExecMethod(CompilerEnvironment environment,
- PrintStream out,
- MessageCollector messageCollector, String[] arguments, String name) throws Exception {
- URLClassLoader loader = getOrCreateClassLoader(environment.getKotlinHome(), messageCollector);
- Class> kompiler = Class.forName(name, true, loader);
- Method exec = kompiler.getMethod("exec", PrintStream.class, String[].class);
- return exec.invoke(kompiler.newInstance(), out, arguments);
- }
-
@NotNull
public static CompilerEnvironment getEnvironmentFor(@NotNull CompileContext compileContext, @NotNull Module module, boolean tests) {
VirtualFile mainOutput = compileContext.getModuleOutputDirectory(module);
@@ -189,92 +51,6 @@ public final class CompilerUtils {
return new File(file.getPath());
}
- private static class CompilerOutputSAXHandler extends DefaultHandler {
- private static final Map CATEGORIES = ImmutableMap.builder()
- .put("error", ERROR)
- .put("warning", WARNING)
- .put("logging", LOGGING)
- .put("exception", ERROR)
- .put("info", INFO)
- .put("messages", INFO) // Root XML element
- .build();
-
- private final MessageCollector messageCollector;
- private final OutputItemsCollector collector;
-
- private final StringBuilder message = new StringBuilder();
- private Stack tags = new Stack();
- private String path;
- private int line;
- private int column;
-
- public CompilerOutputSAXHandler(MessageCollector messageCollector, OutputItemsCollector collector) {
- this.messageCollector = messageCollector;
- this.collector = collector;
- }
-
- @Override
- public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
- tags.push(qName);
-
- message.setLength(0);
-
- String rawPath = attributes.getValue("path");
- path = rawPath == null ? null : "file://" + rawPath;
- line = safeParseInt(attributes.getValue("line"), -1);
- column = safeParseInt(attributes.getValue("column"), -1);
- }
-
- @Override
- public void characters(char[] ch, int start, int length) throws SAXException {
- if (tags.size() == 1) {
- // We're directly inside the root tag:
- String message = new String(ch, start, length);
- if (!message.trim().isEmpty()) {
- messageCollector.report(ERROR, "Unhandled compiler output: " + message, NO_LOCATION);
- }
- }
- else {
- message.append(ch, start, length);
- }
- }
-
- @Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
- if (tags.size() == 1) {
- // We're directly inside the root tag:
- return;
- }
- String qNameLowerCase = qName.toLowerCase();
- CompilerMessageSeverity category = CATEGORIES.get(qNameLowerCase);
- if (category == null) {
- messageCollector.report(ERROR, "Unknown compiler message tag: " + qName, NO_LOCATION);
- category = INFO;
- }
- String text = message.toString();
-
- if (category == LOGGING) {
- collector.learn(text);
- }
- else {
- messageCollector.report(category, text, CompilerMessageLocation.create(path, line, column));
- }
- tags.pop();
- }
-
- private static int safeParseInt(@Nullable String value, int defaultValue) {
- if (value == null) {
- return defaultValue;
- }
- try {
- return Integer.parseInt(value.trim());
- }
- catch (NumberFormatException e) {
- return defaultValue;
- }
- }
- }
-
public static class OutputItemsCollectorImpl implements OutputItemsCollector {
private static final String FOR_SOURCE_PREFIX = "For source: ";
private static final String EMITTING_PREFIX = "Emitting: ";
@@ -313,22 +89,5 @@ public final class CompilerUtils {
return sources;
}
}
-
- public static void outputCompilerMessagesAndHandleExitCode(@NotNull MessageCollector messageCollector,
- @NotNull OutputItemsCollector outputItemsCollector,
- @NotNull Function1 compilerRun) {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- PrintStream out = new PrintStream(outputStream);
-
- int exitCode = compilerRun.invoke(out);
-
- BufferedReader reader = new BufferedReader(new StringReader(outputStream.toString()));
- parseCompilerMessagesFromReader(messageCollector, reader, outputItemsCollector);
- handleProcessTermination(exitCode, messageCollector);
- }
-
- static void reportException(@NotNull MessageCollector messageCollector, @NotNull Throwable e) {
- messageCollector.report(EXCEPTION, MessageRenderer.PLAIN.renderException(e), NO_LOCATION);
- }
}
diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java
index cc410c7fdb6..4cebbe4adbb 100644
--- a/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java
+++ b/idea/src/org/jetbrains/jet/plugin/compiler/JetCompiler.java
@@ -17,40 +17,29 @@
package org.jetbrains.jet.plugin.compiler;
import com.intellij.compiler.impl.javaCompiler.ModuleChunk;
-import com.intellij.execution.configurations.GeneralCommandLine;
-import com.intellij.execution.configurations.SimpleJavaParameters;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompilerMessageCategory;
import com.intellij.openapi.compiler.TranslatingCompiler;
import com.intellij.openapi.compiler.ex.CompileContextEx;
import com.intellij.openapi.module.Module;
-import com.intellij.openapi.projectRoots.JavaSdkType;
-import com.intellij.openapi.projectRoots.JdkUtil;
-import com.intellij.openapi.projectRoots.Sdk;
-import com.intellij.openapi.projectRoots.SimpleJavaSdkType;
import com.intellij.openapi.roots.AnnotationOrderRootType;
import com.intellij.openapi.roots.OrderEnumerator;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Chunk;
import com.intellij.util.Function;
-import com.intellij.util.SystemProperties;
import com.intellij.util.containers.ContainerUtil;
-import jet.Function1;
import org.jetbrains.annotations.NotNull;
-import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
-import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
import org.jetbrains.jet.cli.common.messages.MessageCollector;
+import org.jetbrains.jet.compiler.runner.CompilerEnvironment;
+import org.jetbrains.jet.compiler.runner.KotlinCompilerRunner;
import org.jetbrains.jet.compiler.runner.KotlinModuleScriptGenerator;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.project.JsModuleDetector;
import java.io.File;
import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintStream;
import java.util.*;
/**
@@ -142,22 +131,7 @@ public class JetCompiler implements TranslatingCompiler {
File scriptFile,
CompilerUtils.OutputItemsCollectorImpl collector
) {
- runCompiler(messageCollector, environment, scriptFile, collector, RUN_OUT_OF_PROCESS);
- }
-
- private static void runCompiler(
- MessageCollector messageCollector,
- CompilerEnvironment environment,
- File scriptFile,
- CompilerUtils.OutputItemsCollectorImpl collector,
- boolean runOutOfProcess
- ) {
- if (runOutOfProcess) {
- runOutOfProcess(messageCollector, collector, environment, scriptFile);
- }
- else {
- runInProcess(messageCollector, collector, environment, scriptFile);
- }
+ KotlinCompilerRunner.runCompiler(messageCollector, environment, scriptFile, collector, RUN_OUT_OF_PROCESS);
}
public static File tryToWriteScriptFile(
@@ -223,111 +197,6 @@ public class JetCompiler implements TranslatingCompiler {
};
}
- private static void runInProcess(final MessageCollector messageCollector,
- OutputItemsCollector collector,
- final CompilerEnvironment environment,
- final File scriptFile) {
- CompilerUtils.outputCompilerMessagesAndHandleExitCode(messageCollector, collector, new Function1() {
- @Override
- public Integer invoke(PrintStream stream) {
- return execInProcess(environment, scriptFile, stream, messageCollector);
- }
- });
- }
-
- private static int execInProcess(CompilerEnvironment environment, File scriptFile, PrintStream out, MessageCollector messageCollector) {
- try {
- String compilerClassName = "org.jetbrains.jet.cli.jvm.K2JVMCompiler";
- String[] arguments = commandLineArguments(environment.getOutput(), scriptFile);
- messageCollector.report(CompilerMessageSeverity.INFO,
- "Using kotlinHome=" + environment.getKotlinHome(),
- CompilerMessageLocation.NO_LOCATION);
- messageCollector.report(CompilerMessageSeverity.INFO,
- "Invoking in-process compiler " + compilerClassName + " with arguments " + Arrays.asList(arguments),
- CompilerMessageLocation.NO_LOCATION);
- Object rc = CompilerUtils.invokeExecMethod(environment, out, messageCollector, arguments, compilerClassName);
- // exec() returns a K2JVMCompiler.ExitCode object, that class is not accessible here,
- // so we take it's contents through reflection
- return CompilerUtils.getReturnCodeFromObject(rc);
- }
- catch (Throwable e) {
- CompilerUtils.reportException(messageCollector, e);
- return -1;
- }
- }
-
- private static String[] commandLineArguments(File outputDir, File scriptFile) {
- return new String[]{
- "-module", scriptFile.getAbsolutePath(),
- "-output", outputDir.getPath(),
- "-tags", "-verbose", "-version",
- "-noStdlib", "-noJdkAnnotations", "-noJdk"};
- }
-
- private static void runOutOfProcess(
- final MessageCollector messageCollector,
- final OutputItemsCollector itemCollector,
- CompilerEnvironment environment,
- File scriptFile
- ) {
- final SimpleJavaParameters params = new SimpleJavaParameters();
- params.setJdk(new SimpleJavaSdkType().createJdk("tmp", SystemProperties.getJavaHome()));
- params.setMainClass("org.jetbrains.jet.cli.jvm.K2JVMCompiler");
-
- for (String arg : commandLineArguments(environment.getOutput(), scriptFile)) {
- params.getProgramParametersList().add(arg);
- }
-
- for (File jar : CompilerUtils.kompilerClasspath(environment.getKotlinHome(), messageCollector)) {
- params.getClassPath().add(jar);
- }
-
- params.getVMParametersList().addParametersString("-Djava.awt.headless=true -Xmx512m");
- // params.getVMParametersList().addParametersString("-agentlib:yjpagent=sampling");
-
- Sdk sdk = params.getJdk();
-
- final GeneralCommandLine commandLine = JdkUtil.setupJVMCommandLine(
- ((JavaSdkType)sdk.getSdkType()).getVMExecutablePath(sdk), params, false);
-
- messageCollector.report(CompilerMessageSeverity.INFO,
- "Invoking out-of-process compiler with arguments: " + commandLine,
- CompilerMessageLocation.NO_LOCATION);
-
- try {
- final Process process = commandLine.createProcess();
-
- ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
- @Override
- public void run() {
- CompilerUtils
- .parseCompilerMessagesFromReader(messageCollector, new InputStreamReader(process.getInputStream()), itemCollector);
- }
- });
-
- ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
- @Override
- public void run() {
- try {
- FileUtil.loadBytes(process.getErrorStream());
- }
- catch (IOException e) {
- // Don't care
- }
- }
- });
-
- int exitCode = process.waitFor();
- CompilerUtils.handleProcessTermination(exitCode, messageCollector);
- }
- catch (Exception e) {
- messageCollector.report(CompilerMessageSeverity.ERROR,
- "[Internal Error] " + e.getLocalizedMessage(),
- CompilerMessageLocation.NO_LOCATION);
- return;
- }
- }
-
private static List getAnnotationRootPaths(ModuleChunk chunk) {
List annotationPaths = ContainerUtil.newArrayList();
for (Module module : chunk.getModules()) {
diff --git a/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java b/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java
index 0f098ba6b3f..2e58c4ad048 100644
--- a/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java
+++ b/idea/src/org/jetbrains/jet/plugin/compiler/K2JSCompiler.java
@@ -30,14 +30,16 @@ import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Chunk;
+import com.intellij.util.Function;
import com.intellij.util.StringBuilderSpinAllocator;
import gnu.trove.THashSet;
-import jet.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.cli.common.messages.CompilerMessageLocation;
import org.jetbrains.jet.cli.common.messages.CompilerMessageSeverity;
import org.jetbrains.jet.cli.common.messages.MessageCollector;
+import org.jetbrains.jet.compiler.runner.CompilerEnvironment;
+import org.jetbrains.jet.compiler.runner.CompilerRunnerUtil;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.plugin.project.JsModuleDetector;
@@ -47,8 +49,8 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Set;
-import static org.jetbrains.jet.plugin.compiler.CompilerUtils.invokeExecMethod;
-import static org.jetbrains.jet.plugin.compiler.CompilerUtils.outputCompilerMessagesAndHandleExitCode;
+import static org.jetbrains.jet.compiler.runner.CompilerRunnerUtil.invokeExecMethod;
+import static org.jetbrains.jet.compiler.runner.CompilerRunnerUtil.outputCompilerMessagesAndHandleExitCode;
/**
* @author Pavel Talanov
@@ -91,9 +93,9 @@ public final class K2JSCompiler implements TranslatingCompiler {
private static void doCompile(@NotNull final MessageCollector messageCollector, @NotNull OutputSink sink, @NotNull final Module module,
@NotNull final CompilerEnvironment environment) {
CompilerUtils.OutputItemsCollectorImpl collector = new CompilerUtils.OutputItemsCollectorImpl(environment.getOutput().getPath());
- outputCompilerMessagesAndHandleExitCode(messageCollector, collector, new Function1() {
+ outputCompilerMessagesAndHandleExitCode(messageCollector, collector, new Function() {
@Override
- public Integer invoke(PrintStream stream) {
+ public Integer fun(PrintStream stream) {
return execInProcess(messageCollector, environment, stream, module);
}
});
@@ -136,7 +138,7 @@ public final class K2JSCompiler implements TranslatingCompiler {
assert virtualFile != null : "Virtual file not found for module output: " + outDir;
virtualFile.refresh(false, true);
}
- return CompilerUtils.getReturnCodeFromObject(rc);
+ return CompilerRunnerUtil.getReturnCodeFromObject(rc);
}
@NotNull