Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.gradle.internal.kapt.KaptWithoutKotlincTask.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.internal
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.gradle.workers.IsolationMode
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges
import org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPluginWrapper
import org.jetbrains.kotlin.gradle.tasks.findKotlinStdlibClasspath
import org.jetbrains.kotlin.gradle.tasks.findToolsJar
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.io.Serializable
import java.net.URL
import java.net.URLClassLoader
import javax.inject.Inject
open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor: WorkerExecutor) : KaptTask() {
@get:InputFiles
@get:Classpath
@Suppress("unused")
val kaptJars: Collection
get() = project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).resolve()
@get:Input
var isVerbose: Boolean = false
@get:Input
var mapDiagnosticLocations: Boolean = false
@get:Input
lateinit var annotationProcessorFqNames: List
@get:Input
lateinit var processorOptions: Map
@get:Input
lateinit var javacOptions: Map
@TaskAction
fun compile(inputs: IncrementalTaskInputs) {
logger.info("Running kapt annotation processing using the Gradle Worker API")
checkAnnotationProcessorClasspath()
val incrementalChanges = getIncrementalChanges(inputs)
val (changedFiles, classpathChanges) = when (incrementalChanges) {
is KaptIncrementalChanges.Unknown -> Pair(emptyList(), emptyList())
is KaptIncrementalChanges.Known -> Pair(incrementalChanges.changedSources.toList(), incrementalChanges.changedClasspathJvmNames)
}
val compileClasspath = classpath.files.toMutableList()
if (project.plugins.none { it is KotlinAndroidPluginWrapper }) {
compileClasspath.addAll(0, PathUtil.getJdkClassesRootsFromCurrentJre())
}
val kaptFlagsForWorker = mutableSetOf().apply {
if (isVerbose) add("VERBOSE")
if (mapDiagnosticLocations) add("MAP_DIAGNOSTIC_LOCATIONS")
if (includeCompileClasspath) add("INCLUDE_COMPILE_CLASSPATH")
if (incrementalChanges is KaptIncrementalChanges.Known) add("INCREMENTAL_APT")
}
val optionsForWorker = KaptOptionsForWorker(
project.projectDir,
compileClasspath,
javaSourceRoots.toList(),
changedFiles,
getCompiledSources(),
incAptCache,
classpathChanges.toList(),
destinationDir,
classesDir,
stubsDir,
kaptClasspath.files.toList(),
annotationProcessorFqNames,
processorOptions,
javacOptions,
kaptFlagsForWorker
)
// Skip annotation processing if no annotation processors were provided.
if (annotationProcessorFqNames.isEmpty() && kaptClasspath.isEmpty())
return
val kaptClasspath = kaptJars + findKotlinStdlibClasspath(project)
workerExecutor.submit(KaptExecution::class.java) { config ->
val isolationModeStr = project.findProperty("kapt.workers.isolation") as String? ?: "none"
config.isolationMode = when (isolationModeStr.toLowerCase()) {
"process" -> IsolationMode.PROCESS
"none" -> IsolationMode.NONE
else -> IsolationMode.NONE
}
config.params(optionsForWorker, findToolsJar()?.toURI()?.toURL()?.toString().orEmpty(), kaptClasspath)
if (project.findProperty("kapt.workers.log.classloading") == "true") {
// for tests
config.forkOptions.jvmArgs("-verbose:class")
}
logger.info("Kapt worker classpath: ${config.classpath}")
}
}
}
private class KaptExecution @Inject constructor(
val optionsForWorker: KaptOptionsForWorker,
val toolsJarURLSpec: String,
val kaptClasspath: List
) : Runnable {
private companion object {
private const val JAVAC_CONTEXT_CLASS = "com.sun.tools.javac.util.Context"
private fun kaptClass(classLoader: ClassLoader) = Class.forName("org.jetbrains.kotlin.kapt3.base.Kapt", true, classLoader)
private var cachedClassLoaderWithToolsJar: ClassLoader? = null
private var cachedKaptClassLoader: ClassLoader? = null
}
override fun run(): Unit = with(optionsForWorker) {
val kaptClasspathUrls = kaptClasspath.map { it.toURI().toURL() }.toTypedArray()
val rootClassLoader = findRootClassLoader()
val classLoaderWithToolsJar = cachedClassLoaderWithToolsJar ?: if (!toolsJarURLSpec.isEmpty() && !javacIsAlreadyHere()) {
URLClassLoader(arrayOf(URL(toolsJarURLSpec)), rootClassLoader)
} else {
rootClassLoader
}
cachedClassLoaderWithToolsJar = classLoaderWithToolsJar
val kaptClassLoader = cachedKaptClassLoader ?: URLClassLoader(kaptClasspathUrls, classLoaderWithToolsJar)
cachedKaptClassLoader = kaptClassLoader
val kaptMethod = kaptClass(kaptClassLoader).declaredMethods.single { it.name == "kapt" }
kaptMethod.invoke(null, createKaptOptions(kaptClassLoader))
}
private fun javacIsAlreadyHere(): Boolean {
return try {
Class.forName(JAVAC_CONTEXT_CLASS, false, KaptExecution::class.java.classLoader) != null
} catch (e: Throwable) {
false
}
}
private fun createKaptOptions(classLoader: ClassLoader) = with(optionsForWorker) {
val flags = kaptClass(classLoader).declaredMethods.single { it.name == "kaptFlags" }.invoke(null, flags)
val mode = Class.forName("org.jetbrains.kotlin.base.kapt3.AptMode", true, classLoader)
.enumConstants.single { (it as Enum<*>).name == "APT_ONLY" }
val detectMemoryLeaksMode = Class.forName("org.jetbrains.kotlin.base.kapt3.DetectMemoryLeaksMode", true, classLoader)
.enumConstants.single { (it as Enum<*>).name == "NONE" }
Class.forName("org.jetbrains.kotlin.base.kapt3.KaptOptions", true, classLoader).constructors.single().newInstance(
projectBaseDir,
compileClasspath,
javaSourceRoots,
changedFiles,
compiledSources,
incAptCache,
classpathChanges,
sourcesOutputDir,
classesOutputDir,
stubsOutputDir,
stubsOutputDir, // sic!
processingClasspath,
processors,
processingOptions,
javacOptions,
flags,
mode,
detectMemoryLeaksMode
)
}
private fun findRootClassLoader(): ClassLoader {
tailrec fun parentOrSelf(classLoader: ClassLoader): ClassLoader {
val parent = classLoader.parent ?: return classLoader
return parentOrSelf(parent)
}
return parentOrSelf(KaptExecution::class.java.classLoader)
}
}
private data class KaptOptionsForWorker(
val projectBaseDir: File,
val compileClasspath: List,
val javaSourceRoots: List,
val changedFiles: List,
val compiledSources: List,
val incAptCache: File?,
val classpathChanges: List,
val sourcesOutputDir: File,
val classesOutputDir: File,
val stubsOutputDir: File,
val processingClasspath: List,
val processors: List,
val processingOptions: Map,
val javacOptions: Map,
val flags: Set
) : Serializable