From 1420bd1b332788fe8fd51935a834b6932ae97518 Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Thu, 26 Jan 2017 23:14:17 +0300 Subject: [PATCH] Add Kotlin Gradle DSL to configure coroutines from build.gradle --- .../jetbrains/kotlin/gradle/CoroutinesIT.kt | 20 ++++++++ .../coroutinesProjectDSL/build.gradle | 25 ++++++++++ .../coroutinesProjectDSL/gradle.properties | 1 + .../src/main/kotlin/main.kt | 1 + .../gradle/dsl/KotlinProjectExtension.kt | 47 +++++++++++++++++++ .../gradle/plugin/KotlinPluginWrapper.kt | 6 +++ .../kotlin/gradle/plugin/KotlinProperties.kt | 17 +------ .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 26 ++++++---- 8 files changed, 118 insertions(+), 25 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/gradle.properties create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/src/main/kotlin/main.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinProjectExtension.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CoroutinesIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CoroutinesIT.kt index 4c9ff7905f8..ff0b2019cb6 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CoroutinesIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CoroutinesIT.kt @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.gradle +import org.jetbrains.kotlin.gradle.util.getFileByName +import org.jetbrains.kotlin.gradle.util.modify import org.junit.Test import java.io.File @@ -26,6 +28,24 @@ class CoroutinesIT: BaseGradleIT() { private const val GRADLE_PROPERTIES = "gradle.properties" } + @Test + fun testCoroutinesProjectDSL() { + val project = Project("coroutinesProjectDSL", GRADLE_VERSION) + project.build("assemble") { + assertSuccessful() + assertContains("-Xcoroutines=enable") + } + + project.projectDir.getFileByName("build.gradle").modify { + it.replace("coroutines 'enable'", "coroutines 'error'") + } + + project.build("assemble") { + assertFailed() + assertContains("-Xcoroutines=error") + } + } + @Test fun testCoroutinesJvmEnabled() { jvmProject.doTest("enable", GRADLE_PROPERTIES) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/build.gradle new file mode 100644 index 00000000000..ed3a941c299 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/build.gradle @@ -0,0 +1,25 @@ +buildscript { + repositories { + mavenLocal() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: "kotlin" + +repositories { + mavenLocal() + mavenCentral() +} + +kotlin { + experimental { + coroutines 'enable' + } +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/gradle.properties new file mode 100644 index 00000000000..93ce6a94e63 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xmx1024m -XX:MaxPermSize=512m \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/src/main/kotlin/main.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/src/main/kotlin/main.kt new file mode 100644 index 00000000000..75b4146ee93 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/coroutinesProjectDSL/src/main/kotlin/main.kt @@ -0,0 +1 @@ +suspend fun suspendCoroutine(): T = TODO() \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinProjectExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinProjectExtension.kt new file mode 100644 index 00000000000..7971a1b49e6 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinProjectExtension.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.gradle.dsl + +import org.gradle.api.Project +import org.gradle.api.internal.plugins.DslObject + +internal fun Project.createKotlinExtension() { + val kotlinExt = extensions.create("kotlin", KotlinProjectExtension::class.java) + DslObject(kotlinExt).extensions.create("experimental", ExperimentalExtension::class.java) +} + +open class KotlinProjectExtension { + val experimental: ExperimentalExtension + get() = DslObject(this).extensions.getByType(ExperimentalExtension::class.java)!! +} + +open class ExperimentalExtension { + var coroutines: Coroutines? = null +} + +enum class Coroutines { + ENABLE, + WARN, + ERROR; + + companion object { + val DEFAULT = WARN + + fun byCompilerArgument(argument: String): Coroutines? = + Coroutines.values().firstOrNull { it.name.equals(argument, ignoreCase = true) } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index bace148f722..779ec8241dc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt @@ -19,8 +19,12 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.internal.file.FileResolver +import org.gradle.api.internal.plugins.DslObject import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging +import org.jetbrains.kotlin.gradle.dsl.ExperimentalExtension +import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension +import org.jetbrains.kotlin.gradle.dsl.createKotlinExtension import org.jetbrains.kotlin.gradle.internal.KotlinSourceSetProviderImpl import org.jetbrains.kotlin.gradle.tasks.* import java.io.FileNotFoundException @@ -36,6 +40,8 @@ abstract class KotlinBasePluginWrapper(protected val fileResolver: FileResolver) System.setProperty(org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY, "true") val kotlinGradleBuildServices = KotlinGradleBuildServices.getInstance(project.gradle) + project.createKotlinExtension() + val plugin = getPlugin(kotlinGradleBuildServices) plugin.apply(project) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt index 35a84a4ed81..5a406565c9b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.Project +import org.jetbrains.kotlin.gradle.dsl.Coroutines import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import java.util.* @@ -35,7 +36,7 @@ fun mapKotlinTaskProperties(project: Project, task: AbstractKotlinCompile<*>) { private val propertyMappings = listOf( KotlinPropertyMapping("kotlin.incremental", AbstractKotlinCompile<*>::incremental, String::toBoolean), - KotlinPropertyMapping("kotlin.coroutines", AbstractKotlinCompile<*>::coroutines) { CoroutineSupport.byCompilerArgument(it) } + KotlinPropertyMapping("kotlin.coroutines", AbstractKotlinCompile<*>::coroutinesFromGradleProperties) { Coroutines.byCompilerArgument(it) } ) private class KotlinPropertyMapping( @@ -59,18 +60,4 @@ private class KotlinPropertyMapping( val transformedValue = transform(value) ?: return taskProperty.set(task, transformedValue) } -} - -enum class CoroutineSupport(val compilerArgument: String) { - ENABLED("enable"), - ENABLED_WITH_WARNING("warn"), - DISABLED("error"); - - companion object { - val DEFAULT = ENABLED_WITH_WARNING - - fun byCompilerArgument(argument: String): CoroutineSupport { - return CoroutineSupport.values().find { it.compilerArgument == argument } ?: DEFAULT - } - } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 60010444bce..a4fd5973226 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -20,6 +20,7 @@ import org.codehaus.groovy.runtime.MethodClosure import org.gradle.api.Project import org.gradle.api.Task import org.gradle.api.logging.Logger +import org.gradle.api.tasks.Input import org.gradle.api.tasks.SourceTask import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.compile.AbstractCompile @@ -35,7 +36,6 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.compilerRunner.* import org.jetbrains.kotlin.gradle.dsl.* -import org.jetbrains.kotlin.gradle.plugin.CoroutineSupport import org.jetbrains.kotlin.gradle.plugin.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.kotlinInfo import org.jetbrains.kotlin.gradle.utils.ParsedGradleVersion @@ -62,6 +62,9 @@ abstract class AbstractKotlinCompile() : AbstractCo return ArgumentUtils.convertArgumentsToStringList(arguments) } + private val kotlinExt: KotlinProjectExtension + get() = project.extensions.findByType(KotlinProjectExtension::class.java)!! + // indicates that task should compile kotlin incrementally if possible // it's not possible when IncrementalTaskInputs#isIncremental returns false (i.e first build) var incremental: Boolean = false @@ -73,12 +76,13 @@ abstract class AbstractKotlinCompile() : AbstractCo System.setProperty("kotlin.incremental.compilation.experimental", value.toString()) } - var coroutines: CoroutineSupport = CoroutineSupport.DEFAULT - get() = field - set(value) { - field = value - logger.kotlinDebug { "Set $this.coroutines=${value.compilerArgument}" } - } + internal var coroutinesFromGradleProperties: Coroutines? = null + // Input is needed to force rebuild even if source files are not changed + @get:Input + val coroutines: Coroutines + get() = kotlinExt.experimental.coroutines + ?: coroutinesFromGradleProperties + ?: Coroutines.DEFAULT var compilerJarFile: File? = null internal val compilerJar: File @@ -124,9 +128,11 @@ abstract class AbstractKotlinCompile() : AbstractCo internal abstract fun callCompiler(args: T, sourceRoots: SourceRoots, changedFiles: ChangedFiles) private fun CommonCompilerArguments.setupCommonCompilerArgs() { - coroutinesEnable = coroutines == CoroutineSupport.ENABLED - coroutinesWarn = coroutines == CoroutineSupport.ENABLED_WITH_WARNING - coroutinesError = coroutines == CoroutineSupport.DISABLED + coroutines.let { + coroutinesEnable = it == Coroutines.ENABLE + coroutinesWarn = it == Coroutines.WARN + coroutinesError = it == Coroutines.ERROR + } if (project.logger.isDebugEnabled) { verbose = true