All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.gradle.tasks.configuration.AbstractKotlinCompileConfig.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.gradle.tasks.configuration

import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.Directory
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.compilerRunner.CompilerSystemPropertiesService
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.internal.BuildIdService
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_BUILD_DIR_NAME

/**
 * Configuration for the base compile task, [org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile].
 *
 * This contains all data necessary to configure the tasks, and should avoid exposing global state (project, extensions, other tasks)
 * to the task instance as much as possible.
 */
internal abstract class AbstractKotlinCompileConfig>(
    project: Project,
    val ext: KotlinTopLevelExtension
) : TaskConfigAction(project) {

    init {
        val compilerSystemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project)
        val buildFinishedListenerService = BuildFinishedListenerService.registerIfAbsent(project)
        val buildIdService = BuildIdService.registerIfAbsent(project)
        configureTask { task ->
            val propertiesProvider = project.kotlinPropertiesProvider

            task.taskBuildCacheableOutputDirectory
                .value(getKotlinBuildDir(task).map { it.dir("cacheable") })
                .disallowChanges()
            task.taskBuildLocalStateDirectory
                .value(getKotlinBuildDir(task).map { it.dir("local-state") })
                .disallowChanges()

            task.localStateDirectories.from(task.taskBuildLocalStateDirectory).disallowChanges()
            task.systemPropertiesService.value(compilerSystemPropertiesService).disallowChanges()

            task.kotlinCompilerArgumentsLogLevel.value(propertiesProvider.kotlinCompilerArgumentsLogLevel).disallowChanges()

            propertiesProvider.kotlinDaemonJvmArgs?.let { kotlinDaemonJvmArgs ->
                task.kotlinDaemonJvmArguments.set(providers.provider {
                    kotlinDaemonJvmArgs.split("\\s+".toRegex())
                })
            }
            task.compilerExecutionStrategy.convention(propertiesProvider.kotlinCompilerExecutionStrategy).finalizeValueOnRead()
            task.useDaemonFallbackStrategy.convention(propertiesProvider.kotlinDaemonUseFallbackStrategy).finalizeValueOnRead()
            task.suppressKotlinOptionsFreeArgsModificationWarning
                .convention(propertiesProvider.kotlinOptionsSuppressFreeArgsModificationWarning)
                .finalizeValueOnRead()

            task.preciseCompilationResultsBackup
                .convention(propertiesProvider.preciseCompilationResultsBackup)
                .finalizeValueOnRead()
            task.taskOutputsBackupExcludes.addAll(task.preciseCompilationResultsBackup.map {
                if (it) listOf(task.destinationDirectory.get().asFile, task.taskBuildLocalStateDirectory.get().asFile) else emptyList()
            })
            task.keepIncrementalCompilationCachesInMemory
                .convention(task.preciseCompilationResultsBackup.map { it && propertiesProvider.keepIncrementalCompilationCachesInMemory })
                .finalizeValueOnRead()
            task.taskOutputsBackupExcludes.addAll(task.keepIncrementalCompilationCachesInMemory.map {
                if (it) listOf(task.taskBuildCacheableOutputDirectory.get().asFile) else emptyList()
            })
            task.enableUnsafeIncrementalCompilationForMultiplatform
                .convention(propertiesProvider.enableUnsafeOptimizationsForMultiplatform)
                .finalizeValueOnRead()
            task.buildFinishedListenerService.value(buildFinishedListenerService).disallowChanges()
            task.buildIdService.value(buildIdService).disallowChanges()

            task.incremental = false
            task.useModuleDetection.convention(false)
            task.runViaBuildToolsApi.convention(propertiesProvider.runKotlinCompilerViaBuildToolsApi).finalizeValueOnRead()

            task.explicitApiMode
                .value(project.providers.provider { ext.explicitApi })
                .finalizeValueOnRead()
        }
    }

    private fun getKotlinBuildDir(task: TASK): Provider =
        task.project.layout.buildDirectory.dir("$KOTLIN_BUILD_DIR_NAME/${task.name}")

    protected fun getClasspathSnapshotDir(task: TASK): Provider =
        getKotlinBuildDir(task).map { it.dir("classpath-snapshot") }

    constructor(compilationInfo: KotlinCompilationInfo) : this(
        compilationInfo.project,
        compilationInfo.project.topLevelExtension
    ) {
        configureTask { task ->
            task.friendPaths.from({ compilationInfo.friendPaths })
            compilationInfo.tcs.compilation.let { compilation ->
                task.friendSourceSets
                    .value(providers.provider { compilation.allAssociatedCompilations.map { it.name } })
                    .disallowChanges()
                task.pluginClasspath.from(
                    compilation.internal.configurations.pluginConfiguration
                )
            }

            task.sourceSetName.value(providers.provider { compilationInfo.compilationName })
            task.multiPlatformEnabled.value(
                providers.provider {
                    compilationInfo.project.plugins.any {
                        it is KotlinPlatformPluginBase ||
                                it is AbstractKotlinMultiplatformPluginWrapper
                    }
                }
            )

            task.explicitApiMode
                .value(
                    project.providers.provider {
                        // Plugin explicitly does not configures 'explicitApi' mode for test sources
                        // compilation, as test sources are not published
                        val compilation = compilationInfo.tcs.compilation
                        val isCommonCompilation = compilation.target is KotlinMetadataTarget

                        val androidCompilation = compilationInfo.tcs.compilation as? KotlinJvmAndroidCompilation
                        val isMainAndroidCompilation = androidCompilation?.let {
                            getTestedVariantData(it.androidVariant) == null
                        } ?: false

                        if (compilationInfo.isMain || isCommonCompilation || isMainAndroidCompilation) {
                            ext.explicitApi
                        } else {
                            ExplicitApiMode.Disabled
                        }
                    }
                )
                .finalizeValueOnRead()
        }
    }
}

internal abstract class TaskConfigAction(protected val project: Project) {

    protected val objectFactory: ObjectFactory = project.objects
    protected val providers: ProviderFactory = project.providers
    protected val propertiesProvider = project.kotlinPropertiesProvider

    private var executed = false

    // Collect all task configurations, and run them later (in order they were added).
    private val taskConfigActions = ArrayDeque<(TaskProvider) -> Unit>()

    fun configureTaskProvider(configAction: (TaskProvider) -> Unit) {
        check(!executed) {
            "Task has already been configured. Configuration actions should be added to this object before `this.execute` method runs."
        }
        taskConfigActions.addLast(configAction)
    }

    fun configureTask(configAction: (TASK) -> Unit) {
        configureTaskProvider { taskProvider ->
            taskProvider.configure(configAction)
        }
    }

    fun execute(taskProvider: TaskProvider) {
        executed = true
        taskConfigActions.forEach {
            it(taskProvider)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy