在ProcessResources内循环Gradle并过滤

时间:2016-07-21 07:59:47

标签: gradle groovy build.gradle

在jar任务中,我想替换conf文件中的一些文本。

jar {
    ext {
        excludedClasses = ["com.MyClass1", "com.MyClass2"]
    }
    doFirst {
        println 'Jar task started execution'
        println 'Excluded classes ' + excludedClasses
        exclude(excludedClasses)
    }
    doLast {
        println 'Jar task finished execution'
    }
    processResources {
       filesMatching('**/moduleconfiguration/conf.json') { f ->
            excludedClasses.each { c ->
               filter {
                    println it
                    it.replace(c, "com.MyClass3")
               }
            }
        }
    }
}

但是上面的代码试图从所有* .class文件中替换c,导致非法的jar。我希望它只能在' ** / moduleconfiguration / conf.json'中进行替换。文件。

我怎样才能做到这一点?

更新

看起来我遇到了同样的问题:https://issues.gradle.org/browse/GRADLE-1566。如果我在each内使用processResources循环,则此问题已得到解决但又重新出现。

与此同时,我找到了两个问题的解决方案如下:

解决方案1:更改filtereach循环的顺序。即在filter

内循环
filesMatching('**/moduleconfiguration/conf.json') { f ->
     filter {
        excludedClasses.each { c ->
            println it
            it = it.replace(c, "com.MyClass3")
       }
       it
    }
}

解决方案2:使用正则表达式而不是each循环

filesMatching('**/moduleconfiguration/conf.json') { f ->
     filter {
         println it
         def regex = excludedClasses.join("|")  // watch for .(dot) or other regex chars here
         it.replaceAll(regex, "com.MyClass3")
    }
}

如果我在each方法闭包中使用filesMatching循环,我仍然想知道为什么过滤的范围会改变所有文件。这是一个时髦的东西还是一个混乱的东西?如果有人能解释那里发生的事情,我将非常感激。

更新2

println代表值的输出,此代理和所有者在不同位置输出有问题的案例:

:processResources

Inside filesMatching. delegate:file '.../configuration/conf.json' this:root project 'projectName' owner:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90@6f3e18b8

Problematic Case inside loop before filter. delegate:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91@4587ec31 this:root project 'projectName' owner:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91@4587ec31

Problematic Case inside loop before filter. delegate:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91@4587ec31 this:root project 'projectName' owner:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91@4587ec31

:classes
:jar
Jar task started execution

Excluded classes [MyClass1.class, MyClass2.class]

Problematic Case inside loop inside filter. delegate:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91_closure92@3a0d0128 this:root project 'projectName' owner:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91_closure92@3a0d0128
.
.
.
.
.

println代表值的输出,此代理和所有者在解决方案1的不同位置输出:

:processResources

Inside filesMatching. delegate:file '.../configuration/conf.json' this:root project 'projectName' owner:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90@6ece61a3

Solution 1 Inside filter before loop. delegate:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91@64af2ad7 this:root project 'projectName' owner:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91@64af2ad7

Solution 1 Inside filter inside loop. delegate:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91_closure92@22c74276 this:root project 'projectName' owner:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91_closure92@22c74276

Solution 1 Inside filter inside loop. delegate:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91_closure92@22c74276 this:root project 'projectName' owner:build_95q5jrf5z5ao0hk03tsevn2t0$_run_closure10_closure90_closure91_closure92@22c74276
.
.
.
.
.
:classes
:jar
Jar task started execution
Excluded classes [MyClass1.class, MyClass2.class]

1 个答案:

答案 0 :(得分:0)

更新

根据您的第二次更新和我的一些测试,它似乎不是我最初建议的。它确实似乎是代表团的事情,但我无法确定它。

您可以通过将filter {行更改为f.filter {来说明原始(有问题)示例的不同之处。这明确地尝试执行FileCopyDetails#filter方法,而不是在范围内发生的任何一种方法。

您应该能够看到,在调用f.filter时,只会过滤匹配的文件。当您自己调用filter时,它正在调用任务级别1。但是,由于您已经处于复制文件的中间,因此它仅将过滤器应用于在第一个匹配后按字母顺序排列的文件。

例如,如果您有此文件夹结构:

+ resources/main
  - abc.json
  - configuration.json
  - def.json
  - efg.json

def.jsonefg.json将被过滤,但前两个不会。

这仍然无法回答为什么它没有调用正确的filter方法,但它至少确认它正在调用任务级别。

原始答案

我认为这是由于Groovy闭包委托给不同的对象。我相信你实际上是在原始(有问题的)情况下调用Copy#filter,在两个解决方案中调用FileCopyDetails#filter。复制任务的filter方法会对所有内容应用过滤器,而详细信息filter方法将用于filesMatching中的特定文件。

您应该能够通过打印出来来说明不同的代表:

<强>原始

processResources {
    filesMatching('**/moduleconfiguration/conf.json') { f ->
        excludedClasses.each { c ->
            // print the class of this closure's delegate
            println delegate.class
            filter {
                it.replace(c, "com.MyClass3")
            }
        }
    }
}

解决方案1 ​​

filesMatching('**/moduleconfiguration/conf.json') { f ->
     filter {
        // print the class of this closure's delegate
        println delegate.class
        excludedClasses.each { c ->
            println it
            it = it.replace(c, "com.MyClass3")
       }
       it
    }
}

我的期望是,您会看到原来的Copy任务授权(即processResources)以及委托给FileCopyDetails的解决方案。默认情况下,Groovy中的所有闭包都由声明它们的对象“拥有”,并且还将“委托”给所有者。当Gradle具有以闭包作为参数的API时(例如filter方法),它们通常被重新配置为具有特定委托(通常是封闭容器对象)并使用“委托优先”策略来查找方法

请参阅Groovy关于delegation strategies的文档。

相关问题