Task wiring

* Generalized tasks wiring
* Moved the old implementation to LegacyAndroidAndroidProjectHandler.kt
* Added an implementation with the new AGP API

(cherry picked from commit 1b4592d)

(cherry picked from commit 50a75d4)
This commit is contained in:
Sergey Igushkin
2017-05-08 02:56:52 +03:00
committed by Alexey Tsvetkov
parent eb71dee9cc
commit b0c2c4eba9
4 changed files with 88 additions and 39 deletions
@@ -21,7 +21,7 @@ repositories {
maven { url 'http://repository.jetbrains.com/utils/' } maven { url 'http://repository.jetbrains.com/utils/' }
// todo: remove this once the AGP artifacts get published // todo: remove this once the AGP artifacts get published
maven { url project.property("googlePreviewRepositoryPath") } // path to the local unpacked preview repo maven { url (project.findProperty("googlePreviewRepositoryPath") ?: System.getProperty("googlePreviewRepositoryPath")) }
} }
configurations { configurations {
@@ -57,6 +57,7 @@ tasks.withType(project.compileKotlin.class) {
} }
compileKotlin.dependsOn compileGroovy compileKotlin.dependsOn compileGroovy
compileAgp25Kotlin.dependsOn compileGroovy
compileGroovy.dependsOn.remove("compileJava") compileGroovy.dependsOn.remove("compileJava")
def groovyClassesDir = file("${buildDir}/mainGroovyClasses") def groovyClassesDir = file("${buildDir}/mainGroovyClasses")
@@ -68,6 +69,7 @@ sourceSets.main.java.srcDirs += sourceSets.main.kotlin.srcDirs
sourceSets { sourceSets {
agp25 { agp25 {
compileClasspath += configurations.compile + configurations.agp25CompileOnly + sourceSets.main.output compileClasspath += configurations.compile + configurations.agp25CompileOnly + sourceSets.main.output
compileClasspath += files(groovyClassesDir)
} }
} }
@@ -8,6 +8,8 @@ import com.android.build.gradle.api.UnitTestVariant
import com.android.builder.model.SourceProvider import com.android.builder.model.SourceProvider
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.File import java.io.File
@@ -39,6 +41,45 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
} }
} }
override fun wireKotlinTasks(project: Project,
androidPlugin: BasePlugin,
androidExt: BaseExtension,
variantData: BaseVariant,
javaTask: AbstractCompile,
kotlinTask: KotlinCompile,
kotlinAfterJavaTask: KotlinCompile?) {
val preJavaKotlinOutput =
(if (kotlinAfterJavaTask == null)
// Add Kapt3 output as well, since there's no SyncOutputTask with the new API
project.files(kotlinTask.destinationDir, Kapt3KotlinGradleSubplugin.getKaptClasssesDir(project, getVariantName(variantData)))
else
// Don't register the output, but add the task to the pipeline
project.files()
).builtBy(kotlinTask)
val preJavaClasspathKey = variantData.registerPreJavacGeneratedBytecode(preJavaKotlinOutput)
val kotlinClasspath = variantData.getCompileClasspath(preJavaClasspathKey)
kotlinTask.conventionMapping.map("classpath") {
kotlinClasspath + project.files(AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt))
}
kotlinTask.setJavaOutput(javaTask.destinationDir)
kotlinAfterJavaTask?.setJavaOutput(javaTask.destinationDir)
// Use kapt1 annotations file for up-to-date check since annotation processing is done with javac
kotlinTask.annotationsFile?.let { javaTask.inputs.file(it) }
val kotlinAfterJavaOutput = project.files(kotlinAfterJavaTask).builtBy(kotlinAfterJavaTask)
variantData.registerPostJavacGeneratedBytecode(kotlinAfterJavaOutput)
if (kotlinAfterJavaTask != null) {
// Then don't register kotlinTask output, but only use it for Java compilation
javaTask.appendClasspath(kotlinTask.destinationDir)
}
}
override fun getSourceProviders(variantData: BaseVariant): Iterable<SourceProvider> = override fun getSourceProviders(variantData: BaseVariant): Iterable<SourceProvider> =
variantData.sourceSets variantData.sourceSets
@@ -3,7 +3,6 @@ package org.jetbrains.kotlin.gradle.plugin
import com.android.build.gradle.BaseExtension import com.android.build.gradle.BaseExtension
import com.android.build.gradle.BasePlugin import com.android.build.gradle.BasePlugin
import com.android.build.gradle.api.AndroidSourceSet import com.android.build.gradle.api.AndroidSourceSet
import com.android.build.gradle.internal.variant.BaseVariantData
import com.android.builder.model.SourceProvider import com.android.builder.model.SourceProvider
import groovy.lang.Closure import groovy.lang.Closure
import org.apache.tools.ant.util.ReflectUtil.newInstance import org.apache.tools.ant.util.ReflectUtil.newInstance
@@ -21,13 +20,13 @@ import org.gradle.api.tasks.SourceSet
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.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.gradle.dsl.KotlinJvmOptionsImpl import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.internal.AnnotationProcessingManager import org.jetbrains.kotlin.gradle.internal.AnnotationProcessingManager
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.getKaptClasssesDir import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.getKaptClasssesDir
import org.jetbrains.kotlin.gradle.internal.initKapt import org.jetbrains.kotlin.gradle.internal.initKapt
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.utils.ParsedGradleVersion import org.jetbrains.kotlin.gradle.utils.ParsedGradleVersion
import org.jetbrains.kotlin.incremental.configureMultiProjectIncrementalCompilation import org.jetbrains.kotlin.incremental.configureMultiProjectIncrementalCompilation
@@ -375,22 +374,13 @@ class KotlinConfigurationTools internal constructor(val kotlinSourceSetProvider:
abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationTools: KotlinConfigurationTools) { abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationTools: KotlinConfigurationTools) {
protected val artifactDifferenceRegistryProvider get() = protected val artifactDifferenceRegistryProvider get() =
kotlinConfigurationTools.kotlinGradleBuildServices.artifactDifferenceRegistryProvider kotlinConfigurationTools.kotlinGradleBuildServices.artifactDifferenceRegistryProvider
private val logger = Logging.getLogger(this.javaClass) protected val KotlinCompile.annotationsFile: File? get() = kaptOptions.annotationsFile
protected fun KotlinCompile.setJavaOutput(file: File) { javaOutputDir = file }
protected fun AbstractCompile.appendClasspath(file: File) = appendClasspathDynamically(file)
private fun Project.tryGetSingleArtifact(variantData: BaseVariantData<*>): File? { protected val logger = Logging.getLogger(this.javaClass)
val log = logger
log.kotlinDebug { "Trying to determine single artifact for project $path" }
val outputs = variantData.outputs
if (outputs.size != 1) {
log.kotlinDebug { "Output count != 1 for variant: ${outputs.map { it.outputFile.relativeTo(rootDir).path }.joinToString()}" }
return null
}
return variantData.outputs.first().outputFile
}
protected abstract fun forEachVariant(project: Project, action: (V) -> Unit): Unit protected abstract fun forEachVariant(project: Project, action: (V) -> Unit): Unit
@@ -402,6 +392,14 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
protected abstract fun getJavaTask(variantData: V): AbstractCompile? protected abstract fun getJavaTask(variantData: V): AbstractCompile?
protected abstract fun addJavaSourceDirectoryToVariantModel(variantData: V, javaSourceDirectory: File): Unit protected abstract fun addJavaSourceDirectoryToVariantModel(variantData: V, javaSourceDirectory: File): Unit
protected abstract fun wireKotlinTasks(project: Project,
androidPlugin: BasePlugin,
androidExt: BaseExtension,
variantData: V,
javaTask: AbstractCompile,
kotlinTask: KotlinCompile,
kotlinAfterJavaTask: KotlinCompile?): Unit
protected abstract fun configureMultiProjectIc(project: Project, protected abstract fun configureMultiProjectIc(project: Project,
variantData: V, variantData: V,
javaTask: AbstractCompile, javaTask: AbstractCompile,
@@ -455,10 +453,6 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
val variantDataName = getVariantName(variantData) val variantDataName = getVariantName(variantData)
logger.kotlinDebug("Process variant [$variantDataName]") logger.kotlinDebug("Process variant [$variantDataName]")
val testedVariantData = getTestedVariantData(variantData)
val isAndroidTestVariant = variantDataName.endsWith("androidTest", ignoreCase = true) &&
testedVariantData != null
val javaTask = getJavaTask(variantData) val javaTask = getJavaTask(variantData)
if (javaTask == null) { if (javaTask == null) {
@@ -474,7 +468,6 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
// store kotlin classes in separate directory. They will serve as class-path to java compiler // store kotlin classes in separate directory. They will serve as class-path to java compiler
kotlinTask.destinationDir = File(project.buildDir, "tmp/kotlin-classes/$variantDataName") kotlinTask.destinationDir = File(project.buildDir, "tmp/kotlin-classes/$variantDataName")
kotlinTask.description = "Compiles the $variantDataName kotlin." kotlinTask.description = "Compiles the $variantDataName kotlin."
kotlinTask.setDependsOn(javaTask.dependsOn)
val isKapt3Enabled = Kapt3GradleSubplugin.isEnabled(project) val isKapt3Enabled = Kapt3GradleSubplugin.isEnabled(project)
@@ -502,10 +495,6 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
val appliedPlugins = subpluginEnvironment.addSubpluginOptions( val appliedPlugins = subpluginEnvironment.addSubpluginOptions(
project, kotlinTask, javaTask, variantData, null) project, kotlinTask, javaTask, variantData, null)
kotlinTask.mapClasspath {
javaTask.classpath + project.files(AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt))
}
var kotlinAfterJavaTask: KotlinCompile? = null var kotlinAfterJavaTask: KotlinCompile? = null
if (javaTask is JavaCompile && aptFiles.isNotEmpty() && !isKapt3Enabled) { if (javaTask is JavaCompile && aptFiles.isNotEmpty() && !isKapt3Enabled) {
@@ -524,18 +513,11 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
configureSources(task, variantData) configureSources(task, variantData)
} }
if (isAndroidTestVariant) {
// Android Gradle plugin bypasses the Gradle finalizedBy for its tasks in some cases, and
// the Kotlin classes may not be copied for the tested variant. Make sure they are.
kotlinTask.dependsOn(syncOutputTaskName(getVariantName(testedVariantData!!)))
}
appliedPlugins.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } appliedPlugins.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) }
.forEach { configureSources(it, variantData) } .forEach { configureSources(it, variantData) }
//todo Wire tasks and classpaths with the new API wireKotlinTasks(project, androidPlugin, androidExt, variantData, javaTask,
configureJavaTask(kotlinTask, javaTask, logger) kotlinTask, kotlinAfterJavaTask)
createSyncOutputTask(project, kotlinTask, javaTask, kotlinAfterJavaTask, variantDataName)
configureMultiProjectIc(project, variantData, javaTask, kotlinTask, kotlinAfterJavaTask) configureMultiProjectIc(project, variantData, javaTask, kotlinTask, kotlinAfterJavaTask)
} }
@@ -555,7 +537,7 @@ abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationT
} }
} }
private fun configureJavaTask(kotlinTask: KotlinCompile, javaTask: AbstractCompile, logger: Logger) { internal fun configureJavaTask(kotlinTask: KotlinCompile, javaTask: AbstractCompile, logger: Logger) {
// Gradle Java IC in older Gradle versions (before 2.14) cannot check .class directories updates. // Gradle Java IC in older Gradle versions (before 2.14) cannot check .class directories updates.
// To make it work, reset the up-to-date status of compileJava with this flag. // To make it work, reset the up-to-date status of compileJava with this flag.
kotlinTask.anyClassesCompiled = false kotlinTask.anyClassesCompiled = false
@@ -587,9 +569,9 @@ private fun configureJavaTask(kotlinTask: KotlinCompile, javaTask: AbstractCompi
javaTask.appendClasspathDynamically(kotlinTask.destinationDir!!) javaTask.appendClasspathDynamically(kotlinTask.destinationDir!!)
} }
private fun syncOutputTaskName(variantName: String) = "copy${variantName.capitalize()}KotlinClasses" internal fun syncOutputTaskName(variantName: String) = "copy${variantName.capitalize()}KotlinClasses"
private fun createSyncOutputTask( internal fun createSyncOutputTask(
project: Project, project: Project,
kotlinTask: KotlinCompile, kotlinTask: KotlinCompile,
javaTask: AbstractCompile, javaTask: AbstractCompile,
@@ -1,5 +1,6 @@
package org.jetbrains.kotlin.gradle.plugin package org.jetbrains.kotlin.gradle.plugin
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.BasePlugin import com.android.build.gradle.BasePlugin
import com.android.build.gradle.internal.variant.BaseVariantData import com.android.build.gradle.internal.variant.BaseVariantData
import com.android.build.gradle.internal.variant.BaseVariantOutputData import com.android.build.gradle.internal.variant.BaseVariantOutputData
@@ -31,6 +32,30 @@ internal class LegacyAndroidAndroidProjectHandler(kotlinConfigurationTools: Kotl
variantManager.variantDataList.forEach(action) variantManager.variantDataList.forEach(action)
} }
override fun wireKotlinTasks(project: Project,
androidPlugin: BasePlugin,
androidExt: BaseExtension,
variantData: BaseVariantData<out BaseVariantOutputData>,
javaTask: AbstractCompile,
kotlinTask: KotlinCompile,
kotlinAfterJavaTask: KotlinCompile?) {
kotlinTask.setDependsOn(javaTask.dependsOn)
kotlinTask.mapClasspath {
javaTask.classpath + project.files(AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt))
}
getTestedVariantData(variantData)?.let { testedVariantData ->
// Android Gradle plugin bypasses the Gradle finalizedBy for its tasks in some cases, and
// the Kotlin classes may not be copied for the tested variant. Make sure they are.
kotlinTask.dependsOn(syncOutputTaskName(getVariantName(testedVariantData)))
}
configureJavaTask(kotlinTask, javaTask, logger)
createSyncOutputTask(project, kotlinTask, javaTask, kotlinAfterJavaTask, getVariantName(variantData))
}
override fun getVariantName(variant: BaseVariantData<out BaseVariantOutputData>): String = variant.name override fun getVariantName(variant: BaseVariantData<out BaseVariantOutputData>): String = variant.name
override fun checkVariant(variant: BaseVariantData<out BaseVariantOutputData>): Unit { override fun checkVariant(variant: BaseVariantData<out BaseVariantOutputData>): Unit {
@@ -44,7 +69,6 @@ internal class LegacyAndroidAndroidProjectHandler(kotlinConfigurationTools: Kotl
override fun getJavaTask(variantData: BaseVariantData<out BaseVariantOutputData>): AbstractCompile? = override fun getJavaTask(variantData: BaseVariantData<out BaseVariantOutputData>): AbstractCompile? =
AndroidGradleWrapper.getJavaTask(variantData) AndroidGradleWrapper.getJavaTask(variantData)
override fun addJavaSourceDirectoryToVariantModel(variantData: BaseVariantData<out BaseVariantOutputData>, override fun addJavaSourceDirectoryToVariantModel(variantData: BaseVariantData<out BaseVariantOutputData>,
javaSourceDirectory: File) = javaSourceDirectory: File) =
variantData.addJavaSourceFoldersToModel(javaSourceDirectory) variantData.addJavaSourceFoldersToModel(javaSourceDirectory)