Run compiler via Kotlin daemon in Gradle plugin
This commit is contained in:
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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.gradle.api.Project
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.gradle.plugin.ParentLastURLClassLoader
|
||||
import org.jetbrains.kotlin.gradle.plugin.kotlinInfo
|
||||
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.net.URL
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
|
||||
const val KOTLIN_COMPILER_JAR_PATH_PROPERTY = "kotlin.compiler.jar.path"
|
||||
|
||||
internal class GradleCompilerRunner(private val project: Project) : KotlinCompilerRunner<GradleCompilerEnvironment>() {
|
||||
override val log = GradleKotlinLogger(project.logger)
|
||||
private val flagFile = run {
|
||||
val dir = File(project.rootProject.buildDir, "kotlin").apply { mkdirs() }
|
||||
File(dir, "daemon-is-alive").apply {
|
||||
if (!exists()) {
|
||||
createNewFile()
|
||||
deleteOnExit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun runJvmCompiler(
|
||||
sourcesToCompile: List<File>,
|
||||
javaSourceRoots: Iterable<File>,
|
||||
args: K2JVMCompilerArguments,
|
||||
messageCollector: MessageCollector,
|
||||
outputItemsCollector: OutputItemsCollector
|
||||
): ExitCode {
|
||||
val outputDir = args.destinationAsFile
|
||||
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,
|
||||
isTest = false,
|
||||
outputDir = outputDir,
|
||||
sourcesToCompile = sourcesToCompile,
|
||||
javaSourceRoots = javaSourceRoots,
|
||||
classpath = args.classpathAsList,
|
||||
friendDirs = args.friendPaths?.map(::File) ?: emptyList())
|
||||
args.module = moduleFile.absolutePath
|
||||
|
||||
val additionalArguments = ""
|
||||
|
||||
try {
|
||||
return runCompiler(K2JVM_COMPILER, args, additionalArguments, messageCollector, outputItemsCollector, GradleCompilerEnvironment(project, K2JVM_COMPILER))
|
||||
}
|
||||
finally {
|
||||
moduleFile.delete()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun getDaemonConnection(environment: GradleCompilerEnvironment, messageCollector: MessageCollector): DaemonConnection {
|
||||
return newDaemonConnection(environment.compilerJar, messageCollector, flagFile)
|
||||
}
|
||||
}
|
||||
|
||||
internal class GradleCompilerEnvironment(
|
||||
private val project: Project,
|
||||
private val compilerClassName: String
|
||||
) : CompilerEnvironment(Services.EMPTY) {
|
||||
val compilerJar: File by lazy {
|
||||
val file = findKotlinCompilerJar(project, compilerClassName)
|
||||
?: throw IllegalStateException("Could not found Kotlin compiler jar. " +
|
||||
"As a workaround you may specify path to compiler jar using " +
|
||||
"\"$KOTLIN_COMPILER_JAR_PATH_PROPERTY\" system property")
|
||||
|
||||
project.logger.kotlinInfo("Using kotlin compiler jar: $file")
|
||||
file
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun findKotlinCompilerJar(project: Project, compilerClassName: String): File? {
|
||||
fun Project.classpathJars(): Sequence<File> =
|
||||
buildscript.configurations.findByName("classpath")?.files?.asSequence() ?: emptySequence()
|
||||
|
||||
val pathFromSysProperties = System.getProperty(KOTLIN_COMPILER_JAR_PATH_PROPERTY)
|
||||
if (pathFromSysProperties != null) {
|
||||
val fileFromSysProperties = File(pathFromSysProperties)
|
||||
|
||||
if (fileFromSysProperties.exists()) return fileFromSysProperties
|
||||
}
|
||||
|
||||
val projectsToRoot = generateSequence(project) { if (it != it.rootProject) it.parent else null }
|
||||
val classpathDeps = projectsToRoot.flatMap { it.classpathJars() }
|
||||
val entryToFind = compilerClassName.replace(".", "/") + ".class"
|
||||
val jarCandidate = classpathDeps.firstOrNull { it.hasEntry(entryToFind) }
|
||||
|
||||
System.setProperty(KOTLIN_COMPILER_JAR_PATH_PROPERTY, jarCandidate?.absolutePath)
|
||||
return jarCandidate
|
||||
}
|
||||
|
||||
private fun File.hasEntry(entryToFind: String): Boolean {
|
||||
try {
|
||||
val zip = ZipFile(this)
|
||||
val enumeration = zip.entries()
|
||||
|
||||
while (enumeration.hasMoreElements()) {
|
||||
val entry = enumeration.nextElement()
|
||||
if (entry.name.equals(entryToFind, ignoreCase = true)) return true
|
||||
}
|
||||
}
|
||||
catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.gradle.api.logging.Logger
|
||||
|
||||
internal class GradleKotlinLogger(private val log: Logger) : KotlinLogger {
|
||||
override fun debug(msg: String) {
|
||||
log.debug(msg)
|
||||
}
|
||||
|
||||
override fun error(msg: String) {
|
||||
log.error(msg)
|
||||
}
|
||||
|
||||
override fun info(msg: String) {
|
||||
log.info(msg)
|
||||
}
|
||||
|
||||
override fun warn(msg: String) {
|
||||
log.warn(msg)
|
||||
}
|
||||
}
|
||||
+4
@@ -68,6 +68,10 @@ internal fun Logger.kotlinDebug(message: String) {
|
||||
this.debug("[KOTLIN] $message")
|
||||
}
|
||||
|
||||
internal fun Logger.kotlinWarn(message: String) {
|
||||
this.warn("[KOTLIN] $message")
|
||||
}
|
||||
|
||||
internal inline fun Logger.kotlinDebug(message: () -> String) {
|
||||
if (isDebugEnabled) {
|
||||
kotlinDebug(message())
|
||||
|
||||
+8
-8
@@ -38,6 +38,8 @@ 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.GradleCompilerRunner
|
||||
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.gradle.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.CoroutineSupport
|
||||
@@ -192,20 +194,20 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
||||
override fun callCompiler(args: K2JVMCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
|
||||
sourceRoots as SourceRoots.ForJvm
|
||||
|
||||
val outputDir = destinationDir
|
||||
val messageCollector = GradleMessageCollector(logger)
|
||||
args.classpathAsList = compileClasspath.toList()
|
||||
args.destinationAsFile = destinationDir
|
||||
val outputItemCollector = OutputItemsCollectorImpl()
|
||||
|
||||
if (!incremental) {
|
||||
anyClassesCompiled = true
|
||||
processCompilerExitCode(compileJvmNotIncrementally(
|
||||
compiler, logger,
|
||||
sourceRoots.kotlinSourceFiles, sourceRoots.javaSourceRoots,
|
||||
compileClasspath, outputDir, args))
|
||||
val exitCode = GradleCompilerRunner(project).runJvmCompiler(sourceRoots.kotlinSourceFiles, sourceRoots.javaSourceRoots, args, messageCollector, outputItemCollector)
|
||||
processCompilerExitCode(exitCode)
|
||||
return
|
||||
}
|
||||
|
||||
logger.warn(USING_EXPERIMENTAL_INCREMENTAL_MESSAGE)
|
||||
val reporter = GradleIncReporter(project.rootProject.projectDir)
|
||||
val messageCollector = GradleMessageCollector(logger)
|
||||
val compiler = IncrementalJvmCompilerRunner(
|
||||
taskBuildDirectory,
|
||||
sourceRoots.javaSourceRoots,
|
||||
@@ -216,8 +218,6 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
||||
artifactDifferenceRegistryProvider,
|
||||
artifactFile
|
||||
)
|
||||
args.classpathAsList = classpath.toList()
|
||||
args.destinationAsFile = destinationDir
|
||||
try {
|
||||
val exitCode = compiler.compile(sourceRoots.kotlinSourceFiles, args, messageCollector, { changedFiles })
|
||||
processCompilerExitCode(exitCode)
|
||||
|
||||
Reference in New Issue
Block a user