KT-41295: Friend paths and compiler options compatible with conf caching
This change fixes serialization of friend paths and it uses a file collection to record all friend paths. Also, when computing the tested classpath for android projects, we now avoid resolving the file collection until necessary. Fixes: KT-41295 Test: ConfigurationCacheForAndroidIT
This commit is contained in:
committed by
nataliya.valtman
parent
be916e556a
commit
162dc3aa0c
+6
@@ -41,6 +41,12 @@ class ConfigurationCacheForAndroidIT : AbstractConfigurationCacheIT() {
|
|||||||
testConfigurationCacheOf(":Lib:compileFlavor1DebugKotlin", ":Android:compileFlavor1DebugKotlin")
|
testConfigurationCacheOf(":Lib:compileFlavor1DebugKotlin", ":Android:compileFlavor1DebugKotlin")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testKotlinAndroidProjectTests() = with(Project("AndroidIncrementalMultiModule")) {
|
||||||
|
applyAndroid40Alpha4KotlinVersionWorkaround()
|
||||||
|
testConfigurationCacheOf(":app:compileDebugAndroidTestKotlin", ":app:compileDebugUnitTestKotlin")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Android Gradle plugin 4.0-alpha4 depends on the EAP versions of some o.j.k modules.
|
* Android Gradle plugin 4.0-alpha4 depends on the EAP versions of some o.j.k modules.
|
||||||
* Force the current Kotlin version, so the EAP versions are not queried from the
|
* Force the current Kotlin version, so the EAP versions are not queried from the
|
||||||
|
|||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
import com.example.AppDummy
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
println(AppDummy())
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
import com.example.AppDummy
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2020 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
println(AppDummy())
|
||||||
|
}
|
||||||
+1
-1
@@ -99,7 +99,7 @@ internal open class KotlinJvmCompilerArgumentsContributor(
|
|||||||
args.moduleName = moduleName
|
args.moduleName = moduleName
|
||||||
logger.kotlinDebug { "args.moduleName = ${args.moduleName}" }
|
logger.kotlinDebug { "args.moduleName = ${args.moduleName}" }
|
||||||
|
|
||||||
args.friendPaths = friendPaths
|
args.friendPaths = friendPaths.files.map { it.absolutePath }.toTypedArray()
|
||||||
logger.kotlinDebug { "args.friendPaths = ${args.friendPaths?.joinToString() ?: "[]"}" }
|
logger.kotlinDebug { "args.friendPaths = ${args.friendPaths?.joinToString() ?: "[]"}" }
|
||||||
|
|
||||||
if (DefaultsOnly in flags) return
|
if (DefaultsOnly in flags) return
|
||||||
|
|||||||
+53
-13
@@ -11,9 +11,11 @@ import com.android.build.gradle.*
|
|||||||
import com.android.build.gradle.api.*
|
import com.android.build.gradle.api.*
|
||||||
import com.android.build.gradle.tasks.MergeResources
|
import com.android.build.gradle.tasks.MergeResources
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.ArtifactCollection
|
||||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||||
import org.gradle.api.attributes.Attribute
|
import org.gradle.api.attributes.Attribute
|
||||||
import org.gradle.api.file.FileCollection
|
import org.gradle.api.file.FileCollection
|
||||||
|
import org.gradle.api.specs.Spec
|
||||||
import org.gradle.api.tasks.PathSensitivity
|
import org.gradle.api.tasks.PathSensitivity
|
||||||
import org.gradle.api.tasks.TaskProvider
|
import org.gradle.api.tasks.TaskProvider
|
||||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||||
@@ -26,6 +28,9 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|||||||
import org.jetbrains.kotlin.gradle.tasks.thisTaskProvider
|
import org.jetbrains.kotlin.gradle.tasks.thisTaskProvider
|
||||||
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
|
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.io.ObjectInputStream
|
||||||
|
import java.io.ObjectOutputStream
|
||||||
|
import java.io.Serializable
|
||||||
import java.util.concurrent.Callable
|
import java.util.concurrent.Callable
|
||||||
|
|
||||||
class Android25ProjectHandler(
|
class Android25ProjectHandler(
|
||||||
@@ -65,20 +70,16 @@ class Android25ProjectHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the classpath entries that come from the tested variant and register them as the friend paths, lazily
|
// Find the classpath entries that come from the tested variant and register them as the friend paths, lazily
|
||||||
|
val originalArtifactCollection = variantData.getCompileClasspathArtifacts(preJavaClasspathKey)
|
||||||
|
val testedVariantDataIsNotNull = getTestedVariantData(variantData) != null
|
||||||
|
val projectPath = project.path
|
||||||
compilation.testedVariantArtifacts.set(
|
compilation.testedVariantArtifacts.set(
|
||||||
project.files(
|
originalArtifactCollection.artifactFiles.filter(
|
||||||
project.provider {
|
AndroidTestedVariantArtifactsFilter(
|
||||||
variantData.getCompileClasspathArtifacts(preJavaClasspathKey)
|
originalArtifactCollection,
|
||||||
.filter {
|
testedVariantDataIsNotNull,
|
||||||
it.id.componentIdentifier is TestedComponentIdentifier ||
|
projectPath
|
||||||
// If tests depend on the main classes transitively, through a test dependency on another module which
|
)
|
||||||
// depends on this module, then there's no artifact with a TestedComponentIdentifier, so consider the artifact of the
|
|
||||||
// current module a friend path, too:
|
|
||||||
getTestedVariantData(variantData) != null &&
|
|
||||||
(it.id.componentIdentifier as? ProjectComponentIdentifier)?.projectPath == project.path
|
|
||||||
}
|
|
||||||
.map { it.file }
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -214,3 +215,42 @@ private fun MergeResources.computeResourceSetList0(): List<File>? {
|
|||||||
computeResourceSetListMethod.isAccessible = oldIsAccessible
|
computeResourceSetListMethod.isAccessible = oldIsAccessible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Filter for the AGP test variant classpath artifacts. */
|
||||||
|
class AndroidTestedVariantArtifactsFilter(
|
||||||
|
private val artifactCollection: ArtifactCollection,
|
||||||
|
private val testedVariantDataIsNotNull: Boolean,
|
||||||
|
private val projectPath: String
|
||||||
|
) : Serializable, Spec<File> {
|
||||||
|
|
||||||
|
/** Make transient as it should be derived from the [artifactCollection] property which may change in configuration cached runs. */
|
||||||
|
@Transient
|
||||||
|
private var filteredFiles = initFilteredFiles()
|
||||||
|
|
||||||
|
private fun initFilteredFiles(): Lazy<Set<File>> {
|
||||||
|
return lazy {
|
||||||
|
artifactCollection.filter {
|
||||||
|
it.id.componentIdentifier is TestedComponentIdentifier ||
|
||||||
|
// If tests depend on the main classes transitively, through a test dependency on another module which
|
||||||
|
// depends on this module, then there's no artifact with a TestedComponentIdentifier, so consider the artifact of the
|
||||||
|
// current module a friend path, too:
|
||||||
|
testedVariantDataIsNotNull &&
|
||||||
|
(it.id.componentIdentifier as? ProjectComponentIdentifier)?.projectPath == projectPath
|
||||||
|
}
|
||||||
|
.mapTo(mutableSetOf()) { it.file }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeObject(objectOutputStream: ObjectOutputStream) {
|
||||||
|
objectOutputStream.defaultWriteObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readObject(objectInputStream: ObjectInputStream) {
|
||||||
|
objectInputStream.defaultReadObject()
|
||||||
|
filteredFiles = initFilteredFiles()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSatisfiedBy(element: File): Boolean {
|
||||||
|
return element in filteredFiles.value
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -70,7 +70,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
|
|||||||
classpath = classpathList.joinToString(File.pathSeparator)
|
classpath = classpathList.joinToString(File.pathSeparator)
|
||||||
destination = destinationDir.canonicalPath
|
destination = destinationDir.canonicalPath
|
||||||
|
|
||||||
friendPaths = this@KotlinCompileCommon.friendPaths
|
friendPaths = this@KotlinCompileCommon.friendPaths.files.map { it.absolutePath }.toTypedArray()
|
||||||
refinesPaths = refinesMetadataPaths.map { it.absolutePath }.toTypedArray()
|
refinesPaths = refinesMetadataPaths.map { it.absolutePath }.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-13
@@ -288,15 +288,17 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@get:Internal // takes part in the compiler arguments
|
@get:Internal // takes part in the compiler arguments
|
||||||
val friendPaths: Array<String> by project.provider {
|
val friendPaths: FileCollection = project.files(
|
||||||
taskData.compilation.run {
|
project.provider {
|
||||||
if (this !is AbstractKotlinCompilation<*>) return@run emptyArray<String>()
|
taskData.compilation.run {
|
||||||
associateWithTransitiveClosure
|
if (this !is AbstractKotlinCompilation<*>) return@run project.files()
|
||||||
.flatMap { it.output.classesDirs }
|
mutableListOf<FileCollection>().also { allCollections ->
|
||||||
.plus(friendArtifacts)
|
associateWithTransitiveClosure.forEach { allCollections.add(it.output.classesDirs) }
|
||||||
.map { it.absolutePath }.toTypedArray()
|
allCollections.add(friendArtifacts)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
|
|
||||||
private val kotlinLogger by lazy { GradleKotlinLogger(logger) }
|
private val kotlinLogger by lazy { GradleKotlinLogger(logger) }
|
||||||
|
|
||||||
@@ -415,7 +417,7 @@ class KotlinJvmCompilerArgumentsProvider
|
|||||||
(taskProvider: KotlinCompile) : KotlinCompileArgumentsProvider<KotlinCompile>(taskProvider) {
|
(taskProvider: KotlinCompile) : KotlinCompileArgumentsProvider<KotlinCompile>(taskProvider) {
|
||||||
|
|
||||||
val moduleName: String
|
val moduleName: String
|
||||||
val friendPaths: Array<String>
|
val friendPaths: FileCollection
|
||||||
val compileClasspath: Iterable<File>
|
val compileClasspath: Iterable<File>
|
||||||
val destinationDir: File
|
val destinationDir: File
|
||||||
internal val kotlinOptions: List<KotlinJvmOptionsImpl?>
|
internal val kotlinOptions: List<KotlinJvmOptionsImpl?>
|
||||||
@@ -643,10 +645,9 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
|
|||||||
internal val friendDependencies: List<String>
|
internal val friendDependencies: List<String>
|
||||||
get() {
|
get() {
|
||||||
val filter = libraryFilter
|
val filter = libraryFilter
|
||||||
return friendPaths.filter {
|
return friendPaths.files.filter {
|
||||||
val file = File(it)
|
it.exists() && filter(it)
|
||||||
file.exists() && filter(file)
|
}.map { it.absolutePath }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
|
|||||||
Reference in New Issue
Block a user