如何将一个Gradle脚本导入到另一个脚本中?

113
我有一个复杂的Gradle脚本,用于构建和部署多个NetBeans项目到多个环境。该脚本很有效,但基本上是通过半打包含项目和环境信息的映射进行配置的。 我想把这些任务抽象出来到另一个文件中,以便我可以在一个简单的构建文件中定义我的映射,并从另一个文件中导入任务。这样,我就可以为多个项目使用相同的核心任务,并使用简单的一组映射来配置这些项目。 请问有人能告诉我如何像Ant的task一样,在另一个Gradle文件中导入一个Gradle文件吗?我已经查阅了Gradle的文档,但迄今为止没有找到答案。
附加信息: 在Tom的下面回答后,我想澄清一下我的意思。基本上,我有一个Gradle脚本,用于运行多个子项目。然而,这些子项目都是NetBeans项目,并带有它们自己的ant构建脚本,因此我有Gradle任务来调用其中的每一个。我的问题是,我在文件顶部有一些配置,例如:
projects = [
    [name:"MySubproject1", shortname: "sub1", env:"mainEnv", cvs_module="mod1"],
    [name:"MySubproject2", shortname: "sub2", env:"altEnv", cvs_module="mod2"]
]

我随后生成了一些任务,例如:

projects.each({
    task "checkout_$it.shortname" << {
         // Code to for example check module out from cvs using config from 'it'.
    }
})

我有许多这种任务生成代码片段,它们都是通用的- 它们完全取决于项目列表中的配置。

因此,我想要的是一种将其放入单独脚本并以以下方式导入的方法:

projects = [
    [name:"MySubproject1", shortname: "sub1", env:"mainEnv", cvs_module="mod1"],
    [name:"MySubproject2", shortname: "sub2", env:"altEnv", cvs_module="mod2"]
]

import("tasks.gradle") // This will import and run the script so that all tasks are generated for the projects given above.

所以,在这个例子中,tasks.gradle文件将包含所有通用任务生成代码,并将在主build.gradle文件中定义的项目中运行。通过这种方式,tasks.gradle是一个可以被所有由NetBeans ant构建文件组成的大型项目使用的文件。


3
考虑使用 "apply from: 'other.gradle'" 结构导入外部声明。 (请参阅此处的“12.4.使用外部构建脚本配置项目”http://gradle.org/0.9-preview-1/docs/userguide/tutorial_this_and_that.html#sec:configuring_using_external_script) - Petr Gladkikh
@PetrGladkikh apply from 立即执行外部任务。这在执行逻辑中可能不是首选(即,我希望在我想要执行任务时执行,而不是立即执行)。 - IgorGanapolsky
1
上面的评论中这个声明是不正确的apply from 立即执行外部任务。不要被误导了。外部任务只是被配置,而不是被执行。 - Jarekczek
5个回答

147

2
apply from不允许我在包含的文件中使用插件{}。 - Gavriel

17

回答这个问题的方法在插件系统中,你可以在一组插件中添加所需功能,这些插件可以是 Groovy 文件,位于目录 buildSrc/src/main/groovy 中。插件也可以被打包为 Jar 文件,虽然我没有尝试过。

详细信息请参阅: 自定义插件


只是让你知道链接已经失效了 - 这里有一个更新:http://gradle.org/docs/current/userguide/userguide_single.html#sec:configuring_using_external_script - JARC
插件链接:http://gradle.org/docs/current/userguide/userguide_single.html#custom_plugins - JARC
buildSrc/src/main/groovy 不允许我使用版本化的插件。 - Gavriel
或者一个更简单的方法是 buildscript.sourceFile(请参见我下面的答案) - yuyu5

5

很难在没有看到您的构建文件的情况下确定最适合您的是什么。

我可以假设将您的环境设置为多项目构建应该为您提供所需的抽象。

在您的项目根目录下的build.gradle文件中,您定义了所有特定于域的内容以及适用于所有子项目的内容:

repositories {
    add(new org.apache.ivy.plugins.resolver.FileSystemResolver()) {
        name = 'destRepo'
        addIvyPattern( file( project.properties['repo.dest.dir']).absolutePath + '/[organisation]/[module]/ivys/ivy(-[revision]).xml')
        addArtifactPattern( file( project.properties['repo.dest.dir']).absolutePath + '/[organisation]/[module]/[type]s/[artifact](-[revision]).[ext]')
        descriptor = 'optional'
        checkmodified = true
    }
    ...
}
...
subprojects {
    sourceCompatibility = 1.5
    targetCompatibility = 1.5
    group = 'my.group'
    version = '1.0'
    uploadArchives {
        uploadDescriptor = true
        repositories {
            add rootProject.repositories.destRepo
        }
    }
    apply{ type my.group.gradle.api.plugins.MyPlugin }
    ...
}

dependsOnChildren()

项目根目录可能还包含一个 gradle.properties 文件,您可以在其中定义项目使用的属性。
buildDirName=staging
repo.dest.dir=/var/repo
...

然后,在名为settings.gradle的项目根目录下的另一个文件中,您实际上是指向您的子项目:

include 'my-first-component',
        'my-second-component'
...
project(':my-first-component').projectDir = new File(rootDir, 'path/to/first/component')
project(':my-second-component').projectDir = new File(rootDir, 'path/to/second/component')
...

每个子项目目录都包含一个build.gradle文件,其中只包含特定于子项目的内容。
无论您是从项目根目录还是子项目目录调用gradle,gradle都会自动考虑在各个文件中完成的所有定义。
还请注意,在根级别未加载任何插件之前,不会为您的项目根目录执行任何编译任务。

1
感谢您抽出时间回答。我遇到的问题不是子项目,而是创建一个常见任务的“库”。我已编辑了原始问题,并添加了更多信息和代码片段以使事情更清晰。 - Anthony Roy
1
所以,与其从您的示例中执行import("tasks.gradle"),您应该有subprojects{}部分,指定所有子项目使用的通用任务生成代码。这应该提供您正在寻找的相同抽象层!? - Tom
这里真的需要使用Ivy插件吗?不能只使用Gradle吗? - IgorGanapolsky

4

这是一个关于Kotlin DSL(build.gradle.kts)的示例。

apply(from = "scripts/my-script.gradle.kts")

scripts/my-script.gradle.kts:

println(
    """
    I am defined at the top level of the script and
    executed at the configuration phase of build process
    """
)

tasks.create("MyTask") {
    println(
        """
        I am defined in a task and
        run at the configration phase of build process"""
    )
    doLast {
        // ...
    }
}

请参考此答案此答案,了解如何在Kotlin DSL中从另一个脚本导入函数。

0

根据这个类似的问题/答案,在搜索了几天后我找到的最简单的解决方案是使用buildscript.sourceFile。它可以正确地给出正在运行的文件,而不是该进程的pwd/cwd/父文件。我觉得这可能会解决你的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接