如何使Gradle扩展延迟评估由任务动态设置的属性?

Tag*_*agc 8 gradle gradle-plugin

我很擅长使用Gradle,我正在尝试开发一个有助于管理版本编号的插件.此插件定义了一个任务,用于设置project.version应用于其的项目的属性.

我要做的是使它在每个Gradle构建的开始处设置此属性.使用Peter对另一个Gradle问题的回答,我已经设法通过gradle.startParameter.taskNames = [":setProjectVersionNumber"] + gradle.startParameter.taskNames在我的插件中添加我的任务来执行任何其他任务apply方法中.

但是,其他插件(特别是'Maven-publish')依赖于在配置阶段指定的版本:

publishing {
    publications {
        somePublication(MavenPublication) {
            version = project.version
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道的是,如果有一种方法可以使version这些扩展中的属性评估尽可能地懒惰 - 这样它们就不会被调用,直到调用依赖于它们的任务,在这种情况下可能是:publishToMavenLocal.

下面是一个SSCCE,它展示了我希望实现的目标:

// This would be included within the plugin
class SetProjectVersionNumber extends DefaultTask {

    @TaskAction
    void start() {
        // This will set project.version during execution phase
        project.version = "1.2.3"
        logger.info "Set project version number: $project.version"
    }
}

task setProjectVersionNumber(type: SetProjectVersionNumber)

// Imagine this block being replaced by a maven 'publishing' block (or something similar)
ext {
    version = project.version

    // This will print 'unspecified', as it's evaluated during configuration phase
    println "In extension, setting version=$project.version"
}
Run Code Online (Sandbox Code Playgroud)

如果你能在上面的例子中提供一个ext.version平等的方法1.2.3,我相信你已经解决了我的问题.

如果这要求太多,我可能会让我的插件在配置时而不是执行时生成版本字符串.不过,知道我是否可以这样做会很高兴.

编辑

在一个实验分支中,我尝试将所有版本字符串分配逻辑移动到配置阶段(通过在插件应用程序期间而不是在任务执行期间完成),但我不相信这会起作用,因为插件扩展没有尚未处理并尝试引用其中定义的属性失败.

编辑2

将版本字符串赋值逻辑包装在一个 project.afterEvaluate闭包中似乎有效:

@Override
public void apply(Project project) {
    logger = project.logger
    project.extensions.create(EXTENSION_NAME, SemVerPluginExtension)

    project.afterEvaluate {
        setVersionProjectNumber(project)
        addTasks(project)
    }
}
Run Code Online (Sandbox Code Playgroud)

在模拟项目中,我实现了 build.gradle如下:

apply plugin: 'semver'
apply plugin: 'maven-publish'

group = 'temp'

buildscript {
    repositories {
        mavenLocal()
        jcenter()
    }
    dependencies {
        classpath 'com.github.tagc:semver-plugin:0.2.2'
    }
}

semver {
    versionFilePath = 'version.properties'
}

publishing {
    publications {
        testPublication(MavenPublication) {
            version = project.version
            assert version
            println "Set publication version to $version"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

出于某种原因,这似乎有效.虽然版本字符串赋值逻辑包含在'afterEvaluate'闭包中,而测试发布版本分配不包含,但前者仍然在后者之前发生:

Compiling build file '/Users/davidfallah/Documents/semver/TestSemver2/build.gradle' using StatementExtractingScriptTransformer.
Compiling build file '/Users/davidfallah/Documents/semver/TestSemver2/build.gradle' using BuildScriptTransformer.
VERSION FILE PATH=version.properties
Current Git branch: develop
Set project version to 0.2.1-SNAPSHOT
Set publication version to 0.2.1-SNAPSHOT
All projects evaluated.
Run Code Online (Sandbox Code Playgroud)

我将这个问题保持开放和未解决,因为我仍然想知道是否可以按照我原先的意图去做.另外,我很感激为什么在项目版本设置之后分配出版物版本的任何解释,以及我是否可以依赖于总是如此,或者现在是否恰好发生了.

Rob*_*tts 4

您可以使用GString 的延迟实例化来在运行时评估属性:

project.tasks.create("example_task", Exec.class, {
    commandLine 'echo', "${-> project.someproperty}"
})
Run Code Online (Sandbox Code Playgroud)

请注意,您必须使用引号而不是撇号 -"${...}"可以,但'${...}'不行。