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 package org.jetbrains.kotlin.gradle.plugin.mpp
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.GradleException import org.gradle.api.*
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.attributes.AttributeContainer import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.execution.TaskExecutionListener import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
@@ -193,20 +191,37 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override fun toString(): String = "compilation '$compilationName' ($target)" 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, * 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. * it should point to those friend artifact files via this property.
*/ */
internal open val friendArtifacts: FileCollection internal open val friendArtifacts: FileCollection
get() = with(target.project) { 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 // 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: // that depends on this module's production part, include the main artifact in the friend artifacts, lazily:
files( files(
provider { Callable {
listOfNotNull( friendArtifactsTaskProvider.get().archivePathCompatible
tasks.withType(AbstractArchiveTask::class.java).findByName(target.artifactsTaskName)?.archivePathCompatible
)
} }
) )
} else files() } 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.FileCollection
import org.gradle.api.file.FileTree import org.gradle.api.file.FileTree
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments 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.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.utils.newFileProperty import org.jetbrains.kotlin.gradle.utils.newFileProperty
import java.io.File import java.io.File
import javax.inject.Inject
@CacheableTask @CacheableTask
open class KotlinJsIrLink : Kotlin2JsCompile() { open class KotlinJsIrLink @Inject constructor(
objectFactory: ObjectFactory
): Kotlin2JsCompile(objectFactory) {
// Link tasks are not affected by compiler plugin // Link tasks are not affected by compiler plugin
override val pluginClasspath: FileCollection = project.objects.fileCollection() override val pluginClasspath: FileCollection = project.objects.fileCollection()
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.gradle.targets.js.ir package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.model.ObjectFactory
import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.CacheableTask
import org.gradle.workers.WorkerExecutor import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers
@@ -15,8 +16,9 @@ import javax.inject.Inject
internal open class KotlinJsIrLinkWithWorkers internal open class KotlinJsIrLinkWithWorkers
@Inject @Inject
constructor( constructor(
objectFactory: ObjectFactory,
private val workerExecutor: WorkerExecutor private val workerExecutor: WorkerExecutor
) : KotlinJsIrLink() { ) : KotlinJsIrLink(objectFactory) {
override fun compilerRunner() = override fun compilerRunner() =
GradleCompilerRunnerWithWorkers( GradleCompilerRunnerWithWorkers(
GradleCompileTaskProvider(this), GradleCompileTaskProvider(this),
@@ -10,6 +10,7 @@ import org.gradle.api.Task
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.logging.Logger import org.gradle.api.logging.Logger
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.gradle.api.tasks.compile.AbstractCompile 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.library.impl.isKotlinLibrary
import org.jetbrains.kotlin.utils.JsLibraryUtils import org.jetbrains.kotlin.utils.JsLibraryUtils
import java.io.File import java.io.File
import java.util.zip.ZipFile
import javax.inject.Inject import javax.inject.Inject
const val KOTLIN_BUILD_DIR_NAME = "kotlin" const val KOTLIN_BUILD_DIR_NAME = "kotlin"
@@ -304,6 +306,15 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
taskData.compilation.moduleName 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 @get:Internal // takes part in the compiler arguments
val friendPaths: FileCollection = project.files( val friendPaths: FileCollection = project.files(
project.provider { project.provider {
@@ -632,8 +643,9 @@ internal open class KotlinCompileWithWorkers @Inject constructor(
@CacheableTask @CacheableTask
internal open class Kotlin2JsCompileWithWorkers @Inject constructor( internal open class Kotlin2JsCompileWithWorkers @Inject constructor(
objectFactory: ObjectFactory,
private val workerExecutor: WorkerExecutor private val workerExecutor: WorkerExecutor
) : Kotlin2JsCompile() { ) : Kotlin2JsCompile(objectFactory) {
override fun compilerRunner() = override fun compilerRunner() =
GradleCompilerRunnerWithWorkers( GradleCompilerRunnerWithWorkers(
@@ -654,7 +666,9 @@ internal open class KotlinCompileCommonWithWorkers @Inject constructor(
} }
@CacheableTask @CacheableTask
open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), KotlinJsCompile { open class Kotlin2JsCompile @Inject constructor(
objectFactory: ObjectFactory
) : AbstractKotlinCompile<K2JSCompilerArguments>(), KotlinJsCompile {
init { init {
incremental = true incremental = true
@@ -718,6 +732,19 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
override fun getSourceRoots() = SourceRoots.KotlinOnly.create(getSource(), sourceFilesExtensions) 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") @Suppress("unused")
@get:InputFiles @get:InputFiles
@get:Optional @get:Optional
@@ -781,11 +808,7 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
null null
} }
val friendDependencies: List<String> = friendPaths.files.filter { args.friendModules = friendDependencies.files.joinToString(File.pathSeparator) { it.absolutePath }
it.exists() && libraryFilter(it)
}.map { it.absolutePath }
args.friendModules = friendDependencies.joinToString(File.pathSeparator)
if (args.sourceMapBaseDirs == null && !args.sourceMapPrefix.isNullOrEmpty()) { if (args.sourceMapBaseDirs == null && !args.sourceMapPrefix.isNullOrEmpty()) {
args.sourceMapBaseDirs = absolutePathProvider args.sourceMapBaseDirs = absolutePathProvider