访问应用的外部脚本

时间:2016-05-05 19:27:54

标签: java gradle build build-process

我最初的目标是能够使用buildscriptbuild.gradle中定义的类路径依赖关系,在使用build.gradle导入apply from:的脚本中。但是,由于无法解析类,因此外部脚本无法编译。在研究了这个问题后,我发现逻辑需要重复,所以我想我会将buildscript提取到一个单独的文件中。然后我就可以在build.gradle内部以及外部脚本中应用它。

我甚至没有成功应用build.gradle中的外部buildscript文件,更不用说从外部脚本应用它了。我尝试了很多东西,但似乎无论我尝试什么,我总是遇到两个问题之一:无法使用来自gradle.properties的属性,或者无法找到插件(即使类路径依赖性)已定义)。

目前我的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会抱怨它无法找到标识为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.gradleother.gradle中应用这个文件。

我在buildSrc中创建了一个自定义插件,以我想要的方式配置项目,结果只是以更复杂的方式失败并得到相同的结果。根本原因是相同的:没有办法将类路径依赖性暴露给外部脚本。

是否有关于此类行为的综合文件?关于这一切的一切都违反了最不惊讶的原则。当我将buildscript移动到另一个文件时,我希望build.gradle中使用apply块来“正常工作”。

关于buildscript块的buildscript语义不明确。此外,insert . . . select本身出现在外部文件中时的语义也不清楚 - 行为有明显的变化,特别是插件和外部属性方面。

处理此问题的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

这有点咆哮,但也有一个解决方案。我能够在不使用单独的buildscript文件的情况下解决此问题,但解决方法令人难以置信的是hackish。我认为这是一个主要的缺点,你不能跨外部脚本共享buildscript依赖。

问题在于没有语义一致性,因为行为似乎取决于您决定如何组织/模块化构建逻辑。如果这是一个已知的问题,需要在文档中的某处特别调用 - 我能够找到这种令人惊讶的行为的唯一方法是从gradle自己的论坛或StackOverflow。我认为期望在单个文件中使用离散单元构建逻辑的构建是不合理的,当这些离散单元被分割为多个文件时,工作。只要语义一致,构建逻辑就不应根据您决定组织文件的方式而有所不同。

我知道可能存在技术限制,但是因为您将逻辑从一个文件移动到另一个文件而导致构建中断是抽象泄漏,因为现在我需要了解这样做的详细信息和复杂性,超出应该的范围< em>合理地期望知道。我甚至不介意是否明确地特别提到这一点,以及解决语法差异的解决方案/解决方法。但是,关于组织构建逻辑的当前文档没有提到这些警告;它只记录了快乐的道路。

/咆哮

所以这是解决方案。我使用扩展名保存了对类本身的引用:

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(...)
}