如何在多个 Gradle 项目之间共享样板 Kotlin 配置?
How to share boilerplate Kotlin configuration across multiple Gradle projects?
Gradle 项目中的 typical Kotlin configuration 非常样板化,我正在寻找一种方法将其抽象到外部构建脚本中,以便可以重复使用。
我有一个可行的解决方案(如下),但感觉有点像 hack,因为 kotlin-gradle-plugin 不能以这种方式开箱即用。
在您 can't apply the plugin by id 时从外部脚本应用任何非标准插件是很麻烦的,即
apply plugin: 'kotlin'
将导致 Plugin with id 'kotlin' not found.
简单(嗯,通常)的解决方法是通过插件的完全限定类名来应用,即
apply plugin: org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
在这种情况下会抛出一个很好的小异常,表明该插件可能不应该以这种方式调用:
Failed to determine source cofiguration of kotlin plugin.
Can not download core. Please verify that this or any parent project
contains 'kotlin-gradle-plugin' in buildscript's classpath configuration.
所以我设法拼凑了一个插件(只是 real plugin 的修改版本),这迫使它从当前的构建脚本中找到插件。
kotlin.gradle
buildscript {
ext.kotlin_version = "1.0.3"
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
apply plugin: CustomKotlinPlugin
import org.jetbrains.kotlin.gradle.plugin.CleanUpBuildListener
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePluginWrapper
import org.jetbrains.kotlin.gradle.plugin.KotlinPlugin
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
/**
* Wrapper around the Kotlin plugin wrapper (this code is largely a refactoring of KotlinBasePluginWrapper).
* This is required because the default behaviour expects the kotlin plugin to be applied from the project,
* not from an external buildscript.
*/
class CustomKotlinPlugin extends KotlinBasePluginWrapper {
@Override
void apply(Project project) {
// use String literal as KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY constant isn't available
System.setProperty("kotlin.environment.keepalive", "true")
// just use the kotlin version defined in this script
project.extensions.extraProperties?.set("kotlin.gradle.plugin.version", project.property('kotlin_version'))
// get the plugin using the current buildscript
def plugin = getPlugin(this.class.classLoader, project.buildscript)
plugin.apply(project)
def cleanUpBuildListener = new CleanUpBuildListener(this.class.classLoader, project)
cleanUpBuildListener.buildStarted()
project.gradle.addBuildListener(cleanUpBuildListener)
}
@Override
Plugin<Project> getPlugin(ClassLoader pluginClassLoader, ScriptHandler scriptHandler){
return new KotlinPlugin(scriptHandler, new KotlinTasksProvider(pluginClassLoader));
}
}
然后可以将其应用于任何项目(即 apply from: "kotlin.gradle"
),您就可以 运行 进行 Kotlin 开发了。
可以用,我还没有遇到任何问题,但我想知道是否有更好的方法?每当有新版本的 Kotlin 时,我并不热衷于合并对插件的更改。
查看 nebula-kotlin-plugin。它似乎非常接近您要在那里实现的目标。
这里的问题是 known gradle bug 无法通过 init 脚本中的 id 应用插件。这就是为什么您需要使用完全限定的 class 名称作为解决方法的原因。
例如我在初始化脚本中有以下内容并且它有效:
apply plugin: org.jetbrains.kotlin.gradle.plugin.KotlinPlatformJvmPlugin
顺便说一句,我创建了一个 gradle 插件,用于准备自定义 gradle 发行版,其中包含初始化脚本中定义的通用设置 - custom-gradle-dist。它非常适合我的项目,例如库项目的 build.gradle 看起来像这样(这是一个完整的文件,所有 repository, apply plugin 、dependencies 等设置在初始化脚本中定义):
dependencies {
compile 'org.springframework.kafka:spring-kafka'
}
Gradle 项目中的 typical Kotlin configuration 非常样板化,我正在寻找一种方法将其抽象到外部构建脚本中,以便可以重复使用。
我有一个可行的解决方案(如下),但感觉有点像 hack,因为 kotlin-gradle-plugin 不能以这种方式开箱即用。
在您 can't apply the plugin by id 时从外部脚本应用任何非标准插件是很麻烦的,即
apply plugin: 'kotlin'
将导致 Plugin with id 'kotlin' not found.
简单(嗯,通常)的解决方法是通过插件的完全限定类名来应用,即
apply plugin: org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
在这种情况下会抛出一个很好的小异常,表明该插件可能不应该以这种方式调用:
Failed to determine source cofiguration of kotlin plugin.
Can not download core. Please verify that this or any parent project
contains 'kotlin-gradle-plugin' in buildscript's classpath configuration.
所以我设法拼凑了一个插件(只是 real plugin 的修改版本),这迫使它从当前的构建脚本中找到插件。
kotlin.gradle
buildscript {
ext.kotlin_version = "1.0.3"
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
apply plugin: CustomKotlinPlugin
import org.jetbrains.kotlin.gradle.plugin.CleanUpBuildListener
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePluginWrapper
import org.jetbrains.kotlin.gradle.plugin.KotlinPlugin
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
/**
* Wrapper around the Kotlin plugin wrapper (this code is largely a refactoring of KotlinBasePluginWrapper).
* This is required because the default behaviour expects the kotlin plugin to be applied from the project,
* not from an external buildscript.
*/
class CustomKotlinPlugin extends KotlinBasePluginWrapper {
@Override
void apply(Project project) {
// use String literal as KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY constant isn't available
System.setProperty("kotlin.environment.keepalive", "true")
// just use the kotlin version defined in this script
project.extensions.extraProperties?.set("kotlin.gradle.plugin.version", project.property('kotlin_version'))
// get the plugin using the current buildscript
def plugin = getPlugin(this.class.classLoader, project.buildscript)
plugin.apply(project)
def cleanUpBuildListener = new CleanUpBuildListener(this.class.classLoader, project)
cleanUpBuildListener.buildStarted()
project.gradle.addBuildListener(cleanUpBuildListener)
}
@Override
Plugin<Project> getPlugin(ClassLoader pluginClassLoader, ScriptHandler scriptHandler){
return new KotlinPlugin(scriptHandler, new KotlinTasksProvider(pluginClassLoader));
}
}
然后可以将其应用于任何项目(即 apply from: "kotlin.gradle"
),您就可以 运行 进行 Kotlin 开发了。
可以用,我还没有遇到任何问题,但我想知道是否有更好的方法?每当有新版本的 Kotlin 时,我并不热衷于合并对插件的更改。
查看 nebula-kotlin-plugin。它似乎非常接近您要在那里实现的目标。
这里的问题是 known gradle bug 无法通过 init 脚本中的 id 应用插件。这就是为什么您需要使用完全限定的 class 名称作为解决方法的原因。
例如我在初始化脚本中有以下内容并且它有效:
apply plugin: org.jetbrains.kotlin.gradle.plugin.KotlinPlatformJvmPlugin
顺便说一句,我创建了一个 gradle 插件,用于准备自定义 gradle 发行版,其中包含初始化脚本中定义的通用设置 - custom-gradle-dist。它非常适合我的项目,例如库项目的 build.gradle 看起来像这样(这是一个完整的文件,所有 repository, apply plugin 、dependencies 等设置在初始化脚本中定义):
dependencies {
compile 'org.springframework.kafka:spring-kafka'
}