【问题标题】:How to extend the behavior of a Gradle task for a new task type?如何为新任务类型扩展 Gradle 任务的行为?
【发布时间】:2015-04-29 15:36:16
【问题描述】:

我想为一些测试任务设置一些东西。更具体地说,我想添加一些环境变量和一些系统属性,也许还有一些其他的东西,例如“依赖项”或“workingDir”。使用常规的Test 任务,我可以做到这一点,

task test1(type:Test, dependsOn:[testPrep,testPrep1]){
     workingDir testWorkingPath
     systemProperty 'property','abs'
     environment.find { it.key ==~ /(?i)PATH/ }.value += (System.properties['path.separator'] + myLibPath)
     environment.LD_LIBRARY_PATH = "/usr/lib64:/lib64:${myLibPath}:" + environment.LD_LIBRARY_PATH
 }

task test2(type:Test, dependsOn:[testPrep]){
     workingDir testWorkingPath
     systemProperty 'property','abs'
     environment.find { it.key ==~ /(?i)PATH/ }.value += (System.properties['path.separator'] + myLibPath)
     environment.LD_LIBRARY_PATH = "/usr/lib64:/lib64:${myLibPath}:" + environment.LD_LIBRARY_PATH
     systemPropety 'newProperty','fdsjfkd'
 }

如果有一个新的任务类型MyTestType 扩展常规的测试任务类型,那将是很好的,其中定义了通用定义。

task test1(type:MyTestType){
     dependsOn testPrep1
 }

task test2(type:MyTestType){
     systemPropety 'newProperty','fdsjfkd'
 } 

最好的方法是什么? execute() 方法似乎是最终的,无法扩展。我需要做类似doFirst 的操作来设置这些属性。我应该在构造函数中添加所有额外的值吗?我可以使用其他任何钩子吗?谢谢。

【问题讨论】:

    标签: groovy gradle task


    【解决方案1】:

    一般来说,您可以扩展“测试”任务并实现您的自定义

    task test1(type:MyTestType){
    }
    
    task test2(type:MyTestType){
         systemProperty 'newProperty','fdsjfkd'
    }
    
    class MyTestType extends Test {
        public MyTestType(){
            systemProperty 'property','abs'
        }
    }
    

    或者,您可以使用更少的样板配置Test 类型的所有任务:

    // will apply to all tasks of type test. 
    // regardless the task was created before this snippet or after
    tasks.withType(Test) {
       systemProperty 'newProperty','fdsjfkd'   
    }
    

    【讨论】:

    • 非常感谢。我更喜欢第二个。似乎第一种方法违反了一个经常被引用的原则,即“不要在构造函数中调用可覆盖的方法”,尽管它可能并不重要,因为 systemProperty 方法非常安全。此外,所有上下文都不再可用,如果我需要项目中的任何属性,我必须一直致电getProject()。
    【解决方案2】:

    还可以指定特定超类设置的行为。比如说你想集中 environment.find 块,但允许像这样为每个任务设置 myLibPath:

    task test1(type: MyTestType) {
    }
    task test2(type: MyTestType) {
      libPath = '/foo/bar'
    }
    

    您可以通过覆盖configure 方法来做到这一点:

    class MyTestType {
      @Input def String libPath
    
      @Override
      public Task configure(Closure configureClosure) {
        return super.configure(configureClosure >> {
          environment.find { it.key ==~ /(?i)PATH/ }.value += (System.properties['path.separator'] + (libPath ?: myLibPath))
        })
      }
    }
    

    这里我们使用closure composition 运算符>> 将传入的闭包与我们重写的行为结合起来。用户指定的configureClosure 将首先运行,可能设置libPath 属性,然后我们运行environment.find 块之后。这也可以与构造函数中的软默认值结合使用,如Rene Groeschke's answer

    请注意,如果您配置多个任务,此特定用例可能会中断,因为 environment.find 语句会转换现有状态而不是替换它。

    【讨论】:

    • 有趣,但在我的情况下,配置被调用得太早:( :(
    【解决方案3】:

    你可以通过以下方式做到这一点

    任务测试扩展{ 测试 { 系统属性'newProperty','fdsjfkd' } }

    注意:这只是添加到 Test 的配置方法中 来源:https://docs.gradle.org/current/dsl/org.gradle.api.Task.html#N18D18

    【讨论】:

    • 我不知道如何在 Kotlin DSL 中做到这一点!这将如何运作?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-13
    • 2023-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多