Add prototype against the new AGP API
* Add a separate Gradle source set, that is compiled against the new versions of AGP and Gradle * Separate the public AGP API usages from the old internal API usages in KotlinPlugin.kt -- see AbstractAndroidProjectHandler * Implement Android25ProjectHandler with the new AGP API, wired it to KotlinAndroidPlugin through reflection (cherry picked from commit e6dbf54) (cherry picked from commit 88e3d4b)
This commit is contained in:
committed by
Alexey Tsvetkov
parent
a5620454fa
commit
eb71dee9cc
@@ -19,6 +19,13 @@ repositories {
|
|||||||
jcenter()
|
jcenter()
|
||||||
mavenLocal()
|
mavenLocal()
|
||||||
maven { url 'http://repository.jetbrains.com/utils/' }
|
maven { url 'http://repository.jetbrains.com/utils/' }
|
||||||
|
|
||||||
|
// todo: remove this once the AGP artifacts get published
|
||||||
|
maven { url project.property("googlePreviewRepositoryPath") } // path to the local unpacked preview repo
|
||||||
|
}
|
||||||
|
|
||||||
|
configurations {
|
||||||
|
agp25CompileOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -37,6 +44,10 @@ dependencies {
|
|||||||
compileOnly 'org.codehaus.groovy:groovy-all:2.3.9'
|
compileOnly 'org.codehaus.groovy:groovy-all:2.3.9'
|
||||||
compileOnly 'org.jetbrains.kotlin:gradle-api:2.2'
|
compileOnly 'org.jetbrains.kotlin:gradle-api:2.2'
|
||||||
|
|
||||||
|
agp25CompileOnly 'com.android.tools.build:gradle:2.4.0-dev'
|
||||||
|
agp25CompileOnly 'org.codehaus.groovy:groovy-all:2.3.9'
|
||||||
|
agp25CompileOnly gradleApi()
|
||||||
|
|
||||||
testCompile "org.jetbrains.kotlin:kotlin-build-common-test:$kotlin_version"
|
testCompile "org.jetbrains.kotlin:kotlin-build-common-test:$kotlin_version"
|
||||||
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
|
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
|
||||||
}
|
}
|
||||||
@@ -54,12 +65,21 @@ sourceSets.main.compileClasspath += files(groovyClassesDir)
|
|||||||
compileGroovy.classpath = sourceSets.main.compileClasspath - files(groovyClassesDir)
|
compileGroovy.classpath = sourceSets.main.compileClasspath - files(groovyClassesDir)
|
||||||
sourceSets.main.java.srcDirs += sourceSets.main.kotlin.srcDirs
|
sourceSets.main.java.srcDirs += sourceSets.main.kotlin.srcDirs
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
agp25 {
|
||||||
|
compileClasspath += configurations.compile + configurations.agp25CompileOnly + sourceSets.main.output
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
expand(project.properties)
|
expand(project.properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jar.dependsOn agp25Classes
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
from compileGroovy.destinationDir
|
from compileGroovy.destinationDir
|
||||||
|
from sourceSets.agp25.output.classesDir
|
||||||
}
|
}
|
||||||
|
|
||||||
test.executable = "${JDK_18}/bin/java"
|
test.executable = "${JDK_18}/bin/java"
|
||||||
|
|||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
package org.jetbrains.kotlin.gradle.plugin
|
||||||
|
|
||||||
|
import com.android.build.gradle.*
|
||||||
|
import com.android.build.gradle.api.BaseVariant
|
||||||
|
import com.android.build.gradle.api.SourceKind
|
||||||
|
import com.android.build.gradle.api.TestVariant
|
||||||
|
import com.android.build.gradle.api.UnitTestVariant
|
||||||
|
import com.android.builder.model.SourceProvider
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.tasks.compile.AbstractCompile
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools)
|
||||||
|
: AbstractAndroidProjectHandler<BaseVariant>(kotlinConfigurationTools) {
|
||||||
|
|
||||||
|
override fun forEachVariant(project: Project, action: (BaseVariant) -> Unit) {
|
||||||
|
project.plugins.all { plugin ->
|
||||||
|
val androidExtension = project.extensions.getByName("android")
|
||||||
|
var testedExtension: TestedExtension? = null
|
||||||
|
when (plugin.javaClass) {
|
||||||
|
AppPlugin::class.java -> {
|
||||||
|
(androidExtension as AppExtension).applicationVariants.all(action)
|
||||||
|
testedExtension = androidExtension
|
||||||
|
}
|
||||||
|
LibraryPlugin::class.java -> {
|
||||||
|
(androidExtension as LibraryExtension).libraryVariants.all(action)
|
||||||
|
testedExtension = androidExtension
|
||||||
|
}
|
||||||
|
TestPlugin::class.java -> {
|
||||||
|
(androidExtension as TestExtension).applicationVariants.all(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testedExtension?.apply {
|
||||||
|
testVariants.all(action)
|
||||||
|
unitTestVariants.all(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSourceProviders(variantData: BaseVariant): Iterable<SourceProvider> =
|
||||||
|
variantData.sourceSets
|
||||||
|
|
||||||
|
override fun getAllJavaSources(variantData: BaseVariant): Iterable<File> =
|
||||||
|
variantData.getSourceFolders(SourceKind.JAVA).map { it.dir }
|
||||||
|
|
||||||
|
override fun getVariantName(variant: BaseVariant): String = variant.name
|
||||||
|
|
||||||
|
override fun checkVariant(variant: BaseVariant) = Unit
|
||||||
|
|
||||||
|
override fun getTestedVariantData(variantData: BaseVariant): BaseVariant? = when (variantData) {
|
||||||
|
is TestVariant -> variantData.testedVariant
|
||||||
|
is UnitTestVariant -> variantData.testedVariant as? BaseVariant
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getJavaTask(variantData: BaseVariant): AbstractCompile? =
|
||||||
|
@Suppress("DEPRECATION") // There is always a Java compile task -- the deprecation was for Jack
|
||||||
|
variantData.javaCompile
|
||||||
|
|
||||||
|
override fun addJavaSourceDirectoryToVariantModel(variantData: BaseVariant, javaSourceDirectory: File) =
|
||||||
|
variantData.addJavaSourceFoldersToModel(javaSourceDirectory)
|
||||||
|
|
||||||
|
override fun configureMultiProjectIc(project: Project,
|
||||||
|
variantData: BaseVariant,
|
||||||
|
javaTask: AbstractCompile,
|
||||||
|
kotlinTask: KotlinCompile,
|
||||||
|
kotlinAfterJavaTask: KotlinCompile?) {
|
||||||
|
//todo: No easy solution because of the absence of the output information in library modules
|
||||||
|
// Though it is affordable not to implement this for the first previews, because the impact is tolerable
|
||||||
|
// to some degree -- the dependent projects will rebuild non-incrementally when a library project changes
|
||||||
|
}
|
||||||
|
}
|
||||||
+168
-145
@@ -4,14 +4,12 @@ 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.build.gradle.internal.variant.BaseVariantData
|
||||||
import com.android.build.gradle.internal.variant.BaseVariantOutputData
|
|
||||||
import com.android.build.gradle.internal.variant.TestVariantData
|
|
||||||
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.gradle.api.InvalidUserDataException
|
import org.gradle.api.InvalidUserDataException
|
||||||
import org.gradle.api.Plugin
|
import org.gradle.api.Plugin
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.ProjectConfigurationException
|
|
||||||
import org.gradle.api.artifacts.Configuration
|
import org.gradle.api.artifacts.Configuration
|
||||||
import org.gradle.api.logging.Logger
|
import org.gradle.api.logging.Logger
|
||||||
import org.gradle.api.logging.Logging
|
import org.gradle.api.logging.Logging
|
||||||
@@ -33,7 +31,6 @@ 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
|
||||||
import org.jetbrains.kotlin.incremental.multiproject.ArtifactDifferenceRegistryProviderAndroidWrapper
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -339,11 +336,7 @@ internal open class KotlinAndroidPlugin(
|
|||||||
private val kotlinGradleBuildServices: KotlinGradleBuildServices
|
private val kotlinGradleBuildServices: KotlinGradleBuildServices
|
||||||
) : Plugin<Project> {
|
) : Plugin<Project> {
|
||||||
|
|
||||||
private val log = Logging.getLogger(this.javaClass)
|
|
||||||
|
|
||||||
override fun apply(project: Project) {
|
override fun apply(project: Project) {
|
||||||
val ext = project.extensions.getByName("android") as BaseExtension
|
|
||||||
|
|
||||||
val version = loadAndroidPluginVersion()
|
val version = loadAndroidPluginVersion()
|
||||||
if (version != null) {
|
if (version != null) {
|
||||||
val minimalVersion = "1.1.0"
|
val minimalVersion = "1.1.0"
|
||||||
@@ -352,15 +345,80 @@ internal open class KotlinAndroidPlugin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val kotlinTools = KotlinConfigurationTools(
|
||||||
|
kotlinSourceSetProvider,
|
||||||
|
tasksProvider,
|
||||||
|
kotlinPluginVersion,
|
||||||
|
kotlinGradleBuildServices)
|
||||||
|
|
||||||
|
val legacyVersionThreshold = "2.4.0"
|
||||||
|
|
||||||
|
val variantProcessor = if (compareVersionNumbers(version, legacyVersionThreshold) < 0)
|
||||||
|
LegacyAndroidAndroidProjectHandler(kotlinTools)
|
||||||
|
else
|
||||||
|
newInstance(
|
||||||
|
Class.forName("org.jetbrains.kotlin.gradle.plugin.Android25ProjectHandler"),
|
||||||
|
arrayOf(kotlinTools.javaClass), arrayOf(kotlinTools)) as AbstractAndroidProjectHandler<*>
|
||||||
|
|
||||||
|
variantProcessor.handleProject(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinConfigurationTools internal constructor(val kotlinSourceSetProvider: KotlinSourceSetProvider,
|
||||||
|
val kotlinTasksProvider: KotlinTasksProvider,
|
||||||
|
val kotlinPluginVersion: String,
|
||||||
|
val kotlinGradleBuildServices: KotlinGradleBuildServices)
|
||||||
|
|
||||||
|
/** Part of Android configuration, that works only with the old public API.
|
||||||
|
* @see [LegacyAndroidAndroidProjectHandler] that is implemented with the old internal API and [AndroidGradle25VariantProcessor] that works
|
||||||
|
* with the new public API */
|
||||||
|
abstract class AbstractAndroidProjectHandler<V>(private val kotlinConfigurationTools: KotlinConfigurationTools) {
|
||||||
|
|
||||||
|
protected val artifactDifferenceRegistryProvider get() =
|
||||||
|
kotlinConfigurationTools.kotlinGradleBuildServices.artifactDifferenceRegistryProvider
|
||||||
|
|
||||||
|
private val logger = Logging.getLogger(this.javaClass)
|
||||||
|
|
||||||
|
private fun Project.tryGetSingleArtifact(variantData: BaseVariantData<*>): File? {
|
||||||
|
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 getSourceProviders(variantData: V): Iterable<SourceProvider>
|
||||||
|
protected abstract fun getAllJavaSources(variantData: V): Iterable<File>
|
||||||
|
protected abstract fun getVariantName(variant: V): String
|
||||||
|
protected abstract fun checkVariant(variant: V): Unit
|
||||||
|
protected abstract fun getTestedVariantData(variantData: V): V?
|
||||||
|
protected abstract fun getJavaTask(variantData: V): AbstractCompile?
|
||||||
|
protected abstract fun addJavaSourceDirectoryToVariantModel(variantData: V, javaSourceDirectory: File): Unit
|
||||||
|
|
||||||
|
protected abstract fun configureMultiProjectIc(project: Project,
|
||||||
|
variantData: V,
|
||||||
|
javaTask: AbstractCompile,
|
||||||
|
kotlinTask: KotlinCompile,
|
||||||
|
kotlinAfterJavaTask: KotlinCompile?)
|
||||||
|
|
||||||
|
fun handleProject(project: Project) {
|
||||||
|
val ext = project.extensions.getByName("android") as BaseExtension
|
||||||
val aptConfigurations = hashMapOf<String, Configuration>()
|
val aptConfigurations = hashMapOf<String, Configuration>()
|
||||||
|
|
||||||
ext.sourceSets.all { sourceSet ->
|
ext.sourceSets.all { sourceSet ->
|
||||||
log.kotlinDebug("Creating KotlinSourceSet for source set $sourceSet")
|
logger.kotlinDebug("Creating KotlinSourceSet for source set $sourceSet")
|
||||||
val kotlinSourceSet = kotlinSourceSetProvider.create(sourceSet.name)
|
val kotlinSourceSet = kotlinConfigurationTools.kotlinSourceSetProvider.create(sourceSet.name)
|
||||||
kotlinSourceSet.kotlin.srcDir(project.file(project.file("src/${sourceSet.name}/kotlin")))
|
kotlinSourceSet.kotlin.srcDir(project.file(project.file("src/${sourceSet.name}/kotlin")))
|
||||||
sourceSet.addConvention(KOTLIN_DSL_NAME, kotlinSourceSet)
|
sourceSet.addConvention(KOTLIN_DSL_NAME, kotlinSourceSet)
|
||||||
|
|
||||||
aptConfigurations.put(sourceSet.name, project.createAptConfiguration(sourceSet.name, kotlinPluginVersion))
|
aptConfigurations.put(sourceSet.name, project.createAptConfiguration(sourceSet.name, kotlinConfigurationTools.kotlinPluginVersion))
|
||||||
}
|
}
|
||||||
|
|
||||||
val kotlinOptions = KotlinJvmOptionsImpl()
|
val kotlinOptions = KotlinJvmOptionsImpl()
|
||||||
@@ -372,164 +430,129 @@ internal open class KotlinAndroidPlugin(
|
|||||||
project.afterEvaluate { project ->
|
project.afterEvaluate { project ->
|
||||||
if (project != null) {
|
if (project != null) {
|
||||||
val plugin = (project.plugins.findPlugin("android")
|
val plugin = (project.plugins.findPlugin("android")
|
||||||
?: project.plugins.findPlugin("android-library")
|
?: project.plugins.findPlugin("android-library")
|
||||||
?: project.plugins.findPlugin("com.android.test")) as BasePlugin
|
?: project.plugins.findPlugin("com.android.test")) as BasePlugin
|
||||||
|
val subpluginEnvironment = loadSubplugins(project)
|
||||||
|
|
||||||
val variantManager = AndroidGradleWrapper.getVariantDataManager(plugin)
|
forEachVariant(project) {
|
||||||
processVariantData(variantManager.variantDataList, project,
|
processVariant(it, project, ext, plugin, aptConfigurations, kotlinOptions,
|
||||||
ext, plugin, aptConfigurations, kotlinOptions)
|
kotlinConfigurationTools.kotlinTasksProvider, subpluginEnvironment)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTestedVariantData(variantData: BaseVariantData<*>): BaseVariantData<*>? =
|
private fun processVariant(variantData: V,
|
||||||
((variantData as? TestVariantData)?.testedVariantData as? BaseVariantData<*>)
|
project: Project,
|
||||||
|
androidExt: BaseExtension,
|
||||||
|
androidPlugin: BasePlugin,
|
||||||
|
aptConfigurations: Map<String, Configuration>,
|
||||||
|
rootKotlinOptions: KotlinJvmOptionsImpl,
|
||||||
|
tasksProvider: KotlinTasksProvider, subpluginEnvironment: SubpluginEnvironment) {
|
||||||
|
|
||||||
private fun processVariantData(
|
checkVariant(variantData)
|
||||||
variantDataList: List<BaseVariantData<out BaseVariantOutputData>>,
|
|
||||||
project: Project,
|
|
||||||
androidExt: BaseExtension,
|
|
||||||
androidPlugin: BasePlugin,
|
|
||||||
aptConfigurations: Map<String, Configuration>,
|
|
||||||
rootKotlinOptions: KotlinJvmOptionsImpl
|
|
||||||
) {
|
|
||||||
val logger = project.logger
|
|
||||||
val subpluginEnvironment = loadSubplugins(project)
|
|
||||||
|
|
||||||
for (variantData in variantDataList) {
|
val variantDataName = getVariantName(variantData)
|
||||||
if (AndroidGradleWrapper.isJackEnabled(variantData)) {
|
logger.kotlinDebug("Process variant [$variantDataName]")
|
||||||
throw ProjectConfigurationException(
|
|
||||||
"Kotlin Gradle plugin does not support the deprecated Jack toolchain.\n" +
|
val testedVariantData = getTestedVariantData(variantData)
|
||||||
"Disable Jack or revert to Kotlin Gradle plugin version 1.1.1.", null)
|
val isAndroidTestVariant = variantDataName.endsWith("androidTest", ignoreCase = true) &&
|
||||||
|
testedVariantData != null
|
||||||
|
|
||||||
|
val javaTask = getJavaTask(variantData)
|
||||||
|
|
||||||
|
if (javaTask == null) {
|
||||||
|
logger.info("KOTLIN: javaTask is missing for $variantDataName, so Kotlin files won't be compiled for it")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinTaskName = "compile${variantDataName.capitalize()}Kotlin"
|
||||||
|
// todo: Investigate possibility of creating and configuring kotlinTask before evaluation
|
||||||
|
val kotlinTask = tasksProvider.createKotlinJVMTask(project, kotlinTaskName, variantDataName)
|
||||||
|
kotlinTask.parentKotlinOptionsImpl = rootKotlinOptions
|
||||||
|
|
||||||
|
// 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.description = "Compiles the $variantDataName kotlin."
|
||||||
|
kotlinTask.setDependsOn(javaTask.dependsOn)
|
||||||
|
|
||||||
|
val isKapt3Enabled = Kapt3GradleSubplugin.isEnabled(project)
|
||||||
|
|
||||||
|
val aptFiles = arrayListOf<File>()
|
||||||
|
|
||||||
|
if (!isKapt3Enabled) {
|
||||||
|
var hasAnyKaptDependency: Boolean = false
|
||||||
|
for (provider in getSourceProviders(variantData)) {
|
||||||
|
val aptConfiguration = aptConfigurations[(provider as AndroidSourceSet).name]
|
||||||
|
// Ignore if there's only an annotation processor wrapper in dependencies (added by default)
|
||||||
|
if (aptConfiguration != null && aptConfiguration.allDependencies.size > 1) {
|
||||||
|
javaTask.dependsOn(aptConfiguration.buildDependencies)
|
||||||
|
aptFiles.addAll(aptConfiguration.resolve())
|
||||||
|
hasAnyKaptDependency = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val variantDataName = variantData.name
|
if (!hasAnyKaptDependency) {
|
||||||
logger.kotlinDebug("Process variant [$variantDataName]")
|
|
||||||
|
|
||||||
val testedVariantData = getTestedVariantData(variantData)
|
|
||||||
val isAndroidTestVariant = variantDataName.endsWith("androidTest", ignoreCase = true) &&
|
|
||||||
testedVariantData != null
|
|
||||||
|
|
||||||
val javaTask = AndroidGradleWrapper.getJavaTask(variantData)
|
|
||||||
|
|
||||||
if (javaTask == null) {
|
|
||||||
logger.info("KOTLIN: javaTask is missing for $variantDataName, so Kotlin files won't be compiled for it")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
val kotlinTaskName = "compile${variantDataName.capitalize()}Kotlin"
|
|
||||||
// todo: Investigate possibility of creating and configuring kotlinTask before evaluation
|
|
||||||
val kotlinTask = tasksProvider.createKotlinJVMTask(project, kotlinTaskName, variantData.name)
|
|
||||||
kotlinTask.parentKotlinOptionsImpl = rootKotlinOptions
|
|
||||||
|
|
||||||
// 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.description = "Compiles the $variantDataName kotlin."
|
|
||||||
kotlinTask.setDependsOn(javaTask.dependsOn)
|
|
||||||
|
|
||||||
val isKapt3Enabled = Kapt3GradleSubplugin.isEnabled(project)
|
|
||||||
|
|
||||||
val aptFiles = arrayListOf<File>()
|
|
||||||
|
|
||||||
if (!isKapt3Enabled) {
|
|
||||||
var hasAnyKaptDependency: Boolean = false
|
|
||||||
for (provider in variantData.sourceProviders) {
|
|
||||||
val aptConfiguration = aptConfigurations[(provider as AndroidSourceSet).name]
|
|
||||||
// Ignore if there's only an annotation processor wrapper in dependencies (added by default)
|
|
||||||
if (aptConfiguration != null && aptConfiguration.allDependencies.size > 1) {
|
|
||||||
javaTask.dependsOn(aptConfiguration.buildDependencies)
|
|
||||||
aptFiles.addAll(aptConfiguration.resolve())
|
|
||||||
hasAnyKaptDependency = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasAnyKaptDependency) {
|
|
||||||
removeAnnotationProcessingPluginClasspathEntry(kotlinTask)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
removeAnnotationProcessingPluginClasspathEntry(kotlinTask)
|
removeAnnotationProcessingPluginClasspathEntry(kotlinTask)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
val appliedPlugins = subpluginEnvironment.addSubpluginOptions(
|
removeAnnotationProcessingPluginClasspathEntry(kotlinTask)
|
||||||
project, kotlinTask, javaTask, variantData, null)
|
|
||||||
|
|
||||||
kotlinTask.mapClasspath {
|
|
||||||
javaTask.classpath + project.files(AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt))
|
|
||||||
}
|
|
||||||
|
|
||||||
var kotlinAfterJavaTask: KotlinCompile? = null
|
|
||||||
|
|
||||||
if (javaTask is JavaCompile && aptFiles.isNotEmpty() && !isKapt3Enabled) {
|
|
||||||
val (aptOutputDir, aptWorkingDir) = project.getAptDirsForSourceSet(variantDataName)
|
|
||||||
|
|
||||||
variantData.addJavaSourceFoldersToModel(aptOutputDir)
|
|
||||||
|
|
||||||
val kaptManager = AnnotationProcessingManager(kotlinTask, javaTask, variantDataName,
|
|
||||||
aptFiles.toSet(), aptOutputDir, aptWorkingDir, variantData)
|
|
||||||
|
|
||||||
kotlinAfterJavaTask = project.initKapt(kotlinTask, javaTask, kaptManager,
|
|
||||||
variantDataName, rootKotlinOptions, subpluginEnvironment, tasksProvider)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (task in listOfNotNull(kotlinTask, kotlinAfterJavaTask)) {
|
|
||||||
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(testedVariantData!!.name))
|
|
||||||
}
|
|
||||||
|
|
||||||
appliedPlugins
|
|
||||||
.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) }
|
|
||||||
.forEach { configureSources(it, variantData) }
|
|
||||||
|
|
||||||
configureJavaTask(kotlinTask, javaTask, logger)
|
|
||||||
createSyncOutputTask(project, kotlinTask, javaTask, kotlinAfterJavaTask, variantDataName)
|
|
||||||
|
|
||||||
if ((kotlinAfterJavaTask ?: kotlinTask).incremental) {
|
|
||||||
val artifactFile = project.tryGetSingleArtifact(variantData)
|
|
||||||
val artifactDifferenceRegistryProvider = ArtifactDifferenceRegistryProviderAndroidWrapper(
|
|
||||||
kotlinGradleBuildServices.artifactDifferenceRegistryProvider,
|
|
||||||
{ AndroidGradleWrapper.getJarToAarMapping(variantData) }
|
|
||||||
)
|
|
||||||
configureMultiProjectIncrementalCompilation(project, kotlinTask, javaTask, kotlinAfterJavaTask,
|
|
||||||
artifactDifferenceRegistryProvider, artifactFile)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val appliedPlugins = subpluginEnvironment.addSubpluginOptions(
|
||||||
|
project, kotlinTask, javaTask, variantData, null)
|
||||||
|
|
||||||
|
kotlinTask.mapClasspath {
|
||||||
|
javaTask.classpath + project.files(AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt))
|
||||||
|
}
|
||||||
|
|
||||||
|
var kotlinAfterJavaTask: KotlinCompile? = null
|
||||||
|
|
||||||
|
if (javaTask is JavaCompile && aptFiles.isNotEmpty() && !isKapt3Enabled) {
|
||||||
|
val (aptOutputDir, aptWorkingDir) = project.getAptDirsForSourceSet(variantDataName)
|
||||||
|
|
||||||
|
addJavaSourceDirectoryToVariantModel(variantData, aptOutputDir)
|
||||||
|
|
||||||
|
val kaptManager = AnnotationProcessingManager(kotlinTask, javaTask, variantDataName,
|
||||||
|
aptFiles.toSet(), aptOutputDir, aptWorkingDir, variantData)
|
||||||
|
|
||||||
|
kotlinAfterJavaTask = project.initKapt(kotlinTask, javaTask, kaptManager,
|
||||||
|
variantDataName, rootKotlinOptions, subpluginEnvironment, tasksProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (task in listOfNotNull(kotlinTask, kotlinAfterJavaTask)) {
|
||||||
|
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) }
|
||||||
|
.forEach { configureSources(it, variantData) }
|
||||||
|
|
||||||
|
//todo Wire tasks and classpaths with the new API
|
||||||
|
configureJavaTask(kotlinTask, javaTask, logger)
|
||||||
|
createSyncOutputTask(project, kotlinTask, javaTask, kotlinAfterJavaTask, variantDataName)
|
||||||
|
|
||||||
|
configureMultiProjectIc(project, variantData, javaTask, kotlinTask, kotlinAfterJavaTask)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configureSources(compileTask: AbstractCompile,
|
private fun configureSources(compileTask: AbstractCompile, variantData: V) {
|
||||||
variantData: BaseVariantData<out BaseVariantOutputData>) {
|
|
||||||
val logger = compileTask.project.logger
|
val logger = compileTask.project.logger
|
||||||
|
|
||||||
for (provider in variantData.sourceProviders) {
|
for (provider in getSourceProviders(variantData)) {
|
||||||
val kotlinSourceSet = provider.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet ?: continue
|
val kotlinSourceSet = provider.getConvention(KOTLIN_DSL_NAME) as? KotlinSourceSet ?: continue
|
||||||
compileTask.source(kotlinSourceSet.kotlin)
|
compileTask.source(kotlinSourceSet.kotlin)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (javaSrcDir in AndroidGradleWrapper.getJavaSources(variantData)) {
|
for (javaSrcDir in getAllJavaSources(variantData)) {
|
||||||
compileTask.source(javaSrcDir)
|
compileTask.source(javaSrcDir)
|
||||||
logger.kotlinDebug("Source directory $javaSrcDir was added to kotlin source for ${compileTask.name}")
|
logger.kotlinDebug("Source directory $javaSrcDir was added to kotlin source for ${compileTask.name}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Project.tryGetSingleArtifact(variantData: BaseVariantData<*>): File? {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
private val BaseVariantData<*>.sourceProviders: List<SourceProvider>
|
|
||||||
get() = variantConfiguration.sortedSourceProviders
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configureJavaTask(kotlinTask: KotlinCompile, javaTask: AbstractCompile, logger: Logger) {
|
private fun configureJavaTask(kotlinTask: KotlinCompile, javaTask: AbstractCompile, logger: Logger) {
|
||||||
|
|||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
package org.jetbrains.kotlin.gradle.plugin
|
||||||
|
|
||||||
|
import com.android.build.gradle.BasePlugin
|
||||||
|
import com.android.build.gradle.internal.variant.BaseVariantData
|
||||||
|
import com.android.build.gradle.internal.variant.BaseVariantOutputData
|
||||||
|
import com.android.build.gradle.internal.variant.TestVariantData
|
||||||
|
import com.android.builder.model.SourceProvider
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.ProjectConfigurationException
|
||||||
|
import org.gradle.api.tasks.compile.AbstractCompile
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
import org.jetbrains.kotlin.incremental.configureMultiProjectIncrementalCompilation
|
||||||
|
import org.jetbrains.kotlin.incremental.multiproject.ArtifactDifferenceRegistryProviderAndroidWrapper
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal class LegacyAndroidAndroidProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools)
|
||||||
|
: AbstractAndroidProjectHandler<BaseVariantData<out BaseVariantOutputData>>(kotlinConfigurationTools) {
|
||||||
|
|
||||||
|
override fun getSourceProviders(variantData: BaseVariantData<out BaseVariantOutputData>): Iterable<SourceProvider> =
|
||||||
|
variantData.sourceProviders
|
||||||
|
|
||||||
|
override fun getAllJavaSources(variantData: BaseVariantData<out BaseVariantOutputData>): Iterable<File> =
|
||||||
|
AndroidGradleWrapper.getJavaSources(variantData)
|
||||||
|
|
||||||
|
override fun forEachVariant(project: Project, action: (BaseVariantData<out BaseVariantOutputData>) -> Unit) {
|
||||||
|
val plugin = (project.plugins.findPlugin("android")
|
||||||
|
?: project.plugins.findPlugin("android-library")
|
||||||
|
?: project.plugins.findPlugin("com.android.test")) as BasePlugin
|
||||||
|
val variantManager = AndroidGradleWrapper.getVariantDataManager(plugin)
|
||||||
|
variantManager.variantDataList.forEach(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getVariantName(variant: BaseVariantData<out BaseVariantOutputData>): String = variant.name
|
||||||
|
|
||||||
|
override fun checkVariant(variant: BaseVariantData<out BaseVariantOutputData>): Unit {
|
||||||
|
if (AndroidGradleWrapper.isJackEnabled(variant)) {
|
||||||
|
throw ProjectConfigurationException(
|
||||||
|
"Kotlin Gradle plugin does not support the deprecated Jack toolchain.\n" +
|
||||||
|
"Disable Jack or revert to Kotlin Gradle plugin version 1.1.1.", null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getJavaTask(variantData: BaseVariantData<out BaseVariantOutputData>): AbstractCompile? =
|
||||||
|
AndroidGradleWrapper.getJavaTask(variantData)
|
||||||
|
|
||||||
|
|
||||||
|
override fun addJavaSourceDirectoryToVariantModel(variantData: BaseVariantData<out BaseVariantOutputData>,
|
||||||
|
javaSourceDirectory: File) =
|
||||||
|
variantData.addJavaSourceFoldersToModel(javaSourceDirectory)
|
||||||
|
|
||||||
|
override fun configureMultiProjectIc(project: Project, variantData: BaseVariantData<out BaseVariantOutputData>, javaTask: AbstractCompile, kotlinTask: KotlinCompile, kotlinAfterJavaTask: KotlinCompile?) {
|
||||||
|
if ((kotlinAfterJavaTask ?: kotlinTask).incremental) {
|
||||||
|
val artifactFile = project.tryGetSingleArtifact(variantData)
|
||||||
|
val artifactDifferenceRegistryProvider = ArtifactDifferenceRegistryProviderAndroidWrapper(
|
||||||
|
artifactDifferenceRegistryProvider,
|
||||||
|
{ AndroidGradleWrapper.getJarToAarMapping(variantData) }
|
||||||
|
)
|
||||||
|
configureMultiProjectIncrementalCompilation(project, kotlinTask, javaTask, kotlinAfterJavaTask,
|
||||||
|
artifactDifferenceRegistryProvider, artifactFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTestedVariantData(variantData: BaseVariantData<*>): BaseVariantData<*>? =
|
||||||
|
((variantData as? TestVariantData)?.testedVariantData as? BaseVariantData<*>)
|
||||||
|
|
||||||
|
private fun Project.tryGetSingleArtifact(variantData: BaseVariantData<*>): File? {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
private val BaseVariantData<*>.sourceProviders: List<SourceProvider>
|
||||||
|
get() = variantConfiguration.sortedSourceProviders
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user