[Build] Fix configuration cache issues (part 5)

Make Project.configureFormInstrumentation and Task.useAndroidConfiguration extensions, :dependencies:android-sdk unzip tasks compatible with configuration cache

Relates to #KT-44611
This commit is contained in:
Alexander Likhachev
2021-02-16 15:48:13 +03:00
parent da6544ae3c
commit 46b056c929
4 changed files with 68 additions and 55 deletions
+40 -40
View File
@@ -31,46 +31,6 @@ import java.io.File
import javax.inject.Inject
fun Project.configureFormInstrumentation() {
plugins.matching { it::class.java.canonicalName.startsWith("org.jetbrains.kotlin.gradle.plugin") }.all {
// When we change the output classes directory, Gradle will automatically configure
// the test compile tasks to use the instrumented classes. Normally this is fine,
// however, it causes problems for Kotlin projects:
// The "internal" modifier can be used to restrict access to the same module.
// To make it possible to use internal methods from the main source set in test classes,
// the Kotlin Gradle plugin adds the original output directory of the Java task
// as "friendly directory" which makes it possible to access internal members
// of the main module. Also this directory should be available on classpath during compilation
// This fails when we change the classes dir. The easiest fix is to prepend the
// classes from the "friendly directory" to the compile classpath.
val testCompile = tasks.findByName("compileTestKotlin") as AbstractCompile?
testCompile?.doFirst {
val originalClassesDirs = files((mainSourceSet as ExtensionAware).extra.get("classesDirsCopy"))
testCompile.classpath = (testCompile.classpath
- mainSourceSet.output.classesDirs
+ originalClassesDirs)
// Since Kotlin 1.3.60, the friend paths available to the test compile task are calculated as the main source set's
// output.classesDirs. Since the classesDirs are excluded from the classpath (replaced by the originalClassesDirs),
// in order to be able to access the internals of 'main', tests need to receive the original classes dirs as a
// -Xfriend-paths compiler argument as well.
fun addFreeCompilerArgs(kotlinCompileTask: AbstractCompile, vararg args: String) {
val getKotlinOptions = kotlinCompileTask::class.java.getMethod("getKotlinOptions")
val kotlinOptions = getKotlinOptions(kotlinCompileTask)
val getFreeCompilerArgs = kotlinOptions::class.java.getMethod("getFreeCompilerArgs")
val freeCompilerArgs = getFreeCompilerArgs(kotlinOptions) as List<*>
val setFreeCompilerArgs = kotlinOptions::class.java.getMethod("setFreeCompilerArgs", List::class.java)
setFreeCompilerArgs(kotlinOptions, freeCompilerArgs + args)
}
addFreeCompilerArgs(testCompile, "-Xfriend-paths=" + originalClassesDirs.joinToString(",") { it.absolutePath })
}
}
val instrumentationClasspathCfg = configurations.create("instrumentationClasspath")
dependencies {
@@ -101,6 +61,46 @@ fun Project.configureFormInstrumentation() {
// Ensure that our task is invoked when the source set is built
sourceSetParam.compiledBy(instrumentTask)
}
plugins.matching { it::class.java.canonicalName.startsWith("org.jetbrains.kotlin.gradle.plugin") }.configureEach {
// When we change the output classes directory, Gradle will automatically configure
// the test compile tasks to use the instrumented classes. Normally this is fine,
// however, it causes problems for Kotlin projects:
// The "internal" modifier can be used to restrict access to the same module.
// To make it possible to use internal methods from the main source set in test classes,
// the Kotlin Gradle plugin adds the original output directory of the Java task
// as "friendly directory" which makes it possible to access internal members
// of the main module. Also this directory should be available on classpath during compilation
// This fails when we change the classes dir. The easiest fix is to prepend the
// classes from the "friendly directory" to the compile classpath.
if (!tasks.names.contains("compileTestKotlin")) return@configureEach
tasks.named<AbstractCompile>("compileTestKotlin").configure {
val originalClassesDirs = project.files((project.mainSourceSet as ExtensionAware).extra.get("classesDirsCopy"))
classpath = (classpath
- project.mainSourceSet.output.classesDirs
+ originalClassesDirs)
// Since Kotlin 1.3.60, the friend paths available to the test compile task are calculated as the main source set's
// output.classesDirs. Since the classesDirs are excluded from the classpath (replaced by the originalClassesDirs),
// in order to be able to access the internals of 'main', tests need to receive the original classes dirs as a
// -Xfriend-paths compiler argument as well.
fun addFreeCompilerArgs(kotlinCompileTask: AbstractCompile, vararg args: String) {
val getKotlinOptions = kotlinCompileTask::class.java.getMethod("getKotlinOptions")
val kotlinOptions = getKotlinOptions(kotlinCompileTask)
val getFreeCompilerArgs = kotlinOptions::class.java.getMethod("getFreeCompilerArgs")
val freeCompilerArgs = getFreeCompilerArgs(kotlinOptions) as List<*>
val setFreeCompilerArgs = kotlinOptions::class.java.getMethod("setFreeCompilerArgs", List::class.java)
setFreeCompilerArgs(kotlinOptions, freeCompilerArgs + args)
}
addFreeCompilerArgs(this, "-Xfriend-paths=" + originalClassesDirs.joinToString(",") { it.absolutePath })
}
}
}
}
+13 -5
View File
@@ -9,6 +9,7 @@
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.internal.tasks.testing.filter.DefaultTestFilter
import org.gradle.api.tasks.TaskProvider
@@ -243,18 +244,25 @@ private fun Task.useAndroidConfiguration(systemPropertyName: String, configName:
val configuration = with(project) {
configurations.getOrCreate(configName)
.also {
dependencies.add(
configName,
dependencies.project(":dependencies:android-sdk", configuration = configName)
)
if (it.allDependencies.matching { dep ->
dep is ProjectDependency &&
dep.targetConfiguration == configName &&
dep.dependencyProject.path == ":dependencies:android-sdk"
}.count() == 0) {
dependencies.add(
configName,
dependencies.project(":dependencies:android-sdk", configuration = configName)
)
}
}
}
dependsOn(configuration)
if (this is Test) {
val androidFilePath = configuration.singleFile.canonicalPath
doFirst {
systemProperty(systemPropertyName, configuration.singleFile.canonicalPath)
systemProperty(systemPropertyName, androidFilePath)
}
}
}