我最初的目标是能够在导入到using的脚本中使用inbuildscript
中定义的类路径依赖项。但是,由于无法解析类,因此外部脚本无法编译。在研究了这个问题之后,我发现逻辑需要重复,因此我认为我将提取到一个单独的文件中。然后,我将可以在内部脚本中也可以在外部脚本中应用它。build.gradle
build.gradle
apply from:
buildscript
build.gradle
我什至没有成功地从中应用外部buildscript文件build.gradle
,更不用说从外部脚本中应用它了。我已经尝试了多种方法,但是无论如何尝试,似乎总是会遇到两个问题之一:gradle.properties
无法使用from的属性,或者找不到插件(即使已定义了classpath依赖关系)。
目前,我的gradle/buildscript.gradle
文件如下所示:
buildscript {
repositories {
maven { url "http://some.url.com" }
}
dependencies {
classpath "my.gradle.plugin:gradle-plugin:1.0.0"
classpath "my.library:my-library:$libraryVersion"
}
}
libraryVersion
已在中定义gradle.properties
。我build.gradle
的如下:
buildscript {
apply from: "gradle/buildscript.gradle"
}
apply plugin: 'my.gradle.plugin.PluginClass'
当我这样做时,gradle抱怨找不到ID为的插件my.gradle.plugin.PluginClass
。我尝试删除引号,并且还尝试project.plugin.apply(...)
使用带引号和不带引号的插件的FQN。两者均导致gradle错误并显示一条消息,指出它无法my
在根项目中找到该属性。
我也尝试过:
buildscript {
apply from: "gradle/buildscript.gradle", to: buildscript
}
apply plugin: 'my.gradle.PluginClass'
但是,这会导致另一个错误的gradle哪里抱怨它不能解析libraryVersion
在gradle/buildscript.gradle
。所以我尝试了这个:
buildscript {
ext.libraryVersion = "1.0.1"
repositories {
maven { url "http://some.url.com" }
}
dependencies {
classpath "my.gradle.plugin:gradle-plugin:1.0.0"
classpath "my.library:my-library:$libraryVersion"
}
}
这会导致另一个错误,其中gradle这个说有没有这样的属性ext
上buildscript
。我知道这是因为确实是没有“项目”可言的,因为它buildscript
是单独编译的。然后我将代码buildscript
块改build.gradle
回:
buildscript {
apply from: "gradle/buildscript.gradle"
}
现在我没有收到ext
错误,但仍然收到一条错误消息,提示它找不到具有指定ID的插件。
我不能硬编码libraryVersion
里面buildscript
,因为我需要它作为一个编译时依赖build.gradle
,我宁愿没有保持它在两个地方。
这是非常令人困惑和沮丧的,因为以下代码buildscript
块本身在以下方面可以正常工作build.gradle
:
buildscript {
ext.libraryVersion = "1.0.1"
repositories {
maven { url "http://some.url.com" }
}
dependencies {
classpath "my.gradle.plugin:gradle-plugin:1.0.0"
classpath "my.library:my-library:$libraryVersion"
}
}
apply plugin: 'my-plugin-id' //No need to use FQN
dependencies {
compile "my.library:library-version:$libraryVersion"
}
我尝试拆分该buildscript
块的原因是因为我有一个文件other.gradle
,其中包含一些使用以下类的自定义任务my.library
:
import my.library.SomeThing
task customTask(type: DefaultTask) {
//does something with SomeThing
}
但是,当我离开buildscript
块build.gradle
并应用另一个文件时,如下所示:
buildscript {
ext.libraryVersion = "1.0.1"
repositories {
maven { url "http://some.url.com" }
}
dependencies {
classpath "my.gradle.plugin:gradle-plugin:1.0.0"
classpath "my.library:my-library:$libraryVersion"
}
}
apply plugin: 'my-plugin-id' //No need to use FQN
dependencies {
compile "my.library:my-library:$libraryVersion"
}
apply from: 'gradle/other.gradle'
我从gradle中得到一个错误,说它无法解决该类my.library.SomeThing
。我认为我可以解决这个问题,并通过有一个通用buildscript
文件避免重复,然后将其应用于build.gradle
和other.gradle
。
我在内部创建了一个自定义插件,buildSrc
以按我想要的方式配置项目,但最终以更复杂的方式失败,导致结果相同。根本原因是相同的:无法将类路径依赖项暴露给外部脚本。
是否有关于此类行为的综合文档?关于此的一切都违反了最小惊奇原则。当我将其移动到另一个文件时,我期望buildscript
它会被用来build.gradle
“正常工作”。
apply
关于buildscript
块的语义尚不清楚。此外,buildscript
当它出现在外部文件中时,其自身的语义也不明确-行为存在明显的变化,尤其是在插件和外部属性方面。
处理此问题的最佳方法是什么?
这有点麻烦,但是也有解决方案。我能够解决此问题而无需使用单独的buildscript
文件,但是解决方法令人难以置信地令人讨厌。我认为这是一个主要缺点,您无法在外部脚本之间共享buildscript依赖关系。
问题在于没有语义上的一致性,因为行为似乎取决于您决定如何组织/模块化构建逻辑。如果这是一个已知问题,则需要在文档中的某个地方特别注明-我能够找到提及这种令人惊讶行为的唯一方法是来自gradle自己的论坛或StackOverflow。我认为期望可以在单个文件中使用构建逻辑的离散单元的构建并在将这些离散单元拆分为多个文件时也可以运行是不合理的。只要语义是一致的,构建逻辑就不会根据您决定组织文件的方式而有所不同。
我知道这可能会有技术限制,但是由于您将逻辑从一个文件移动到另一个文件而导致构建中断是抽象泄漏,因为现在我必须知道这样做的细节和复杂性,超出了应该合理预期的范围。我什至都不介意是否明确,明确地指出这一点,以及弥合语义差异的解决方案/变通办法。但是,有关组织构建逻辑的最新文档没有提到这些警告。它只记录了幸福的道路。
/ rant
所以这是解决方案。我通过使用扩展保存了对类本身的引用:
import my.library.SomeThing
import my.library.SomeOtherThing
buildscript {
ext.libraryVersion = "1.0.1"
repositories {
maven { url "http://some.url.com" }
}
dependencies {
classpath "my.gradle.plugin:gradle-plugin:1.0.0"
classpath "my.library:my-library:$libraryVersion"
}
}
apply plugin: 'my-plugin-id' //No need to use FQN
ext.SomeThing = SomeThing
ext.SomeOtherThing = SomeOtherThing
dependencies {
compile "my.library:my-library:$libraryVersion"
}
apply from: 'gradle/other.gradle'
然后在other.gradle
:
// Necessary; you can't just use ext.SomeThing in the task later because
// it is available at compile-time, but apparently not at runtime. Although
// it does work if you use project.ext.SomeThing. However, I just found this
// to be more convenient.
def SomeThing = ext.SomeThing
def SomeOtherThing = ext.SomeOtherThing
task someTask(type: DefaultTask) {
// You have to use def; you cannot use the actual type because
// it is not available at compile-time. Also, since you only
// have a class object, you cannot use "new" directly; you have to
// create a new instance by calling newInstance() on the class object
def someThing = SomeThing.newInstance(...)
// If you are calling static methods you can invoke them directly
// on the class object. Again, you have to use def if the return
// type is something defined within my-library.
def foo = SomeOtherThing.staticMethod(...)
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句