From 51a8f6ee4f2c4b1f909f01acad9b9614f3bdaa2a Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Tue, 6 Dec 2016 16:30:17 +0300 Subject: [PATCH] Implement server side IC --- .../compilerRunner/KotlinCompilerRunner.kt | 16 ++-- .../kotlin/daemon/common/CompileService.kt | 10 +++ .../IncrementalCompilationServicesFacade.kt | 56 ++++++++++++++ compiler/daemon/daemon.iml | 3 + .../kotlin/daemon/CompileServiceImpl.kt | 63 ++++++++++++++++ .../daemon/RemoteAnnotationsFileUpdater.kt | 34 +++++++++ .../kotlin/daemon/RemoteICReporter.kt | 36 +++++++++ .../IncrementalJvmCompilerRunner.kt | 8 +- ...daloneCacheVersion.kt => cacheVersions.kt} | 9 ++- .../GradleCompilerEnvironment.kt | 17 ++++- .../GradleKotlinCompilerRunner.kt | 53 +++++++++++-- .../IncrementalCompilationFacadeImpl.kt | 74 +++++++++++++++++++ .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 36 +++------ .../kotlin/incremental/GradleICReporter.kt | 11 +++ 14 files changed, 375 insertions(+), 51 deletions(-) create mode 100644 compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/IncrementalCompilationServicesFacade.kt create mode 100644 compiler/daemon/src/org/jetbrains/kotlin/daemon/RemoteAnnotationsFileUpdater.kt create mode 100644 compiler/daemon/src/org/jetbrains/kotlin/daemon/RemoteICReporter.kt rename compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/{standaloneCacheVersion.kt => cacheVersions.kt} (79%) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/IncrementalCompilationFacadeImpl.kt diff --git a/compiler/compiler-runner/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt b/compiler/compiler-runner/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt index 985145d2777..3e425f7ecb8 100644 --- a/compiler/compiler-runner/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt +++ b/compiler/compiler-runner/src/org/jetbrains/kotlin/compilerRunner/KotlinCompilerRunner.kt @@ -93,7 +93,7 @@ abstract class KotlinCompilerRunner { protected fun processCompilerOutput( environment: Env, stream: ByteArrayOutputStream, - exitCode: ExitCode + exitCode: ExitCode? ) { val reader = BufferedReader(StringReader(stream.toString())) CompilerOutputParser.parseCompilerMessagesFromReader(environment.messageCollector, reader, environment.outputItemsCollector) @@ -194,12 +194,12 @@ abstract class KotlinCompilerRunner { return null } - protected fun exitCodeFromProcessExitCode(res: Int): ExitCode = - if (res == 0) { - ExitCode.OK - } - else { - ExitCode.COMPILATION_ERROR - } + protected fun exitCodeFromProcessExitCode(code: Int): ExitCode { + val exitCode = ExitCode.values().find { it.code == code } + if (exitCode != null) return exitCode + + log.debug("Could not find exit code by value: $code") + return if (code == 0) ExitCode.OK else ExitCode.COMPILATION_ERROR + } } diff --git a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompileService.kt b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompileService.kt index 810bd5b8bf9..bc0b5c7aa0c 100644 --- a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompileService.kt +++ b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/CompileService.kt @@ -125,6 +125,16 @@ interface CompileService : Remote { operationsTracer: RemoteOperationsTracer? ): CallResult + @Throws(RemoteException::class) + fun serverSideJvmIC( + sessionId: Int, + args: Array, + servicesFacade: IncrementalCompilationServicesFacade, + compilerOutputStream: RemoteOutputStream, + serviceOutputStream: RemoteOutputStream, + operationsTracer: RemoteOperationsTracer? + ): CallResult + @Throws(RemoteException::class) fun leaseReplSession( aliveFlagPath: String?, diff --git a/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/IncrementalCompilationServicesFacade.kt b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/IncrementalCompilationServicesFacade.kt new file mode 100644 index 00000000000..2378a75beed --- /dev/null +++ b/compiler/daemon/daemon-common/src/org/jetbrains/kotlin/daemon/common/IncrementalCompilationServicesFacade.kt @@ -0,0 +1,56 @@ +/* + * Copyright 2010-2016 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.daemon.common + +import java.io.File +import java.rmi.Remote +import java.rmi.RemoteException + +interface IncrementalCompilationServicesFacade : Remote { + @Throws(RemoteException::class) + fun areFileChangesKnown(): Boolean + + @Throws(RemoteException::class) + fun modifiedFiles(): List? + + @Throws(RemoteException::class) + fun deletedFiles(): List? + + @Throws(RemoteException::class) + fun workingDir(): File + + // ICReporter + + @Throws(RemoteException::class) + fun shouldReportIC(): Boolean + + @Throws(RemoteException::class) + fun reportIC(message: String) + + @Throws(RemoteException::class) + fun reportCompileIteration(files: Iterable, exitCode: Int) + + // AnnotationFileUpdater + @Throws(RemoteException::class) + fun hasAnnotationsFileUpdater(): Boolean + + @Throws(RemoteException::class) + fun updateAnnotations(outdatedClassesJvmNames: Iterable) + + @Throws(RemoteException::class) + fun revert() +} diff --git a/compiler/daemon/daemon.iml b/compiler/daemon/daemon.iml index f66fb35d0c9..8d3fad96acf 100644 --- a/compiler/daemon/daemon.iml +++ b/compiler/daemon/daemon.iml @@ -12,5 +12,8 @@ + + + \ No newline at end of file diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt index b50040e11f9..d890129599d 100644 --- a/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt +++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/CompileServiceImpl.kt @@ -20,20 +20,31 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.impl.ZipHandler import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem +import org.jetbrains.kotlin.annotation.AnnotationFileUpdater import org.jetbrains.kotlin.cli.common.CLICompiler 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.K2JVMCompilerArguments +import org.jetbrains.kotlin.cli.common.messages.* +import org.jetbrains.kotlin.cli.common.modules.ModuleXmlParser import org.jetbrains.kotlin.cli.common.repl.ReplCheckResult import org.jetbrains.kotlin.cli.common.repl.ReplCodeLine import org.jetbrains.kotlin.cli.common.repl.ReplCompileResult import org.jetbrains.kotlin.cli.common.repl.ReplEvalResult +import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.config.IncrementalCompilation import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.daemon.common.* +import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents +import org.jetbrains.kotlin.modules.Module +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.progress.CompilationCanceledStatus +import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.utils.addToStdlib.check import java.io.BufferedOutputStream +import java.io.ByteArrayOutputStream import java.io.File import java.io.PrintStream import java.rmi.NoSuchObjectException @@ -306,6 +317,58 @@ class CompileServiceImpl( } } + override fun serverSideJvmIC( + sessionId: Int, + args: Array, + servicesFacade: IncrementalCompilationServicesFacade, + compilerOutputStream: RemoteOutputStream, + serviceOutputStream: RemoteOutputStream, + operationsTracer: RemoteOperationsTracer? + ): CompileService.CallResult { + return doCompile(sessionId, args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, eventManager, profiler -> + val reporter = RemoteICReporter(servicesFacade) + val annotationFileUpdater = if (servicesFacade.hasAnnotationsFileUpdater()) RemoteAnnotationsFileUpdater(servicesFacade) else null + + // these flags do not have any effect on the compiler (only on caches, incremental compilation logic, jps plugin) + // so it's OK to just set them true + IncrementalCompilation.setIsEnabled(true) + IncrementalCompilation.setIsExperimental(true) + + val k2jvmArgs = K2JVMCompilerArguments() + (compiler[CompileService.TargetPlatform.JVM] as K2JVMCompiler).parseArguments(args, k2jvmArgs) + + val moduleFile = k2jvmArgs.module?.let(::File) + assert(moduleFile?.exists() ?: false) { "Module does not exist ${k2jvmArgs.module}" } + val renderer = MessageRenderer.XML + val messageCollector = PrintingMessageCollector(printStream, renderer, k2jvmArgs.verbose) + val filteringMessageCollector = FilteringMessageCollector(messageCollector) { it == CompilerMessageSeverity.ERROR } + + val parsedModule = ModuleXmlParser.parseModuleScript(k2jvmArgs.module, filteringMessageCollector) + val javaSourceRoots = parsedModule.modules.flatMapTo(HashSet()) { it.getJavaSourceRoots().map { File(it.path) } } + val allKotlinFiles = parsedModule.modules.flatMap { it.getSourceFiles().map(::File) } + k2jvmArgs.friendPaths = parsedModule.modules.flatMap(Module::getFriendPaths).toTypedArray() + + val changedFiles = if (servicesFacade.areFileChangesKnown()) { + ChangedFiles.Known(servicesFacade.modifiedFiles()!!, servicesFacade.deletedFiles()!!) + } + else { + ChangedFiles.Unknown() + } + + val workingDir = servicesFacade.workingDir() + val versions = commonCacheVersions(workingDir) + standaloneCacheVersion(workingDir, forceEnable = true) + + try { + printStream.print(renderer.renderPreamble()) + IncrementalJvmCompilerRunner(workingDir, javaSourceRoots, versions, reporter, annotationFileUpdater) + .compile(allKotlinFiles, k2jvmArgs, messageCollector, { changedFiles }) + } + finally { + printStream.print(renderer.renderConclusion()) + } + } + } + override fun leaseReplSession( aliveFlagPath: String?, targetPlatform: CompileService.TargetPlatform, diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/RemoteAnnotationsFileUpdater.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/RemoteAnnotationsFileUpdater.kt new file mode 100644 index 00000000000..41c74cd8574 --- /dev/null +++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/RemoteAnnotationsFileUpdater.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2010-2016 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.daemon + +import org.jetbrains.kotlin.annotation.AnnotationFileUpdater +import org.jetbrains.kotlin.cli.common.ExitCode +import org.jetbrains.kotlin.daemon.common.IncrementalCompilationServicesFacade +import org.jetbrains.kotlin.incremental.ICReporter +import org.jetbrains.kotlin.resolve.jvm.JvmClassName +import java.io.File + +internal class RemoteAnnotationsFileUpdater(private val servicesFacade: IncrementalCompilationServicesFacade) : AnnotationFileUpdater { + override fun updateAnnotations(outdatedClasses: Iterable) { + servicesFacade.updateAnnotations(outdatedClasses.map { it.internalName }) + } + + override fun revert() { + servicesFacade.revert() + } +} \ No newline at end of file diff --git a/compiler/daemon/src/org/jetbrains/kotlin/daemon/RemoteICReporter.kt b/compiler/daemon/src/org/jetbrains/kotlin/daemon/RemoteICReporter.kt new file mode 100644 index 00000000000..91b3eac57b0 --- /dev/null +++ b/compiler/daemon/src/org/jetbrains/kotlin/daemon/RemoteICReporter.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2016 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.daemon + +import org.jetbrains.kotlin.cli.common.ExitCode +import org.jetbrains.kotlin.daemon.common.IncrementalCompilationServicesFacade +import org.jetbrains.kotlin.incremental.ICReporter +import java.io.File + +internal class RemoteICReporter(private val servicesFacade: IncrementalCompilationServicesFacade) : ICReporter() { + override fun report(message: () -> String) { + if (servicesFacade.shouldReportIC()) { + servicesFacade.reportIC(message()) + } + } + + override fun reportCompileIteration(sourceFiles: Iterable, exitCode: ExitCode) { + if (servicesFacade.shouldReportIC()) { + servicesFacade.reportCompileIteration(sourceFiles, exitCode.code) + } + } +} \ No newline at end of file diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt index 37b8b128a8a..72ae18e8d36 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/IncrementalJvmCompilerRunner.kt @@ -49,10 +49,7 @@ fun makeIncrementally( messageCollector: MessageCollector = MessageCollector.NONE, reporter: ICReporter = EmptyICReporter ) { - val versions = listOf(normalCacheVersion(cachesDir), - experimentalCacheVersion(cachesDir), - dataContainerCacheVersion(cachesDir), - standaloneCacheVersion(cachesDir)) + val versions = commonCacheVersions(cachesDir) + standaloneCacheVersion(cachesDir) val kotlinExtensions = listOf("kt", "kts") val allExtensions = kotlinExtensions + listOf("java") @@ -313,9 +310,6 @@ class IncrementalJvmCompilerRunner( caches.incrementalCache.removeClassfilesBySources(dirtySources) val (sourcesToCompile, removedKotlinSources) = dirtySources.partition(File::exists) - if (sourcesToCompile.isNotEmpty()) { - reporter.report { "compile iteration: ${reporter.pathsAsString(sourcesToCompile)}" } - } // todo: more optimal to save only last iteration, but it will require adding standalone-ic specific logs // (because jps rebuilds all files from last build if it failed and gradle rebuilds everything) diff --git a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/standaloneCacheVersion.kt b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/cacheVersions.kt similarity index 79% rename from compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/standaloneCacheVersion.kt rename to compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/cacheVersions.kt index 60297754e7c..ab65f155ad9 100644 --- a/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/standaloneCacheVersion.kt +++ b/compiler/incremental-compilation-impl/src/org/jetbrains/kotlin/incremental/cacheVersions.kt @@ -22,10 +22,15 @@ import java.io.File internal const val STANDALONE_CACHE_VERSION = 0 internal const val STANDALONE_VERSION_FILE_NAME = "standalone-ic-format-version.txt" -internal fun standaloneCacheVersion(dataRoot: File): CacheVersion = +fun standaloneCacheVersion(dataRoot: File, forceEnable: Boolean = false): CacheVersion = CacheVersion(ownVersion = STANDALONE_CACHE_VERSION, versionFile = File(dataRoot, STANDALONE_VERSION_FILE_NAME), whenVersionChanged = CacheVersion.Action.REBUILD_ALL_KOTLIN, whenTurnedOn = CacheVersion.Action.REBUILD_ALL_KOTLIN, whenTurnedOff = CacheVersion.Action.REBUILD_ALL_KOTLIN, - isEnabled = { IncrementalCompilation.isExperimental() }) + isEnabled = { IncrementalCompilation.isExperimental() || forceEnable }) + +fun commonCacheVersions(cachesDir: File): List = + listOf(normalCacheVersion(cachesDir), + experimentalCacheVersion(cachesDir), + dataContainerCacheVersion(cachesDir)) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt index 7fcf9a1d396..c6ce4e48bbf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt @@ -1,11 +1,14 @@ package org.jetbrains.kotlin.compilerRunner +import org.jetbrains.kotlin.annotation.AnnotationFileUpdater import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.config.Services +import org.jetbrains.kotlin.incremental.ChangedFiles +import org.jetbrains.kotlin.incremental.GradleICReporter import java.io.File import java.net.URL -internal class GradleCompilerEnvironment( +internal open class GradleCompilerEnvironment( val compilerJar: File, messageCollector: MessageCollector, outputItemsCollector: OutputItemsCollector @@ -15,4 +18,14 @@ internal class GradleCompilerEnvironment( val compilerClasspathURLs: List get() = compilerClasspath.map { it.toURI().toURL() } -} \ No newline at end of file +} + +internal class GradleIncrementalCompilerEnvironment( + compilerJar: File, + val changedFiles: ChangedFiles, + val reporter: GradleICReporter, + val workingDir: File, + messageCollector: MessageCollector, + outputItemsCollector: OutputItemsCollector, + val kaptAnnotationsFileUpdater: AnnotationFileUpdater? +) : GradleCompilerEnvironment(compilerJar, messageCollector, outputItemsCollector) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt index da6259381e0..75fd3f0c473 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt @@ -22,16 +22,22 @@ import org.gradle.api.Project import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +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.config.Services +import org.jetbrains.kotlin.daemon.client.RemoteOutputStreamServer +import org.jetbrains.kotlin.daemon.common.IncrementalCompilationServicesFacade +import org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface +import org.jetbrains.kotlin.daemon.common.SOCKET_ANY_FREE_PORT import org.jetbrains.kotlin.gradle.plugin.ParentLastURLClassLoader import org.jetbrains.kotlin.gradle.plugin.kotlinDebug +import org.jetbrains.kotlin.incremental.ChangedFiles import org.jetbrains.kotlin.incremental.classpathAsList import org.jetbrains.kotlin.incremental.destinationAsFile import org.jetbrains.kotlin.incremental.makeModuleFile -import java.io.ByteArrayOutputStream -import java.io.File -import java.io.PrintStream +import java.io.* +import java.rmi.server.UnicastRemoteObject import kotlin.concurrent.thread internal const val KOTLIN_COMPILER_EXECUTION_STRATEGY_PROPERTY = "kotlin.compiler.execution.strategy" @@ -58,11 +64,13 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil environment: GradleCompilerEnvironment ): ExitCode { val outputDir = args.destinationAsFile - log.debug("Removing all kotlin classes in $outputDir") log.info("Using kotlin compiler jar: ${environment.compilerJar}") - // we're free to delete all classes since only we know about that directory - outputDir.deleteRecursively() + if (environment !is GradleIncrementalCompilerEnvironment) { + log.debug("Removing all kotlin classes in $outputDir") + // we're free to delete all classes since only we know about that directory + outputDir.deleteRecursively() + } val moduleFile = makeModuleFile( args.moduleName, @@ -121,14 +129,43 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil } } - override fun compileWithDaemon(compilerClassName: String, argsArray: Array, environment: GradleCompilerEnvironment, retryOnConnectionError: Boolean): ExitCode? { - val exitCode = super.compileWithDaemon(compilerClassName, argsArray, environment, retryOnConnectionError) + override fun compileWithDaemon(compilerClassName: String, argsArray: Array, environment: GradleCompilerEnvironment): ExitCode? { + val exitCode = if (environment is GradleIncrementalCompilerEnvironment) { + performIncrementalCompilationWithDaemon(argsArray, environment) + } + else { + super.compileWithDaemon(compilerClassName, argsArray, environment) + } exitCode?.let { logFinish(DAEMON_EXECUTION_STRATEGY) } return exitCode } + private fun performIncrementalCompilationWithDaemon(argsArray: Array, environment: GradleIncrementalCompilerEnvironment): ExitCode? { + val port = SOCKET_ANY_FREE_PORT + val services = IncrementalCompilationFacadeImpl(environment, port) + val compilerOut = ByteArrayOutputStream() + val daemonOut = ByteArrayOutputStream() + + val res = withDaemon(environment) { daemon, sessionId -> + val remoteCompilerOut = RemoteOutputStreamServer(compilerOut, port) + val remoteDaemonOut = RemoteOutputStreamServer(daemonOut, port) + daemon.serverSideJvmIC(sessionId, argsArray, services, remoteCompilerOut, remoteDaemonOut, null) + } + + val exitCode = res?.get()?.let { exitCodeFromProcessExitCode(it) } + if (exitCode == null) { + log.warn("Could not perform incremental compilation with Kotlin compile daemon, " + + "non-incremental compilation in fallback mode will be performed") + } + processCompilerOutput(environment, compilerOut, exitCode) + BufferedReader(StringReader(daemonOut.toString())).forEachLine { + environment.messageCollector.report(CompilerMessageSeverity.INFO, it, CompilerMessageLocation.NO_LOCATION) + } + return exitCode + } + private fun compileOutOfProcess( argsArray: Array, compilerClassName: String, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/IncrementalCompilationFacadeImpl.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/IncrementalCompilationFacadeImpl.kt new file mode 100644 index 00000000000..a97b7b10243 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/IncrementalCompilationFacadeImpl.kt @@ -0,0 +1,74 @@ +/* + * Copyright 2010-2016 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.ExitCode +import org.jetbrains.kotlin.daemon.common.IncrementalCompilationServicesFacade +import org.jetbrains.kotlin.daemon.common.LoopbackNetworkInterface +import org.jetbrains.kotlin.daemon.common.SOCKET_ANY_FREE_PORT +import org.jetbrains.kotlin.incremental.ChangedFiles +import org.jetbrains.kotlin.resolve.jvm.JvmClassName +import java.io.File +import java.rmi.server.UnicastRemoteObject + +internal class IncrementalCompilationFacadeImpl( + private val environment: GradleIncrementalCompilerEnvironment, + port: Int = SOCKET_ANY_FREE_PORT +) : IncrementalCompilationServicesFacade, + UnicastRemoteObject(port, LoopbackNetworkInterface.clientLoopbackSocketFactory, LoopbackNetworkInterface.serverLoopbackSocketFactory) { + + override fun areFileChangesKnown(): Boolean { + return environment.changedFiles is ChangedFiles.Known + } + + override fun deletedFiles(): List { + return (environment.changedFiles as ChangedFiles.Known).removed + } + + override fun modifiedFiles(): List { + return (environment.changedFiles as ChangedFiles.Known).modified + } + + override fun reportCompileIteration(files: Iterable, exitCode: Int) { + environment.reporter.reportCompileIteration(files, ExitCode.values().first { it.code == exitCode }) + } + + override fun reportIC(message: String) { + environment.reporter.report { message } + } + + override fun shouldReportIC(): Boolean { + return environment.reporter.isDebugEnabled + } + + override fun workingDir(): File { + return environment.workingDir + } + + override fun hasAnnotationsFileUpdater(): Boolean { + return environment.kaptAnnotationsFileUpdater != null + } + + override fun revert() { + environment.kaptAnnotationsFileUpdater!!.revert() + } + + override fun updateAnnotations(outdatedClassesJvmNames: Iterable) { + val jvmNames = outdatedClassesJvmNames.map { JvmClassName.byInternalName(it) } + environment.kaptAnnotationsFileUpdater!!.updateAnnotations(jvmNames) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 87e88cd0863..885ffb12ae3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -38,10 +38,7 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.js.K2JSCompiler import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler -import org.jetbrains.kotlin.compilerRunner.ArgumentUtils -import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment -import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner -import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl +import org.jetbrains.kotlin.compilerRunner.* import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.plugin.CoroutineSupport import org.jetbrains.kotlin.gradle.plugin.kotlinDebug @@ -206,36 +203,27 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl args.classpathAsList = compileClasspath.toList() args.destinationAsFile = destinationDir val outputItemCollector = OutputItemsCollectorImpl() + val compilerRunner = GradleCompilerRunner(project) - if (!incremental) { - anyClassesCompiled = true - val compilerRunner = GradleCompilerRunner(project) - val environment = GradleCompilerEnvironment(compilerJar, messageCollector, outputItemCollector) - val exitCode = compilerRunner.runJvmCompiler(sourceRoots.kotlinSourceFiles, sourceRoots.javaSourceRoots, args, environment) - processCompilerExitCode(exitCode) - return + val environment = when { + !incremental -> GradleCompilerEnvironment(compilerJar, messageCollector, outputItemCollector) + else -> { + logger.warn(USING_EXPERIMENTAL_INCREMENTAL_MESSAGE) + val reporter = GradleICReporter(project.rootProject.projectDir) + GradleIncrementalCompilerEnvironment(compilerJar, changedFiles, reporter, taskBuildDirectory, + messageCollector, outputItemCollector, kaptAnnotationsFileUpdater) + } } - logger.warn(USING_EXPERIMENTAL_INCREMENTAL_MESSAGE) - val reporter = GradleICReporter(project.rootProject.projectDir) - val compiler = IncrementalJvmCompilerRunner( - taskBuildDirectory, - sourceRoots.javaSourceRoots, - cacheVersions, - reporter, - kaptAnnotationsFileUpdater, - artifactDifferenceRegistryProvider, - artifactFile - ) try { - val exitCode = compiler.compile(sourceRoots.kotlinSourceFiles, args, messageCollector, { changedFiles }) + val exitCode = compilerRunner.runJvmCompiler(sourceRoots.kotlinSourceFiles, sourceRoots.javaSourceRoots, args, environment) processCompilerExitCode(exitCode) } catch (e: Throwable) { cleanupOnError() throw e } - anyClassesCompiled = compiler.anyClassesCompiled + anyClassesCompiled = true } private fun cleanupOnError() { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/incremental/GradleICReporter.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/incremental/GradleICReporter.kt index 41202f3e87d..658f1fabb65 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/incremental/GradleICReporter.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/incremental/GradleICReporter.kt @@ -17,17 +17,28 @@ package org.jetbrains.kotlin.incremental import org.gradle.api.logging.Logging +import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.gradle.plugin.kotlinDebug import java.io.File internal class GradleICReporter(private val projectRootFile: File) : ICReporter() { private val log = Logging.getLogger(GradleICReporter::class.java) + val isDebugEnabled: Boolean + get() = log.isDebugEnabled + override fun report(message: ()->String) { log.kotlinDebug(message) } override fun pathsAsString(files: Iterable): String = files.pathsAsStringRelativeTo(projectRootFile) + + override fun reportCompileIteration(sourceFiles: Iterable, exitCode: ExitCode) { + if (sourceFiles.any()) { + report { "compile iteration: ${pathsAsString(sourceFiles)}" } + } + report { "compiler exit code: $exitCode" } + } }