diff --git a/jps/jps-plugin/jps-plugin.iml b/jps/jps-plugin/jps-plugin.iml index b7f14f215a5..21a11f39ee9 100644 --- a/jps/jps-plugin/jps-plugin.iml +++ b/jps/jps-plugin/jps-plugin.iml @@ -10,6 +10,7 @@ + diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerEnvironment.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerEnvironment.kt deleted file mode 100644 index 119b0357974..00000000000 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerEnvironment.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2010-2015 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.kotlin.compilerRunner - -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.config.Services -import org.jetbrains.kotlin.preloading.ClassCondition -import org.jetbrains.kotlin.utils.KotlinPaths -import org.jetbrains.kotlin.utils.PathUtil - -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation.Companion.NO_LOCATION -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR - -class CompilerEnvironment private constructor( - val kotlinPaths: KotlinPaths, - val classesToLoadByParent: ClassCondition, - val services: Services -) { - - fun success(): Boolean { - return kotlinPaths.homePath.exists() - } - - fun reportErrorsTo(messageCollector: MessageCollector) { - if (!kotlinPaths.homePath.exists()) { - messageCollector.report(ERROR, "Cannot find kotlinc home: " + kotlinPaths.homePath + ". Make sure plugin is properly installed, " + - "or specify " + PathUtil.JPS_KOTLIN_HOME_PROPERTY + " system property", NO_LOCATION) - } - } - - companion object { - fun getEnvironmentFor( - kotlinPaths: KotlinPaths, - classesToLoadByParent: ClassCondition, - compilerServices: Services - ): CompilerEnvironment { - return CompilerEnvironment(kotlinPaths, classesToLoadByParent, compilerServices) - } - } -} diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerOutputParser.java b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerOutputParser.java deleted file mode 100644 index beaebcab7f1..00000000000 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/CompilerOutputParser.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright 2010-2015 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.kotlin.compilerRunner; - -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.Stack; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation; -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity; -import org.jetbrains.kotlin.cli.common.messages.MessageCollector; -import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil; -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.IOException; -import java.io.Reader; -import java.util.Map; - -import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation.NO_LOCATION; -import static org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*; -import static org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil.reportException; - -public class CompilerOutputParser { - public static void parseCompilerMessagesFromReader(MessageCollector messageCollector, final Reader reader, OutputItemsCollector collector) { - // Sometimes the compiler doesn't output valid XML. - // Example: error in command line arguments passed to the compiler. - // The compiler will 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(); - Reader wrappingReader = new Reader() { - @Override - public int read(@NotNull 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); - } - } - } - - private static class CompilerOutputSAXHandler extends DefaultHandler { - private static final Map CATEGORIES = new ContainerUtil.ImmutableMapBuilder() - .put("error", ERROR) - .put("warning", WARNING) - .put("logging", LOGGING) - .put("output", OUTPUT) - .put("exception", EXCEPTION) - .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 final 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(@NotNull String uri, @NotNull String localName, @NotNull String qName, @NotNull Attributes attributes) - throws SAXException { - tags.push(qName); - - message.setLength(0); - - path = attributes.getValue("path"); - 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, @NotNull String localName, @NotNull 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 == OUTPUT) { - reportToCollector(text); - } - else { - messageCollector.report(category, text, CompilerMessageLocation.create(path, line, column, null)); - } - tags.pop(); - } - - private void reportToCollector(String text) { - OutputMessageUtil.Output output = OutputMessageUtil.parseOutputMessage(text); - if (output != null) { - collector.add(output.sourceFiles, output.outputFile); - } - } - - 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; - } - } - } -} diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt deleted file mode 100644 index 011550c9845..00000000000 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2010-2015 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.kotlin.compilerRunner - -import org.jetbrains.jps.api.GlobalOptions -import org.jetbrains.kotlin.cli.common.ExitCode -import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY -import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments -import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments -import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.jetbrains.kotlin.cli.common.arguments.mergeBeans -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.INFO -import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil -import org.jetbrains.kotlin.config.CompilerSettings -import org.jetbrains.kotlin.daemon.client.CompilationServices -import org.jetbrains.kotlin.daemon.client.DaemonReportMessage -import org.jetbrains.kotlin.daemon.client.DaemonReportingTargets -import org.jetbrains.kotlin.daemon.client.KotlinCompilerClient -import org.jetbrains.kotlin.daemon.common.* -import org.jetbrains.kotlin.jps.build.KotlinBuilder -import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents -import org.jetbrains.kotlin.progress.CompilationCanceledStatus -import java.io.* -import java.util.* -import java.util.concurrent.TimeUnit - -object KotlinCompilerRunner { - private val K2JVM_COMPILER = "org.jetbrains.kotlin.cli.jvm.K2JVMCompiler" - private val K2JS_COMPILER = "org.jetbrains.kotlin.cli.js.K2JSCompiler" - private val INTERNAL_ERROR = ExitCode.INTERNAL_ERROR.toString() - - fun runK2JvmCompiler( - commonArguments: CommonCompilerArguments, - k2jvmArguments: K2JVMCompilerArguments, - compilerSettings: CompilerSettings, - messageCollector: MessageCollector, - environment: CompilerEnvironment, - moduleFile: File, - collector: OutputItemsCollector) { - val arguments = mergeBeans(commonArguments, k2jvmArguments) - setupK2JvmArguments(moduleFile, arguments) - - runCompiler(K2JVM_COMPILER, arguments, compilerSettings.additionalArguments, messageCollector, collector, environment) - } - - fun runK2JsCompiler( - commonArguments: CommonCompilerArguments, - k2jsArguments: K2JSCompilerArguments, - compilerSettings: CompilerSettings, - messageCollector: MessageCollector, - environment: CompilerEnvironment, - collector: OutputItemsCollector, - sourceFiles: Collection, - libraryFiles: List, - outputFile: File) { - val arguments = mergeBeans(commonArguments, k2jsArguments) - setupK2JsArguments(outputFile, sourceFiles, libraryFiles, arguments) - - runCompiler(K2JS_COMPILER, arguments, compilerSettings.additionalArguments, messageCollector, collector, environment) - } - - private fun processCompilerOutput( - messageCollector: MessageCollector, - collector: OutputItemsCollector, - stream: ByteArrayOutputStream, - exitCode: String) { - val reader = BufferedReader(StringReader(stream.toString())) - CompilerOutputParser.parseCompilerMessagesFromReader(messageCollector, reader, collector) - - if (INTERNAL_ERROR == exitCode) { - reportInternalCompilerError(messageCollector) - } - } - - private fun reportInternalCompilerError(messageCollector: MessageCollector) { - messageCollector.report(ERROR, "Compiler terminated with internal error", CompilerMessageLocation.NO_LOCATION) - } - - private fun runCompiler( - compilerClassName: String, - arguments: CommonCompilerArguments, - additionalArguments: String, - messageCollector: MessageCollector, - collector: OutputItemsCollector, - environment: CompilerEnvironment) { - try { - messageCollector.report(INFO, "Using kotlin-home = " + environment.kotlinPaths.homePath, CompilerMessageLocation.NO_LOCATION) - - val argumentsList = ArgumentUtils.convertArgumentsToStringList(arguments) - argumentsList.addAll(additionalArguments.split(" ")) - - val argsArray = argumentsList.toTypedArray() - - if (!tryCompileWithDaemon(compilerClassName, argsArray, environment, messageCollector, collector)) { - // otherwise fallback to in-process - KotlinBuilder.LOG.info("Compile in-process") - - val stream = ByteArrayOutputStream() - val out = PrintStream(stream) - - // the property should be set at least for parallel builds to avoid parallel building problems (racing between destroying and using environment) - // unfortunately it cannot be currently set by default globally, because it breaks many tests - // since there is no reliable way so far to detect running under tests, switching it on only for parallel builds - if (System.getProperty(GlobalOptions.COMPILE_PARALLEL_OPTION, "false").toBoolean()) - System.setProperty(KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY, "true") - - val rc = CompilerRunnerUtil.invokeExecMethod(compilerClassName, argsArray, environment, messageCollector, out) - - // exec() returns an ExitCode object, class of which is loaded with a different class loader, - // so we take it's contents through reflection - processCompilerOutput(messageCollector, collector, stream, getReturnCodeFromObject(rc)) - } - } - catch (e: Throwable) { - MessageCollectorUtil.reportException(messageCollector, e) - reportInternalCompilerError(messageCollector) - } - - } - - internal class DaemonConnection(val daemon: CompileService?, val sessionId: Int = CompileService.NO_SESSION) - - internal object getDaemonConnection { - private @Volatile var connection: DaemonConnection? = null - - @Synchronized operator fun invoke(environment: CompilerEnvironment, messageCollector: MessageCollector): DaemonConnection { - if (connection == null) { - val libPath = CompilerRunnerUtil.getLibPath(environment.kotlinPaths, messageCollector) - val compilerId = CompilerId.makeCompilerId(File(libPath, "kotlin-compiler.jar")) - val daemonOptions = configureDaemonOptions() - val daemonJVMOptions = configureDaemonJVMOptions(inheritMemoryLimits = true, inheritAdditionalProperties = true) - - val daemonReportMessages = ArrayList() - - val profiler = if (daemonOptions.reportPerf) WallAndThreadAndMemoryTotalProfiler(withGC = false) else DummyProfiler() - - profiler.withMeasure(null) { - val daemon = KotlinCompilerClient.connectToCompileService(compilerId, daemonJVMOptions, daemonOptions, DaemonReportingTargets(null, daemonReportMessages), true, true) - connection = DaemonConnection(daemon, daemon?.leaseCompileSession(makeAutodeletingFlagFile("compiler-jps-session").absolutePath)?.get() ?: CompileService.NO_SESSION) - } - - for (msg in daemonReportMessages) { - messageCollector.report(CompilerMessageSeverity.INFO, - (if (msg.category == DaemonReportCategory.EXCEPTION && connection?.daemon == null) "Falling back to compilation without daemon due to error: " else "") + msg.message, - CompilerMessageLocation.NO_LOCATION) - } - - reportTotalAndThreadPerf("Daemon connect", daemonOptions, messageCollector, profiler) - } - return connection!! - } - } - - private fun tryCompileWithDaemon(compilerClassName: String, - argsArray: Array, - environment: CompilerEnvironment, - messageCollector: MessageCollector, - collector: OutputItemsCollector, - retryOnConnectionError: Boolean = true): Boolean { - - if (isDaemonEnabled()) { - - KotlinBuilder.LOG.debug("Try to connect to daemon") - val connection = getDaemonConnection(environment, messageCollector) - - if (connection.daemon != null) { - KotlinBuilder.LOG.info("Connected to daemon") - - val compilerOut = ByteArrayOutputStream() - val daemonOut = ByteArrayOutputStream() - - val services = CompilationServices( - incrementalCompilationComponents = environment.services.get(IncrementalCompilationComponents::class.java), - compilationCanceledStatus = environment.services.get(CompilationCanceledStatus::class.java)) - - val targetPlatform = when (compilerClassName) { - K2JVM_COMPILER -> CompileService.TargetPlatform.JVM - K2JS_COMPILER -> CompileService.TargetPlatform.JS - else -> throw IllegalArgumentException("Unknown compiler type $compilerClassName") - } - - fun retryOrFalse(e: Exception): Boolean { - if (retryOnConnectionError) { - KotlinBuilder.LOG.debug("retrying once on daemon connection error: ${e.message}") - return tryCompileWithDaemon(compilerClassName, argsArray, environment, messageCollector, collector, retryOnConnectionError = false) - } - KotlinBuilder.LOG.info("daemon connection error: ${e.message}") - return false - } - - val res: Int = try { - KotlinCompilerClient.incrementalCompile(connection.daemon, connection.sessionId, targetPlatform, argsArray, services, compilerOut, daemonOut) - } - catch (e: java.rmi.ConnectException) { - return retryOrFalse(e) - } - catch (e: java.rmi.UnmarshalException) { - return retryOrFalse(e) - } - - processCompilerOutput(messageCollector, collector, compilerOut, res.toString()) - BufferedReader(StringReader(daemonOut.toString())).forEachLine { - messageCollector.report(CompilerMessageSeverity.INFO, it, CompilerMessageLocation.NO_LOCATION) - } - return true - } - - KotlinBuilder.LOG.info("Daemon not found") - } - return false - } - - private fun reportTotalAndThreadPerf(message: String, daemonOptions: DaemonOptions, messageCollector: MessageCollector, profiler: Profiler) { - if (daemonOptions.reportPerf) { - fun Long.ms() = TimeUnit.NANOSECONDS.toMillis(this) - val counters = profiler.getTotalCounters() - messageCollector.report(INFO, - "PERF: $message ${counters.time.ms()} ms, thread ${counters.threadTime.ms()}", - CompilerMessageLocation.NO_LOCATION) - } - } - - private fun getReturnCodeFromObject(rc: Any?): String { - when { - rc == null -> return INTERNAL_ERROR - ExitCode::class.java.name == rc.javaClass.name -> return rc.toString() - else -> throw IllegalStateException("Unexpected return: " + rc) - } - } - - private fun setupK2JvmArguments(moduleFile: File, settings: K2JVMCompilerArguments) { - with(settings) { - module = moduleFile.absolutePath - noStdlib = true - noReflect = true - noJdk = true - } - } - - private fun setupK2JsArguments( _outputFile: File, sourceFiles: Collection, _libraryFiles: List, settings: K2JSCompilerArguments) { - with(settings) { - noStdlib = true - freeArgs = sourceFiles.map { it.path } - outputFile = _outputFile.path - metaInfo = true - libraryFiles = _libraryFiles.toTypedArray() - } - } -}