在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:更改filter
和each
循环的顺序。即在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]
答案 0 :(得分:0)
根据您的第二次更新和我的一些测试,它似乎不是我最初建议的。它确实似乎是代表团的事情,但我无法确定它。
您可以通过将filter {
行更改为f.filter {
来说明原始(有问题)示例的不同之处。这明确地尝试执行FileCopyDetails#filter
方法,而不是在范围内发生的任何一种方法。
您应该能够看到,在调用f.filter
时,只会过滤匹配的文件。当您自己调用filter
时,它正在调用任务级别1。但是,由于您已经处于复制文件的中间,因此它仅将过滤器应用于在第一个匹配后按字母顺序排列的文件。
例如,如果您有此文件夹结构:
+ resources/main
- abc.json
- configuration.json
- def.json
- efg.json
def.json
和efg.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的文档。