Support for gradle subplugins in Kotlin2JS compilation

Because ServiceLoader can't check generic argument of
KotlinGradleSubplugin in runtime, we have to manually check the type in
`isApplicable`.
This commit is contained in:
Leonid Startsev
2017-08-24 17:26:01 +03:00
parent e666b87545
commit 749a574234
5 changed files with 44 additions and 24 deletions
@@ -23,10 +23,10 @@ import org.gradle.api.tasks.compile.AbstractCompile
class SubpluginOption(val key: String, val value: String) class SubpluginOption(val key: String, val value: String)
interface KotlinGradleSubplugin<in KotlinCompile : AbstractCompile> { interface KotlinGradleSubplugin<in KotlinCompile : AbstractCompile> {
fun isApplicable(project: Project, task: KotlinCompile): Boolean fun isApplicable(project: Project, task: AbstractCompile): Boolean
fun apply( fun apply(
project: Project, project: Project,
kotlinCompile: KotlinCompile, kotlinCompile: KotlinCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile,
variantData: Any?, variantData: Any?,
@@ -74,7 +74,8 @@ class AndroidExtensionsSubpluginIndicator : Plugin<Project> {
} }
class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> { class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> {
override fun isApplicable(project: Project, task: KotlinCompile): Boolean { override fun isApplicable(project: Project, task: AbstractCompile): Boolean {
if (task !is KotlinCompile) return false
try { try {
project.extensions.getByName("android") as? BaseExtension ?: return false project.extensions.getByName("android") as? BaseExtension ?: return false
} catch (e: UnknownDomainObjectException) { } catch (e: UnknownDomainObjectException) {
@@ -89,7 +90,7 @@ class AndroidSubplugin : KotlinGradleSubplugin<KotlinCompile> {
override fun apply( override fun apply(
project: Project, project: Project,
kotlinCompile: KotlinCompile, kotlinCompile: KotlinCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile,
variantData: Any?, variantData: Any?,
androidProjectHandler: Any?, androidProjectHandler: Any?,
javaSourceSet: SourceSet? javaSourceSet: SourceSet?
@@ -84,7 +84,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
private val kotlinToKaptGenerateStubsTasksMap = mutableMapOf<KotlinCompile, KaptGenerateStubsTask>() private val kotlinToKaptGenerateStubsTasksMap = mutableMapOf<KotlinCompile, KaptGenerateStubsTask>()
override fun isApplicable(project: Project, task: KotlinCompile) = Kapt3GradleSubplugin.isEnabled(project) override fun isApplicable(project: Project, task: AbstractCompile) = task is KotlinCompile && Kapt3GradleSubplugin.isEnabled(project)
fun getKaptGeneratedDir(project: Project, sourceSetName: String): File { fun getKaptGeneratedDir(project: Project, sourceSetName: String): File {
return File(project.project.buildDir, "generated/source/kapt/$sourceSetName") return File(project.project.buildDir, "generated/source/kapt/$sourceSetName")
@@ -123,7 +123,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
} }
override fun apply( override fun apply(
project: Project, project: Project,
kotlinCompile: KotlinCompile, kotlinCompile: KotlinCompile,
javaCompile: AbstractCompile, javaCompile: AbstractCompile,
variantData: Any?, variantData: Any?,
@@ -21,6 +21,7 @@ import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetOutput import org.gradle.api.tasks.SourceSetOutput
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.com.intellij.openapi.util.text.StringUtil.compareVersionNumbers import org.jetbrains.kotlin.com.intellij.openapi.util.text.StringUtil.compareVersionNumbers
import org.jetbrains.kotlin.com.intellij.util.ReflectionUtil import org.jetbrains.kotlin.com.intellij.util.ReflectionUtil
@@ -269,7 +270,11 @@ internal class Kotlin2JsSourceSetProcessor(
createCleanSourceMapTask() createCleanSourceMapTask()
// outputFile can be set later during the configuration phase, get it only after the phase: // outputFile can be set later during the configuration phase, get it only after the phase:
project.afterEvaluate { project.afterEvaluate { project ->
val subpluginEnvironment: SubpluginEnvironment = loadSubplugins(project)
val appliedPlugins = subpluginEnvironment.addSubpluginOptions(
project, kotlinTask, kotlinTask, null, null, sourceSet)
kotlinTask.kotlinOptions.outputFile = File(kotlinTask.outputFile).absolutePath kotlinTask.kotlinOptions.outputFile = File(kotlinTask.outputFile).absolutePath
val outputDir = File(kotlinTask.outputFile).parentFile val outputDir = File(kotlinTask.outputFile).parentFile
@@ -285,6 +290,10 @@ internal class Kotlin2JsSourceSetProcessor(
if (!isSeparateClassesDirSupported) { if (!isSeparateClassesDirSupported) {
sourceSet.output.setClassesDir(kotlinTask.destinationDir) sourceSet.output.setClassesDir(kotlinTask.destinationDir)
} }
appliedPlugins
.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) }
.forEach { it.source(kotlinSourceSet.kotlin) }
} }
} }
@@ -694,7 +703,7 @@ private fun removeAnnotationProcessingPluginClasspathEntry(kotlinCompile: Kotlin
private fun loadSubplugins(project: Project): SubpluginEnvironment { private fun loadSubplugins(project: Project): SubpluginEnvironment {
try { try {
val subplugins = ServiceLoader.load(KotlinGradleSubplugin::class.java, project.buildscript.classLoader) val subplugins = ServiceLoader.load(KotlinGradleSubplugin::class.java, project.buildscript.classLoader)
.map { @Suppress("UNCHECKED_CAST") (it as KotlinGradleSubplugin<KotlinCompile>) } .map { @Suppress("UNCHECKED_CAST") (it as KotlinGradleSubplugin<AbstractCompile>) }
return SubpluginEnvironment(project.resolveSubpluginArtifacts(subplugins), subplugins) return SubpluginEnvironment(project.resolveSubpluginArtifacts(subplugins), subplugins)
} catch (e: NoClassDefFoundError) { } catch (e: NoClassDefFoundError) {
@@ -704,9 +713,9 @@ private fun loadSubplugins(project: Project): SubpluginEnvironment {
} }
} }
internal fun Project.resolveSubpluginArtifacts( internal fun <T: AbstractCompile> Project.resolveSubpluginArtifacts(
subplugins: List<KotlinGradleSubplugin<KotlinCompile>> subplugins: List<KotlinGradleSubplugin<T>>
): Map<KotlinGradleSubplugin<KotlinCompile>, List<File>> { ): Map<KotlinGradleSubplugin<T>, List<File>> {
fun Project.getResolvedArtifacts() = buildscript.configurations.getByName("classpath") fun Project.getResolvedArtifacts() = buildscript.configurations.getByName("classpath")
.resolvedConfiguration.resolvedArtifacts .resolvedConfiguration.resolvedArtifacts
@@ -716,7 +725,7 @@ internal fun Project.resolveSubpluginArtifacts(
resolvedClasspathArtifacts += rootProject.getResolvedArtifacts() resolvedClasspathArtifacts += rootProject.getResolvedArtifacts()
} }
val subpluginClasspaths = hashMapOf<KotlinGradleSubplugin<KotlinCompile>, List<File>>() val subpluginClasspaths = hashMapOf<KotlinGradleSubplugin<T>, List<File>>()
for (subplugin in subplugins) { for (subplugin in subplugins) {
val file = resolvedClasspathArtifacts val file = resolvedClasspathArtifacts
@@ -733,18 +742,18 @@ internal fun Project.resolveSubpluginArtifacts(
} }
internal class SubpluginEnvironment( internal class SubpluginEnvironment(
val subpluginClasspaths: Map<KotlinGradleSubplugin<KotlinCompile>, List<File>>, val subpluginClasspaths: Map<KotlinGradleSubplugin<AbstractCompile>, List<File>>,
val subplugins: List<KotlinGradleSubplugin<KotlinCompile>> val subplugins: List<KotlinGradleSubplugin<AbstractCompile>>
) { ) {
fun addSubpluginOptions( fun <C: CommonCompilerArguments> addSubpluginOptions(
project: Project, project: Project,
kotlinTask: KotlinCompile, kotlinTask: AbstractKotlinCompile<C>,
javaTask: AbstractCompile, javaTask: AbstractCompile,
variantData: Any?, variantData: Any?,
androidProjectHandler: AbstractAndroidProjectHandler<out Any?>?, androidProjectHandler: AbstractAndroidProjectHandler<out Any?>?,
javaSourceSet: SourceSet? javaSourceSet: SourceSet?
): List<KotlinGradleSubplugin<KotlinCompile>> { ): List<KotlinGradleSubplugin<AbstractKotlinCompile<C>>> {
val pluginOptions = kotlinTask.pluginOptions val pluginOptions = kotlinTask.pluginOptions
val appliedSubplugins = subplugins.filter { it.isApplicable(project, kotlinTask) } val appliedSubplugins = subplugins.filter { it.isApplicable(project, kotlinTask) }
@@ -65,6 +65,8 @@ abstract class AbstractKotlinCompileTool<T : CommonToolArguments>() : AbstractCo
abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKotlinCompileTool<T>(), CompilerArgumentAware { abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKotlinCompileTool<T>(), CompilerArgumentAware {
abstract protected fun createCompilerArgs(): T abstract protected fun createCompilerArgs(): T
internal val pluginOptions = CompilerPluginOptions()
protected val additionalClasspath = arrayListOf<File>() protected val additionalClasspath = arrayListOf<File>()
protected val compileClasspath: Iterable<File> protected val compileClasspath: Iterable<File>
get() = (classpath + additionalClasspath) get() = (classpath + additionalClasspath)
@@ -204,6 +206,13 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
if (project.logger.isDebugEnabled) { if (project.logger.isDebugEnabled) {
args.verbose = true args.verbose = true
} }
setupPlugins(args)
}
open fun setupPlugins(compilerArgs: T) {
compilerArgs.pluginClasspaths = pluginOptions.classpath.toTypedArray()
compilerArgs.pluginOptions = pluginOptions.arguments.toTypedArray()
} }
} }
@@ -241,7 +250,6 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
@get:Input @get:Input
internal val javaPackagePrefixInputString get() = javaPackagePrefix ?: "" internal val javaPackagePrefixInputString get() = javaPackagePrefix ?: ""
internal val pluginOptions = CompilerPluginOptions()
internal var artifactDifferenceRegistryProvider: ArtifactDifferenceRegistryProvider? = null internal var artifactDifferenceRegistryProvider: ArtifactDifferenceRegistryProvider? = null
internal var artifactFile: File? = null internal var artifactFile: File? = null
@@ -251,15 +259,17 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
override fun createCompilerArgs(): K2JVMCompilerArguments = override fun createCompilerArgs(): K2JVMCompilerArguments =
K2JVMCompilerArguments() K2JVMCompilerArguments()
override fun setupPlugins(compilerArgs: K2JVMCompilerArguments) {
compilerArgs.pluginClasspaths = pluginOptions.classpath.toTypedArray()
val kaptPluginOptions = getKaptPluginOptions()
compilerArgs.pluginOptions = (pluginOptions.arguments + kaptPluginOptions.arguments).toTypedArray()
}
override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean) { override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean) {
super.setupCompilerArgs(args, defaultsOnly) super.setupCompilerArgs(args, defaultsOnly)
args.apply { fillDefaultValues() } args.apply { fillDefaultValues() }
args.pluginClasspaths = pluginOptions.classpath.toTypedArray()
val kaptPluginOptions = getKaptPluginOptions()
args.pluginOptions = (pluginOptions.arguments + kaptPluginOptions.arguments).toTypedArray()
args.addCompilerBuiltIns = true args.addCompilerBuiltIns = true
val gradleVersion = getGradleVersion() val gradleVersion = getGradleVersion()