[Build] Fix configuration cache issues (part 3)

* Make IntelliJInstrumentCodeTask compatible with configuration cache
* Make CoreXmlShadingTransformer compatible with configuration cache
* Make :kotlin-reflect:relocateCoreSources compatible with configuration cache
* Copy some properties to not capture it's owning object into lambda to support configuration cache
Relates to #KT-44611
This commit is contained in:
Alexander Likhachev
2021-02-14 10:39:26 +03:00
parent 0e4e90dc13
commit 5f10c98a38
5 changed files with 42 additions and 15 deletions
+18 -11
View File
@@ -21,12 +21,14 @@ import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.internal.ConventionTask
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.tasks.*
import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.kotlin.dsl.*
import java.io.File
import javax.inject.Inject
fun Project.configureFormInstrumentation() {
plugins.matching { it::class.java.canonicalName.startsWith("org.jetbrains.kotlin.gradle.plugin") }.all {
@@ -76,7 +78,7 @@ fun Project.configureFormInstrumentation() {
}
afterEvaluate {
sourceSets.all { sourceSetParam ->
sourceSets.forEach { sourceSetParam ->
// This copy will ignore filters, but they are unlikely to be used.
val classesDirs = (sourceSetParam.output.classesDirs as ConfigurableFileCollection).from as Collection<Any>
@@ -88,7 +90,7 @@ fun Project.configureFormInstrumentation() {
(sourceSetParam.output.classesDirs as ConfigurableFileCollection).setFrom(instrumentedClassesDir)
val instrumentTask =
project.tasks.register(sourceSetParam.getTaskName("instrument", "classes"), IntelliJInstrumentCodeTask::class.java) {
dependsOn(sourceSetParam.classesTaskName).onlyIf { !classesDirsCopy.isEmpty }
dependsOn(sourceSetParam.classesTaskName)
sourceSet = sourceSetParam
instrumentationClasspathConfiguration = instrumentationClasspathCfg
originalClassesDirs = classesDirsCopy
@@ -98,14 +100,12 @@ fun Project.configureFormInstrumentation() {
// Ensure that our task is invoked when the source set is built
sourceSetParam.compiledBy(instrumentTask)
@Suppress("UNUSED_EXPRESSION")
true
}
}
}
@CacheableTask
open class IntelliJInstrumentCodeTask : ConventionTask() {
abstract class IntelliJInstrumentCodeTask : ConventionTask() {
companion object {
private const val FILTER_ANNOTATION_REGEXP_CLASS = "com.intellij.ant.ClassFilterAnnotationRegexp"
private const val LOADER_REF = "java2.loader"
@@ -122,7 +122,8 @@ open class IntelliJInstrumentCodeTask : ConventionTask() {
@InputFiles
@PathSensitive(PathSensitivity.RELATIVE)
var originalClassesDirs: FileCollection? = null
@SkipWhenEmpty
lateinit var originalClassesDirs: FileCollection
@get:Input
var instrumentNotNull: Boolean = false
@@ -135,6 +136,12 @@ open class IntelliJInstrumentCodeTask : ConventionTask() {
sourceSet.compileClasspath
}
// Instrumentation needs to have access to sources of forms for inclusion
private val depSourceDirectorySets by lazy {
project.configurations["compile"].dependencies.withType(ProjectDependency::class.java)
.map { p -> p.dependencyProject.mainSourceSet.allSource.sourceDirectories }
}
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
val sourceDirs: FileCollection by lazy {
@@ -144,10 +151,13 @@ open class IntelliJInstrumentCodeTask : ConventionTask() {
@get:OutputDirectory
lateinit var output: File
@get:Inject
abstract val fs: FileSystemOperations
@TaskAction
fun instrumentClasses() {
logger.info(
"input files are: ${originalClassesDirs?.joinToString(
"input files are: ${originalClassesDirs.joinToString(
"; ",
transform = { "'${it.name}'${if (it.exists()) "" else " (does not exists)"}" })}"
)
@@ -174,7 +184,7 @@ open class IntelliJInstrumentCodeTask : ConventionTask() {
}
private fun copyOriginalClasses() {
project.copy {
fs.copy {
from(originalClassesDirs)
into(output)
}
@@ -194,9 +204,6 @@ open class IntelliJInstrumentCodeTask : ConventionTask() {
private fun instrumentCode(srcDirs: FileCollection, instrumentNotNull: Boolean) {
val headlessOldValue = System.setProperty("java.awt.headless", "true")
// Instrumentation needs to have access to sources of forms for inclusion
val depSourceDirectorySets = project.configurations["compile"].dependencies.withType(ProjectDependency::class.java)
.map { p -> p.dependencyProject.mainSourceSet.allSource.sourceDirectories }
val instrumentationClasspath =
depSourceDirectorySets.fold(compileClasspath) { acc, v -> acc + v }.asPath.also {
logger.info("Using following dependency source dirs: $it")
+6 -1
View File
@@ -4,6 +4,7 @@ import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import kotlinx.metadata.jvm.KmModuleVisitor
import kotlinx.metadata.jvm.KotlinModuleMetadata
import org.gradle.kotlin.dsl.support.serviceOf
import shadow.org.apache.tools.zip.ZipEntry
import shadow.org.apache.tools.zip.ZipOutputStream
@@ -157,8 +158,12 @@ val proguard by task<CacheableProguardTask> {
}
val relocateCoreSources by task<Copy> {
val relocatedCoreSrc = relocatedCoreSrc
val fs = serviceOf<FileSystemOperations>()
doFirst {
delete(relocatedCoreSrc)
fs.delete {
delete(relocatedCoreSrc)
}
}
from("$core/descriptors/src")
+3
View File
@@ -76,6 +76,9 @@ val jsMainSources by task<Sync> {
into("$buildDir/jsMainSources")
val unimplementedNativeBuiltIns = unimplementedNativeBuiltIns
val buildDir = buildDir
val builtInsHeader = builtInsHeader
doLast {
unimplementedNativeBuiltIns.forEach { path ->
val file = File("$buildDir/jsMainSources/$path")
+12 -3
View File
@@ -50,25 +50,34 @@ class CoreXmlShadingTransformer : Transformer {
private const val XML_NAME = "META-INF/extensions/core.xml"
}
private val content = StringBuilder()
@kotlin.jvm.Transient
private var content: StringBuilder? = StringBuilder()
private fun ensureStringBuilderExist() {
if (content == null) {
content = StringBuilder()
}
}
override fun canTransformResource(element: FileTreeElement): Boolean {
return (element.name == XML_NAME)
}
override fun transform(context: TransformerContext) {
ensureStringBuilderExist()
val text = context.`is`.bufferedReader().lines()
.map { it.replace("com.intellij.psi", "org.jetbrains.kotlin.com.intellij.psi") }
.collect(Collectors.joining("\n"))
content.appendln(text)
content!!.appendln(text)
context.`is`.close()
}
override fun hasTransformedResource(): Boolean {
return content.isNotEmpty()
return content?.isNotEmpty() ?: false
}
override fun modifyOutputStream(outputStream: ZipOutputStream, preserveFileTimestamps: Boolean) {
if (content == null) return
val entry = ZipEntry(XML_NAME)
outputStream.putNextEntry(entry)
outputStream.write(content.toString().toByteArray())
@@ -13,6 +13,9 @@ val markdownVersion = findProperty("versions.markdown").toString()
val writeVersions by tasks.registering {
val versionFile = File(versionFilePath)
val ideaVersion = ideaVersion
val markdownVersion = markdownVersion
inputs.property("ideaVersion", ideaVersion)
inputs.property("markdownVersion", markdownVersion)