[Build] Fix configuration cache issues (part 7)

* Read system property "disable.verification.tasks" using Gradle provider
* Fix compileTestKotlin tasks with instrumented classes
* Read Gradle property "kotlin.test.maxParallelForks" using Gradle provider
* Change :idea:performanceTests jackson version to fixed ones
Relates to #KT-44611
This commit is contained in:
Alexander Likhachev
2021-02-25 15:21:32 +03:00
parent 6bd44df861
commit 57f5939f5e
4 changed files with 73 additions and 69 deletions
+2 -1
View File
@@ -1208,7 +1208,8 @@ val Jar.outputFile: File
val Project.sourceSetsOrNull: SourceSetContainer? val Project.sourceSetsOrNull: SourceSetContainer?
get() = convention.findPlugin(JavaPluginConvention::class.java)?.sourceSets get() = convention.findPlugin(JavaPluginConvention::class.java)?.sourceSets
val disableVerificationTasks = System.getProperty("disable.verification.tasks") == "true" val disableVerificationTasks = providers.systemProperty("disable.verification.tasks")
.forUseAtConfigurationTime().orNull?.toBoolean() ?: false
if (disableVerificationTasks) { if (disableVerificationTasks) {
gradle.taskGraph.whenReady { gradle.taskGraph.whenReady {
allTasks.forEach { allTasks.forEach {
+67 -64
View File
@@ -22,6 +22,7 @@ import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.file.FileSystemOperations import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.internal.ConventionTask import org.gradle.api.internal.ConventionTask
import org.gradle.api.plugins.ExtensionAware import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
@@ -31,6 +32,51 @@ import java.io.File
import javax.inject.Inject import javax.inject.Inject
fun Project.configureFormInstrumentation() { fun Project.configureFormInstrumentation() {
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") {
val objects = project.objects
val classesDirs = project.mainSourceSet.output.classesDirs
val classesDirsCopy = project.provider { (mainSourceSet as ExtensionAware).extra.get("classesDirsCopy") }
doFirst {
val originalClassesDirs = objects.fileCollection().from(classesDirsCopy)
classpath = (classpath
- 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 as AbstractCompile, "-Xfriend-paths=" + originalClassesDirs.joinToString(",") { it.absolutePath })
}
}
}
val instrumentationClasspathCfg = configurations.create("instrumentationClasspath") val instrumentationClasspathCfg = configurations.create("instrumentationClasspath")
dependencies { dependencies {
@@ -51,56 +97,16 @@ fun Project.configureFormInstrumentation() {
val instrumentTask = val instrumentTask =
project.tasks.register(sourceSetParam.getTaskName("instrument", "classes"), IntelliJInstrumentCodeTask::class.java) { project.tasks.register(sourceSetParam.getTaskName("instrument", "classes"), IntelliJInstrumentCodeTask::class.java) {
dependsOn(sourceSetParam.classesTaskName) dependsOn(sourceSetParam.classesTaskName)
sourceSet = sourceSetParam compileClasspath.from(sourceSetParam.compileClasspath)
sourceDirs.from(project.files({ sourceSetParam.allSource.srcDirs.filter { !sourceSetParam.resources.contains(it) && it.exists() } }))
instrumentationClasspathConfiguration = instrumentationClasspathCfg instrumentationClasspathConfiguration = instrumentationClasspathCfg
originalClassesDirs = classesDirsCopy originalClassesDirs.from(classesDirsCopy)
output = instrumentedClassesDir output.set(instrumentedClassesDir)
outputs.dir(instrumentedClassesDir)
} }
// Ensure that our task is invoked when the source set is built // Ensure that our task is invoked when the source set is built
sourceSetParam.compiledBy(instrumentTask) 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 })
}
}
} }
} }
@@ -120,21 +126,17 @@ abstract class IntelliJInstrumentCodeTask : ConventionTask() {
instrumentationClasspathConfiguration.asPath instrumentationClasspathConfiguration.asPath
} }
@InputFiles @get:InputFiles
@PathSensitive(PathSensitivity.RELATIVE) @get:PathSensitive(PathSensitivity.RELATIVE)
@SkipWhenEmpty @get:SkipWhenEmpty
lateinit var originalClassesDirs: FileCollection abstract val originalClassesDirs: ConfigurableFileCollection
@get:Input @get:Input
var instrumentNotNull: Boolean = false var instrumentNotNull: Boolean = false
@Transient @get:InputFiles
@Internal @get:Classpath
lateinit var sourceSet: SourceSet abstract val compileClasspath: ConfigurableFileCollection
private val compileClasspath by lazy {
sourceSet.compileClasspath
}
// Instrumentation needs to have access to sources of forms for inclusion // Instrumentation needs to have access to sources of forms for inclusion
private val depSourceDirectorySets by lazy { private val depSourceDirectorySets by lazy {
@@ -144,12 +146,10 @@ abstract class IntelliJInstrumentCodeTask : ConventionTask() {
@get:InputFiles @get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE) @get:PathSensitive(PathSensitivity.RELATIVE)
val sourceDirs: FileCollection by lazy { abstract val sourceDirs: ConfigurableFileCollection
project.files(sourceSet.allSource.srcDirs.filter { !sourceSet.resources.contains(it) && it.exists() })
}
@get:OutputDirectory @get:OutputDirectory
lateinit var output: File abstract val output: RegularFileProperty
@get:Inject @get:Inject
abstract val fs: FileSystemOperations abstract val fs: FileSystemOperations
@@ -157,11 +157,13 @@ abstract class IntelliJInstrumentCodeTask : ConventionTask() {
@TaskAction @TaskAction
fun instrumentClasses() { fun instrumentClasses() {
logger.info( logger.info(
"input files are: ${originalClassesDirs.joinToString( "input files are: ${
"; ", originalClassesDirs.joinToString(
transform = { "'${it.name}'${if (it.exists()) "" else " (does not exists)"}" })}" "; ",
transform = { "'${it.name}'${if (it.exists()) "" else " (does not exists)"}" })
}"
) )
output.deleteRecursively() output.asFile.get().deleteRecursively()
copyOriginalClasses() copyOriginalClasses()
val classpath = instrumentationClasspath val classpath = instrumentationClasspath
@@ -203,9 +205,10 @@ abstract class IntelliJInstrumentCodeTask : ConventionTask() {
private fun instrumentCode(srcDirs: FileCollection, instrumentNotNull: Boolean) { private fun instrumentCode(srcDirs: FileCollection, instrumentNotNull: Boolean) {
val headlessOldValue = System.setProperty("java.awt.headless", "true") val headlessOldValue = System.setProperty("java.awt.headless", "true")
val output = output.get().asFile
val instrumentationClasspath = val instrumentationClasspath =
depSourceDirectorySets.fold(compileClasspath) { acc, v -> acc + v }.asPath.also { depSourceDirectorySets.fold(compileClasspath as FileCollection) { acc, v -> acc + v }.asPath.also {
logger.info("Using following dependency source dirs: $it") logger.info("Using following dependency source dirs: $it")
} }
+2 -2
View File
@@ -214,8 +214,8 @@ fun Project.projectTest(
if (parallel && !jUnit5Enabled) { if (parallel && !jUnit5Enabled) {
maxParallelForks = maxParallelForks =
project.findProperty("kotlin.test.maxParallelForks")?.toString()?.toInt() project.providers.gradleProperty("kotlin.test.maxParallelForks").forUseAtConfigurationTime().orNull?.toInt()
?: (Runtime.getRuntime().availableProcessors() / if (kotlinBuildProperties.isTeamcityBuild) 2 else 4).coerceAtLeast(1) ?: (Runtime.getRuntime().availableProcessors() / if (project.kotlinBuildProperties.isTeamcityBuild) 2 else 4).coerceAtLeast(1)
} }
}.apply { configure(body) } }.apply { configure(body) }
} }
+2 -2
View File
@@ -33,8 +33,8 @@ dependencies {
testImplementation(projectTests(":idea")) testImplementation(projectTests(":idea"))
testImplementation(project(":idea:idea-gradle")) { isTransitive = false } testImplementation(project(":idea:idea-gradle")) { isTransitive = false }
testImplementation(commonDep("junit:junit")) testImplementation(commonDep("junit:junit"))
testImplementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.11.+") testImplementation("com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.11.4")
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.11.+") testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.11.4")
testImplementation("khttp:khttp:1.0.0") testImplementation("khttp:khttp:1.0.0")
testCompileOnly(intellijPluginDep("java")) testCompileOnly(intellijPluginDep("java"))