[Gradle] Use task properties to modify task configuration

This change migrates to using properties of KGP tasks and Gradle
built-in tasks. Also, in TaskProvider class, Configurator instances are
created to configure KGP tasks.
This commit is contained in:
Ivan Gavrilovic
2021-04-26 17:32:11 +01:00
committed by teamcityserver
parent ad9f6e63b6
commit 01dd15cc3e
19 changed files with 66 additions and 131 deletions
@@ -685,7 +685,8 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
val abstractKotlinCompileClass =
compileKotlinTask.javaClass.classLoader.loadClass(AbstractKotlinGradleModelBuilder.ABSTRACT_KOTLIN_COMPILE_CLASS)
val getCompileClasspath =
abstractKotlinCompileClass.getDeclaredMethodOrNull("getCompileClasspath") ?: return emptyList()
abstractKotlinCompileClass.getDeclaredMethodOrNull("getCompileClasspath") ?:
abstractKotlinCompileClass.getDeclaredMethodOrNull("getClasspath") ?: return emptyList()
@Suppress("UNCHECKED_CAST")
return (getCompileClasspath(compileKotlinTask) as? Collection<File>)?.map { it.path } ?: emptyList()
}
@@ -83,14 +83,14 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String, private val an
private fun AbstractKotlinCompile<*>.createSourceSet(project: Project, projectType: KotlinProject.ProjectType): SourceSet? {
val javaSourceSet =
project.convention.findPlugin(JavaPluginConvention::class.java)?.sourceSets?.find { it.name == sourceSetName }
project.convention.findPlugin(JavaPluginConvention::class.java)?.sourceSets?.find { it.name == sourceSetName.get() }
val kotlinSourceSet =
javaSourceSet?.getConvention(if (projectType == KotlinProject.ProjectType.PLATFORM_JS) KOTLIN_JS_DSL_NAME else KOTLIN_DSL_NAME) as? KotlinSourceSet
return if (kotlinSourceSet != null) {
SourceSetImpl(
sourceSetName,
if (sourceSetName.contains("test", true)) SourceSet.SourceSetType.TEST else SourceSet.SourceSetType.PRODUCTION,
findFriendSourceSets(),
sourceSetName.get(),
if (sourceSetName.get().contains("test", true)) SourceSet.SourceSetType.TEST else SourceSet.SourceSetType.PRODUCTION,
friendSourceSets.get(),
kotlinSourceSet.kotlin.srcDirs,
javaSourceSet.resources.srcDirs,
destinationDir,
@@ -104,7 +104,7 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String, private val an
* Constructs the Android [SourceSet] that should be returned to the IDE for each compile task/variant.
*/
private fun AbstractKotlinCompile<*>.createAndroidSourceSet(androidTarget: KotlinAndroidTarget): SourceSet {
val variantName = sourceSetName
val variantName = sourceSetName.get()
val compilation = androidTarget.compilations.getByName(variantName)
// Merge all sources and resource dirs from the different Source Sets that make up this variant.
val sources = compilation.allKotlinSourceSets.flatMap {
@@ -114,9 +114,9 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String, private val an
it.resources.srcDirs
}.distinctBy { it.absolutePath }
return SourceSetImpl(
sourceSetName,
if (sourceSetName.contains("test", true)) SourceSet.SourceSetType.TEST else SourceSet.SourceSetType.PRODUCTION,
findFriendSourceSets(),
sourceSetName.get(),
if (sourceSetName.get().contains("test", true)) SourceSet.SourceSetType.TEST else SourceSet.SourceSetType.PRODUCTION,
friendSourceSets.get(),
sources,
resources,
destinationDir,
@@ -125,24 +125,16 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String, private val an
)
}
private fun AbstractKotlinCompile<*>.findFriendSourceSets(): Collection<String> {
val friendSourceSets = ArrayList<String>()
(taskData.compilation as? KotlinCompilation<*>)?.associateWithTransitiveClosure?.forEach { associateCompilation ->
friendSourceSets.add(associateCompilation.name)
}
return friendSourceSets
}
private fun AbstractKotlinCompile<*>.createCompilerArguments(): CompilerArguments {
return CompilerArgumentsImpl(
serializedCompilerArguments,
defaultSerializedCompilerArguments,
compileClasspath.toList()
classpath.toList()
)
}
private fun AbstractKotlinCompile<*>.createExperimentalFeatures(): ExperimentalFeatures {
return ExperimentalFeaturesImpl(coroutinesStr.get())
return ExperimentalFeaturesImpl(coroutines.get().name)
}
}
}
@@ -170,12 +170,12 @@ open class KotlinPlatformImplementationPluginBase(platformName: String) : Kotlin
// At the point when the source set in the platform module is created, the task does not exist
val platformTasks = platformProject.tasks
.withType(AbstractKotlinCompile::class.java)
.filter { it.sourceSetName == commonSourceSet.name } // TODO use strict check once this code is not run in K/N
.filter { it.sourceSetName.get() == commonSourceSet.name } // TODO use strict check once this code is not run in K/N
val commonSources = getKotlinSourceDirectorySetSafe(commonSourceSet)!!
for (platformTask in platformTasks) {
platformTask.source(commonSources)
platformTask.commonSourceSet += commonSources
platformTask.commonSourceSet.from(commonSources)
}
}
}
@@ -14,6 +14,7 @@ import org.gradle.api.artifacts.maven.Conf2ScopeMappingContainer
import org.gradle.api.artifacts.maven.MavenResolver
import org.gradle.api.attributes.Usage
import org.gradle.api.file.ConfigurableFileTree
import org.gradle.api.file.Directory
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.logging.Logging
@@ -107,7 +108,7 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
private fun prepareKotlinCompileTask(): TaskProvider<out T> =
registerKotlinCompileTask(register = ::doRegisterTask).also { task ->
kotlinCompilation.output.addClassesDir { project.files(task.map { it.destinationDir }).builtBy(task) }
kotlinCompilation.output.classesDirs.from(task.flatMap { it.destinationDirectory })
}
protected fun registerKotlinCompileTask(
@@ -116,13 +117,10 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
): TaskProvider<out T> {
logger.kotlinDebug("Creating kotlin compile task $name")
KotlinCompileTaskData.register(name, kotlinCompilation).apply {
destinationDir.set(project.provider { defaultKotlinDestinationDir })
}
return register(project, name) {
it.description = taskDescription
it.mapClasspath { kotlinCompilation.compileDependencyFiles }
it.destinationDirectory.set(defaultKotlinDestinationDir)
it.classpath = project.files({ kotlinCompilation.compileDependencyFiles })
}
}
@@ -207,21 +205,25 @@ internal class Kotlin2JvmSourceSetProcessor(
javaSourceSet?.let { java ->
val javaTask = project.tasks.withType<AbstractCompile>().named(java.compileJavaTaskName)
configureJavaTask(kotlinTask, javaTask)
javaTask.configure { javaCompile ->
javaCompile.classpath += project.files(kotlinTask.flatMap { it.destinationDirectory })
}
kotlinTask.configure { kotlinCompile ->
kotlinCompile.javaOutputDir.set(javaTask.flatMap { it.destinationDirectory })
}
}
if (sourceSetName == SourceSet.MAIN_SOURCE_SET_NAME) {
project.pluginManager.withPlugin("java-library") {
registerKotlinOutputForJavaLibrary(kotlinTask.map { it.destinationDir }, kotlinTask)
registerKotlinOutputForJavaLibrary(kotlinTask.flatMap { it.destinationDirectory })
}
}
}
}
private fun registerKotlinOutputForJavaLibrary(outputDir: Provider<File>, taskDependency: TaskProvider<*>) {
private fun registerKotlinOutputForJavaLibrary(outputDir: Provider<Directory>) {
val configuration = project.configurations.getByName("apiElements")
configuration.outgoing.variants.getByName("classes").artifact(outputDir) {
it.builtBy(taskDependency)
it.type = "java-classes-directory"
}
}
@@ -259,11 +261,12 @@ internal class Kotlin2JsSourceSetProcessor(
project.whenEvaluated {
kotlinTask.configure { kotlinTaskInstance ->
val kotlinOptions = kotlinTaskInstance.kotlinOptions
val outputDir: File = kotlinTaskInstance.outputFile.parentFile
val outputFile = kotlinTaskInstance.outputFile.get()
val outputDir: File = outputFile.parentFile
kotlinOptions.outputFile = if (!kotlinOptions.isProduceUnzippedKlib()) {
kotlinTaskInstance.outputFile.absolutePath
outputFile.absolutePath
} else {
kotlinTaskInstance.outputFile.parentFile.absolutePath
outputFile.parentFile.absolutePath
}
if (outputDir.isParentOf(project.rootDir))
throw InvalidUserDataException(
@@ -931,14 +934,11 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationTool
val kotlinTaskName = compilation.compileKotlinTaskName
KotlinCompileTaskData.register(kotlinTaskName, compilation).apply {
// store kotlin classes in separate directory. They will serve as class-path to java compiler
destinationDir.set(project.provider { File(project.buildDir, "tmp/kotlin-classes/$variantDataName") })
}
tasksProvider.registerKotlinJVMTask(project, kotlinTaskName, compilation) {
it.parentKotlinOptionsImpl = rootKotlinOptions
it.parentKotlinOptionsImpl.set(rootKotlinOptions)
// store kotlin classes in separate directory. They will serve as class-path to java compiler
it.destinationDirectory.set(project.layout.buildDirectory.dir( "tmp/kotlin-classes/$variantDataName"))
it.description = "Compiles the $variantDataName kotlin."
}
@@ -979,36 +979,6 @@ internal inline fun BaseVariant.forEachJavaSourceDir(action: (ConfigurableFileTr
getSourceFolders(SourceKind.JAVA).forEach(action)
}
internal fun configureJavaTask(
kotlinTaskProvider: TaskProvider<out KotlinCompile>,
javaTaskProvider: TaskProvider<out AbstractCompile>
) {
javaTaskProvider.configure { javaTask ->
val kotlinTask = kotlinTaskProvider.get()
kotlinTask.javaOutputDir = javaTask.destinationDir
// Make Gradle check if the javaTask is up-to-date based on the Kotlin classes
javaTask.inputs.run {
dir(kotlinTask.destinationDir)
.withNormalizer(CompileClasspathNormalizer::class.java)
.withPropertyName("${kotlinTask.name}OutputClasses")
}
// Also, use kapt1 annotations file for up-to-date check since annotation processing is done with javac
javaTask.dependsOn(kotlinTask)
/*
* It's important to modify javaTask.classpath only in doFirst,
* because Android plugin uses ConventionMapping to modify it too (see JavaCompileConfigAction.execute),
* and setting classpath explicitly prevents usage of Android mappings.
* Also classpath set by Android can be modified after execution of some tasks (see VarianConfiguration.getCompileClasspath)
* ex. it adds some support libraries jars after execution of prepareComAndroidSupportSupportV42311Library task,
* so it's only safe to modify javaTask.classpath right before its usage
*/
// todo: remove?
javaTask.appendClasspathDynamically(kotlinTask.destinationDir)
}
}
internal fun ifKaptEnabled(project: Project, block: () -> Unit) {
var triggered = false
@@ -28,7 +28,6 @@ import java.io.File
import java.util.*
internal fun PropertiesProvider.mapKotlinTaskProperties(task: AbstractKotlinCompile<*>) {
coroutines?.let { task.coroutinesFromGradleProperties = it }
useFallbackCompilerSearch?.let { task.useFallbackCompilerSearch = it }
if (task is KotlinCompile) {
@@ -16,34 +16,8 @@
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.HasConvention
import org.gradle.api.logging.Logger
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.compilerRunner.KotlinLogger
import java.io.File
internal fun AbstractCompile.appendClasspathDynamically(file: File) {
var added = false
val objects = project.objects
doFirst {
if (file !in classpath) {
classpath += objects.fileCollection().from(file)
added = true
}
}
doLast {
if (added) {
classpath -= objects.fileCollection().from(file)
}
}
}
fun AbstractCompile.mapClasspath(fn: () -> FileCollection) {
conventionMapping.map("classpath", fn)
}
internal inline fun <reified T : Any> Any.addConvention(name: String, plugin: T) {
(this as HasConvention).convention.plugins[name] = plugin
@@ -323,12 +323,12 @@ internal fun addSourcesToKotlinCompileTask(
// In this call, the super-implementation of `source` adds the directories files to the roots of the union file tree,
// so it's OK to pass just the source roots.
source(Callable(sources))
sourceFilesExtensions(sourceFileExtensions)
sourceFilesExtensions.addAll(sourceFileExtensions)
// The `commonSourceSet` is passed to the compiler as-is, converted with toList
commonSourceSet += project.files(Callable<Any> {
if (addAsCommonSources.value) sources else emptyList<Any>()
})
commonSourceSet.from(
Callable<Any> { if (addAsCommonSources.value) sources else emptyList<Any>() }
)
}
project.tasks
@@ -62,7 +62,7 @@ class ScriptingGradleSubplugin : Plugin<Project> {
if (task !is KaptGenerateStubsTask) {
try {
val discoveryClasspathConfigurationName = getDiscoveryClasspathConfigurationName(task.sourceSetName)
val discoveryClasspathConfigurationName = getDiscoveryClasspathConfigurationName(task.sourceSetName.get())
val discoveryClasspathConfiguration = project.configurations.findByName(discoveryClasspathConfigurationName)
when {
discoveryClasspathConfiguration == null ->
@@ -70,7 +70,7 @@ class ScriptingGradleSubplugin : Plugin<Project> {
discoveryClasspathConfiguration.allDependencies.isEmpty() -> {
// skip further checks - user did not configured any discovery sources
}
else -> configureScriptsExtensions(project, javaPluginConvention, task.sourceSetName)
else -> configureScriptsExtensions(project, javaPluginConvention, task.sourceSetName.get())
}
} catch (e: IllegalStateException) {
project.logger.warn("$SCRIPTING_LOG_PREFIX applied in the non-supported environment (error received: ${e.message})")
@@ -61,12 +61,11 @@ class Android25ProjectHandler(
kotlinTask.configure { kotlinTaskInstance ->
kotlinTaskInstance.inputs.files(variantData.getSourceFolders(SourceKind.JAVA)).withPathSensitivity(PathSensitivity.RELATIVE)
kotlinTaskInstance.mapClasspath {
val kotlinClasspath = variantData.getCompileClasspath(preJavaClasspathKey)
kotlinClasspath + project.files(AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt))
}
kotlinTaskInstance.classpath = project.files()
.from(variantData.getCompileClasspath(preJavaClasspathKey))
.from(AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt))
kotlinTaskInstance.javaOutputDir = javaTask.get().destinationDir
kotlinTaskInstance.javaOutputDir.set(javaTask.flatMap { it.destinationDirectory })
}
// Find the classpath entries that come from the tested variant and register them as the friend paths, lazily
@@ -84,8 +83,8 @@ class Android25ProjectHandler(
)
compilation.output.classesDirs.from(
kotlinTask.map { it.destinationDir },
javaTask.map { it.destinationDir }
kotlinTask.flatMap { it.destinationDirectory },
javaTask.flatMap { it.destinationDirectory }
)
}
@@ -78,7 +78,7 @@ class KotlinJsDcePlugin : Plugin<Project> {
dceTask.configure {
it.classpath = configuration
it.destinationDir = it.dceOptions.outputDirectory?.let { File(it) } ?: outputDir
it.source((kotlinTask.get() as Kotlin2JsCompile).outputFile)
it.source((kotlinTask.get() as Kotlin2JsCompile).outputFile.get())
}
}
}
@@ -103,7 +103,7 @@ open class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
) { task ->
val entryFileProvider = binary.linkSyncTask.map {
it.destinationDir
.resolve(binary.linkTask.get().outputFile.name)
.resolve(binary.linkTask.get().outputFile.get().name)
}
webpackMajorVersion.choose(
@@ -173,7 +173,7 @@ open class KotlinBrowserJsIr @Inject constructor(target: KotlinJsIrTarget) :
) { task ->
val entryFileProvider = binary.linkSyncTask.map {
it.destinationDir
.resolve(binary.linkTask.get().outputFile.name)
.resolve(binary.linkTask.get().outputFile.get().name)
}
task.description = "build webpack ${mode.name.toLowerCase()} bundle"
@@ -123,7 +123,7 @@ abstract class KotlinJsIrSubTarget(
project.layout.file(
binary.linkSyncTask.map {
it.destinationDir
.resolve(binary.linkTask.get().outputFile.name)
.resolve(binary.linkTask.get().outputFile.get().name)
}
)
)
@@ -69,7 +69,7 @@ open class KotlinNodeJsIr @Inject constructor(target: KotlinJsIrTarget) :
project.layout.file(
binary.linkSyncTask.map {
it.destinationDir
.resolve(binary.linkTask.get().outputFile.name)
.resolve(binary.linkTask.get().outputFile.get().name)
}
)
)
@@ -257,7 +257,7 @@ open class KotlinBrowserJs @Inject constructor(target: KotlinJsTarget) :
entryProperty.set(
project.layout.file(actualDceTaskProvider.map {
it.destinationDir.resolve(compilation.compileKotlinTask.outputFile.name)
it.destinationDir.resolve(compilation.compileKotlinTask.outputFile.get().name)
})
)
@@ -300,7 +300,7 @@ open class KotlinBrowserJs @Inject constructor(target: KotlinJsTarget) :
?: compilation.npmProject.dir.resolve(if (dev) DCE_DEV_DIR else DCE_DIR)
it.defaultCompilerClasspath.setFrom(project.configurations.named(COMPILER_CLASSPATH_CONFIGURATION_NAME))
it.source(kotlinTask.map { it.outputFile })
it.source(kotlinTask.map { it.outputFile.get() })
}
}
@@ -103,8 +103,8 @@ abstract class KotlinJsSubTarget(
testJs.group = LifecycleBasePlugin.VERIFICATION_GROUP
testJs.description = testTaskDescription
val compileOutputFile = compileTask.map { it.outputFile }
testJs.inputFileProperty.set(project.layout.file(compileOutputFile))
val compileOutputFile = compileTask.flatMap { it.outputFile }
testJs.inputFileProperty.fileProvider(compileOutputFile)
testJs.dependsOn(nodeJs.npmInstallTaskProvider, compileTask, nodeJs.nodeJsSetupTaskProvider)
@@ -49,7 +49,7 @@ open class KotlinNodeJs @Inject constructor(target: KotlinJsTarget) :
) {
val runTaskHolder = NodeJsExec.create(compilation, disambiguateCamelCased(RUN_TASK_NAME)) {
group = taskGroupName
inputFileProperty.set(project.layout.file(compilation.compileKotlinTaskProvider.map { it.outputFile }))
inputFileProperty.fileProvider(compilation.compileKotlinTaskProvider.flatMap { it.outputFile })
}
target.runTask.dependsOn(runTaskHolder)
}
@@ -10,6 +10,7 @@ import org.gradle.api.Incubating
import org.gradle.api.file.FileCollection
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.internal.file.FileResolver
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
@@ -27,7 +28,6 @@ import org.jetbrains.kotlin.gradle.targets.js.npm.npmProject
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig.Mode
import org.jetbrains.kotlin.gradle.testing.internal.reportsDir
import org.jetbrains.kotlin.gradle.utils.injected
import org.jetbrains.kotlin.gradle.utils.newFileProperty
import org.jetbrains.kotlin.gradle.utils.property
import java.io.File
import javax.inject.Inject
@@ -37,7 +37,8 @@ open class KotlinWebpack
constructor(
@Internal
@Transient
override val compilation: KotlinJsCompilation
override val compilation: KotlinJsCompilation,
objects: ObjectFactory
) : DefaultTask(), RequiresNpmDependencies {
@Transient
private val nodeJs = NodeJsRootPlugin.apply(project.rootProject)
@@ -78,9 +79,7 @@ constructor(
@get:PathSensitive(PathSensitivity.ABSOLUTE)
@get:InputFile
val entryProperty: RegularFileProperty = project.newFileProperty {
compilation.compileKotlinTask.outputFile
}
val entryProperty: RegularFileProperty = objects.fileProperty().fileProvider(compilation.compileKotlinTask.outputFile)
init {
onlyIf {
@@ -457,9 +457,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
}
compilation.output.addClassesDir {
project.project.files(compileTaskProvider.map { it.outputFile })
}
compilation.output.classesDirs.from(compileTaskProvider.flatMap { it.outputFile })
project.project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTaskProvider)
@@ -21,10 +21,9 @@ import org.gradle.api.Task
import org.gradle.api.UnknownTaskException
import org.gradle.api.tasks.TaskCollection
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.runOnceAfterEvaluated
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinOptions
@@ -92,6 +91,7 @@ internal open class KotlinTasksProvider {
val taskClass = taskOrWorkersTask<KotlinCompile, KotlinCompileWithWorkers>(properties)
val result = project.registerTask(name, taskClass) {
configureAction(it)
KotlinCompile.Configurator(compilation).configure(it)
}
configure(result, project, properties, compilation)
return result
@@ -107,6 +107,7 @@ internal open class KotlinTasksProvider {
val taskClass = taskOrWorkersTask<Kotlin2JsCompile, Kotlin2JsCompileWithWorkers>(properties)
val result = project.registerTask(name, taskClass) {
configureAction(it)
Kotlin2JsCompile.Configurator<Kotlin2JsCompile>(compilation).configure(it)
}
configure(result, project, properties, compilation)
return result
@@ -122,6 +123,7 @@ internal open class KotlinTasksProvider {
val taskClass = taskOrWorkersTask<KotlinJsIrLink, KotlinJsIrLinkWithWorkers>(properties)
val result = project.registerTask(name, taskClass) {
configureAction(it)
KotlinJsIrLink.Configurator(compilation).configure(it)
}
configure(result, project, properties, compilation)
return result
@@ -137,6 +139,7 @@ internal open class KotlinTasksProvider {
val taskClass = taskOrWorkersTask<KotlinCompileCommon, KotlinCompileCommonWithWorkers>(properties)
val result = project.registerTask(name, taskClass) {
configureAction(it)
KotlinCompileCommon.Configurator(compilation).configure(it)
}
configure(result, project, properties, compilation)
return result
@@ -171,7 +174,7 @@ internal class AndroidTasksProvider : KotlinTasksProvider() {
) {
super.configure(kotlinTaskHolder, project, propertiesProvider, compilation)
kotlinTaskHolder.configure {
it.useModuleDetection = true
it.useModuleDetection.set(true)
}
}
}