Ensure compilation task depends on friend artifact producer task.

Without it Gradle 7.0 tasks dependency validation will fail.

Fix JS tasks are not cacheable due to friends inputs change.

^KT-44949 In Progress
This commit is contained in:
Yahor Berdnikau
2021-02-16 15:29:03 +01:00
parent 0340a89045
commit db2d6c7e0a
4 changed files with 61 additions and 17 deletions
@@ -6,9 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.mpp
import groovy.lang.Closure
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.*
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.file.FileCollection
@@ -193,20 +191,37 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override fun toString(): String = "compilation '$compilationName' ($target)"
internal val friendArtifactsTask: TaskProvider<AbstractArchiveTask>? by lazy {
if (associateWithTransitiveClosure.any { it.isMain() }) {
val archiveTasks = target.project.tasks.withType(AbstractArchiveTask::class.java)
if (!archiveTasks.isEmpty()) {
try {
archiveTasks.named(target.artifactsTaskName)
} catch (e: UnknownTaskException) {
// Native tasks does not extend AbstractArchiveTask
null
}
} else {
null
}
} else {
null
}
}
/**
* If a compilation is aware of its associate compilations' outputs being added to the classpath in a transformed or packaged way,
* it should point to those friend artifact files via this property.
*/
internal open val friendArtifacts: FileCollection
get() = with(target.project) {
if (associateWithTransitiveClosure.any { it.isMain() }) {
val friendArtifactsTaskProvider = friendArtifactsTask
if (friendArtifactsTaskProvider != null) {
// In case the main artifact is transitively added to the test classpath via a test dependency on another module
// that depends on this module's production part, include the main artifact in the friend artifacts, lazily:
files(
provider {
listOfNotNull(
tasks.withType(AbstractArchiveTask::class.java).findByName(target.artifactsTaskName)?.archivePathCompatible
)
Callable {
friendArtifactsTaskProvider.get().archivePathCompatible
}
)
} else files()
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.file.FileCollection
import org.gradle.api.file.FileTree
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.*
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
@@ -19,9 +20,12 @@ import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.PRODUCTION
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.utils.newFileProperty
import java.io.File
import javax.inject.Inject
@CacheableTask
open class KotlinJsIrLink : Kotlin2JsCompile() {
open class KotlinJsIrLink @Inject constructor(
objectFactory: ObjectFactory
): Kotlin2JsCompile(objectFactory) {
// Link tasks are not affected by compiler plugin
override val pluginClasspath: FileCollection = project.objects.fileCollection()
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.CacheableTask
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers
@@ -15,8 +16,9 @@ import javax.inject.Inject
internal open class KotlinJsIrLinkWithWorkers
@Inject
constructor(
objectFactory: ObjectFactory,
private val workerExecutor: WorkerExecutor
) : KotlinJsIrLink() {
) : KotlinJsIrLink(objectFactory) {
override fun compilerRunner() =
GradleCompilerRunnerWithWorkers(
GradleCompileTaskProvider(this),
@@ -10,6 +10,7 @@ import org.gradle.api.Task
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.api.logging.Logger
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.gradle.api.tasks.compile.AbstractCompile
@@ -51,6 +52,7 @@ import org.jetbrains.kotlin.incremental.ChangedFiles
import org.jetbrains.kotlin.library.impl.isKotlinLibrary
import org.jetbrains.kotlin.utils.JsLibraryUtils
import java.io.File
import java.util.zip.ZipFile
import javax.inject.Inject
const val KOTLIN_BUILD_DIR_NAME = "kotlin"
@@ -304,6 +306,15 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
taskData.compilation.moduleName
}
init {
if (taskData.compilation is AbstractKotlinCompilation<*> &&
(taskData.compilation as AbstractKotlinCompilation<*>).friendArtifactsTask != null) {
this@AbstractKotlinCompile.dependsOn(
(taskData.compilation as AbstractKotlinCompilation<*>).friendArtifactsTask
)
}
}
@get:Internal // takes part in the compiler arguments
val friendPaths: FileCollection = project.files(
project.provider {
@@ -632,8 +643,9 @@ internal open class KotlinCompileWithWorkers @Inject constructor(
@CacheableTask
internal open class Kotlin2JsCompileWithWorkers @Inject constructor(
objectFactory: ObjectFactory,
private val workerExecutor: WorkerExecutor
) : Kotlin2JsCompile() {
) : Kotlin2JsCompile(objectFactory) {
override fun compilerRunner() =
GradleCompilerRunnerWithWorkers(
@@ -654,7 +666,9 @@ internal open class KotlinCompileCommonWithWorkers @Inject constructor(
}
@CacheableTask
open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), KotlinJsCompile {
open class Kotlin2JsCompile @Inject constructor(
objectFactory: ObjectFactory
) : AbstractKotlinCompile<K2JSCompilerArguments>(), KotlinJsCompile {
init {
incremental = true
@@ -718,6 +732,19 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
override fun getSourceRoots() = SourceRoots.KotlinOnly.create(getSource(), sourceFilesExtensions)
@get:InputFiles
@get:Optional
@get:PathSensitive(PathSensitivity.RELATIVE)
internal val friendDependencies: FileCollection = objectFactory
.fileCollection()
.from(friendPaths)
.filter {
// .jar files are not required for js compilation as friend modules
// and, because of `@InputFiles` and different normalization strategy from `@Classpath`,
// they produce build cache misses
it.exists() && !it.name.endsWith(".jar") && libraryFilter(it)
}
@Suppress("unused")
@get:InputFiles
@get:Optional
@@ -781,11 +808,7 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
null
}
val friendDependencies: List<String> = friendPaths.files.filter {
it.exists() && libraryFilter(it)
}.map { it.absolutePath }
args.friendModules = friendDependencies.joinToString(File.pathSeparator)
args.friendModules = friendDependencies.files.joinToString(File.pathSeparator) { it.absolutePath }
if (args.sourceMapBaseDirs == null && !args.sourceMapPrefix.isNullOrEmpty()) {
args.sourceMapBaseDirs = absolutePathProvider