为什么我不能在应用文件中使用 Gradle DSL
Why can't I use Gradle DSL in apply'ed files
在我们的团队中,我们有很多项目是用 Gradle 构建的。 Gradle 文件中的某些部分完全相同。例如,我们在所有项目中都使用 Java 11。所以我的想法是我可以将我的 build.gradle 文件拆分成一个公共部分,然后从中央存储库同步到每个 Gradle 项目,而项目特定部分保留在 build.gradle 中。
build.gradle:
plugins {
id 'java'
//...
}
apply from: "common.gradle.kts"
dependencies {
// ...
}
common.gradle.kts
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
test {
useJUnitPlatform()
}
现在我收到 Gradle
的错误消息
* Where:
Script '/Users/.../common.gradle.kts' line: 4
* What went wrong:
Script compilation errors:
Line 04: java {
^ Expression 'java' cannot be invoked as a function. The function 'invoke()' is not found
Line 04: java {
^ Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val PluginDependenciesSpec.java: PluginDependencySpec defined in org.gradle.kotlin.dsl
Line 05: toolchain {
^ Unresolved reference: toolchain
Line 06: languageVersion = JavaLanguageVersion.of(11)
^ Unresolved reference: languageVersion
Line 09: test {
^ Unresolved reference: test
Line 10: useJUnitPlatform()
^ Unresolved reference: useJUnitPlatform
6 errors
对于某些配置,我找到了一个使用更通用的 API 的替代方案,虽然要找到相应的替代方案需要付出很多努力,但最终没有人能保证它们做的完全一样东西:
tasks.withType<JavaCompile> {
options.release.set(11)
}
所以问题仍然存在:为什么我不能在我的外化 common.gradle.kts 中使用 DSL 函数 java
或 test
?
似乎它必须使用 Kotlin 脚本来做一些事情,至少如果我对我的外部化脚本也使用 Groovy,它就可以工作。
在您的 common.gradle.kts
中,java { }
生成了辅助 Kotlin DSL 函数。 Gradle 不知道 Kotlin DSL 助手,除非
- 它是构建的一部分(不使用
apply(from = "...")
- 已应用 java 插件
Understanding when type-safe model accessors are available
Only the main project build scripts and precompiled project script plugins have type-safe model accessors. Initialization scripts, settings scripts, script plugins do not. These limitations will be removed in a future Gradle release.
对插件的反应
https://docs.gradle.org/current/userguide/implementing_gradle_plugins.html#reacting_to_plugins
仍然可以使用您的 common.gradle.kts
- 但它需要在没有 Kotlin DSL 的情况下配置 Java 插件
// common.gradle.kts
plugins.withType(JavaBasePlugin::class).configureEach {
// the project has the Java plugin
project.extensions.getByType<JavaPluginExtension>().apply {
toolchain {
languageVersion.set(JavaLanguageVersion.of(11))
}
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
}
这有点笨拙,因为 Kotlin DSL 助手不可用。
buildSrc 约定插件
如果您想为单个项目创建约定,那么标准方法是创建 buildSrc 约定插件。
https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources
这最适合有很多子项目的项目。
// $projectRoot/buildSrc/src/main/kotlin/java-convention.gradle.kts
plugins {
java
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
test {
useJUnitPlatform()
}
查看此处的答案了解更多详情:
在项目之间共享插件
https://docs.gradle.org/current/userguide/implementing_gradle_plugins.html
可以在项目之间共享约定插件,只要您有一个 Maven 存储库来部署您的插件。
甚至可以创建自己的 Gradle 发行版,因此插件与 Gradle 包装器一起包含在内! https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:custom_gradle_distribution
但是我建议不要使用这些方法。一般来说,创建共享插件所花费的时间永远不会比仅仅复制和粘贴 buildSrc 约定插件更快。更重要的是,最好保持项目独立。虽然共享构建约定似乎是个好主意,但它引入了依赖关系,这使得跟踪问题变得困难,并使更新共享插件变得困难,因为你不确定后果可能是什么。本文解释更多https://phauer.com/2016/dont-share-libraries-among-microservices/
在我们的团队中,我们有很多项目是用 Gradle 构建的。 Gradle 文件中的某些部分完全相同。例如,我们在所有项目中都使用 Java 11。所以我的想法是我可以将我的 build.gradle 文件拆分成一个公共部分,然后从中央存储库同步到每个 Gradle 项目,而项目特定部分保留在 build.gradle 中。
build.gradle:
plugins {
id 'java'
//...
}
apply from: "common.gradle.kts"
dependencies {
// ...
}
common.gradle.kts
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
test {
useJUnitPlatform()
}
现在我收到 Gradle
的错误消息* Where:
Script '/Users/.../common.gradle.kts' line: 4
* What went wrong:
Script compilation errors:
Line 04: java {
^ Expression 'java' cannot be invoked as a function. The function 'invoke()' is not found
Line 04: java {
^ Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val PluginDependenciesSpec.java: PluginDependencySpec defined in org.gradle.kotlin.dsl
Line 05: toolchain {
^ Unresolved reference: toolchain
Line 06: languageVersion = JavaLanguageVersion.of(11)
^ Unresolved reference: languageVersion
Line 09: test {
^ Unresolved reference: test
Line 10: useJUnitPlatform()
^ Unresolved reference: useJUnitPlatform
6 errors
对于某些配置,我找到了一个使用更通用的 API 的替代方案,虽然要找到相应的替代方案需要付出很多努力,但最终没有人能保证它们做的完全一样东西:
tasks.withType<JavaCompile> {
options.release.set(11)
}
所以问题仍然存在:为什么我不能在我的外化 common.gradle.kts 中使用 DSL 函数 java
或 test
?
似乎它必须使用 Kotlin 脚本来做一些事情,至少如果我对我的外部化脚本也使用 Groovy,它就可以工作。
在您的 common.gradle.kts
中,java { }
生成了辅助 Kotlin DSL 函数。 Gradle 不知道 Kotlin DSL 助手,除非
- 它是构建的一部分(不使用
apply(from = "...")
- 已应用 java 插件
Understanding when type-safe model accessors are available
Only the main project build scripts and precompiled project script plugins have type-safe model accessors. Initialization scripts, settings scripts, script plugins do not. These limitations will be removed in a future Gradle release.
对插件的反应
https://docs.gradle.org/current/userguide/implementing_gradle_plugins.html#reacting_to_plugins
仍然可以使用您的 common.gradle.kts
- 但它需要在没有 Kotlin DSL 的情况下配置 Java 插件
// common.gradle.kts
plugins.withType(JavaBasePlugin::class).configureEach {
// the project has the Java plugin
project.extensions.getByType<JavaPluginExtension>().apply {
toolchain {
languageVersion.set(JavaLanguageVersion.of(11))
}
}
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
}
这有点笨拙,因为 Kotlin DSL 助手不可用。
buildSrc 约定插件
如果您想为单个项目创建约定,那么标准方法是创建 buildSrc 约定插件。
https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:build_sources
这最适合有很多子项目的项目。
// $projectRoot/buildSrc/src/main/kotlin/java-convention.gradle.kts
plugins {
java
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
test {
useJUnitPlatform()
}
查看此处的答案了解更多详情:
在项目之间共享插件
https://docs.gradle.org/current/userguide/implementing_gradle_plugins.html
可以在项目之间共享约定插件,只要您有一个 Maven 存储库来部署您的插件。
甚至可以创建自己的 Gradle 发行版,因此插件与 Gradle 包装器一起包含在内! https://docs.gradle.org/current/userguide/organizing_gradle_projects.html#sec:custom_gradle_distribution
但是我建议不要使用这些方法。一般来说,创建共享插件所花费的时间永远不会比仅仅复制和粘贴 buildSrc 约定插件更快。更重要的是,最好保持项目独立。虽然共享构建约定似乎是个好主意,但它引入了依赖关系,这使得跟踪问题变得困难,并使更新共享插件变得困难,因为你不确定后果可能是什么。本文解释更多https://phauer.com/2016/dont-share-libraries-among-microservices/