如何在Groovy编写的Gradle插件中计算XML定义的Ant Fileset
在Gradle插件中用Groovy解析XML里的Ant Fileset
其实这个需求实现起来挺顺畅的——毕竟Gradle天生就和Ant深度集成,Groovy处理XML又灵活得不行。下面给你一套最简的实现方案,分步骤来:
1. 用XmlSlurper解析XML文件
首先你需要把包含Fileset的XML文档读进来,用Groovy的XmlSlurper来解析,它能通过GPath表达式轻松定位到目标节点。假设你的XML结构大概是这样:
<config> <fileset dir="src/main/java" includes="**/*.java" excludes="**/test/**"> <include name="**/utils/**"/> <exclude name="**/deprecated/**"/> </fileset> </config>
那解析代码可以这么写:
def xmlFile = project.file('path/to/your/config.xml') // 用Gradle的file方法获取文件实例 def config = new XmlSlurper().parse(xmlFile) def filesetNodes = config.fileset // 直接定位所有fileset节点
2. 把XML节点映射到Ant Fileset并计算匹配文件
Gradle的project.ant对象直接提供了Ant任务的调用能力,我们可以把XML里的Fileset属性、子节点一一映射到Ant的fileset任务上,然后就能拿到匹配的文件列表了。
基础版(处理简单属性和直接子节点)
filesetNodes.each { filesetNode -> // 初始化Ant Fileset,先传入dir、includes、excludes这些顶层属性 def antFileset = project.ant.fileset( dir: filesetNode.@dir.text(), includes: filesetNode.@includes.text(), excludes: filesetNode.@excludes.text() ) // 处理子节点里的<include>和<exclude> filesetNode.include.each { include -> antFileset.include(name: include.@name.text()) } filesetNode.exclude.each { exclude -> antFileset.exclude(name: exclude.@name.text()) } // 把Ant返回的文件转换成Gradle的File对象集合 def matchedFiles = antFileset.files.collect { new File(it.absolutePath) } // 这里就可以对文件做自定义操作了,比如打印、传给其他任务 println "匹配到的文件:${matchedFiles.size()}个" matchedFiles.each { println it.name } }
进阶版(处理嵌套的patternset)
如果你的XML里有嵌套的<patternset>节点,也能轻松处理:
filesetNodes.each { filesetNode -> def antFileset = project.ant.fileset(dir: filesetNode.@dir.text()) // 处理根节点的includes/excludes属性 if (filesetNode.@includes.text()) { antFileset.includes = filesetNode.@includes.text() } if (filesetNode.@excludes.text()) { antFileset.excludes = filesetNode.@excludes.text() } // 处理直接的include/exclude子节点 filesetNode.include.each { antFileset.include(name: it.@name.text()) } filesetNode.exclude.each { antFileset.exclude(name: it.@name.text()) } // 处理嵌套的patternset filesetNode.patternset.each { patternset -> patternset.include.each { antFileset.include(name: it.@name.text()) } patternset.exclude.each { antFileset.exclude(name: it.@name.text()) } // 也支持patternset本身的includes/excludes属性 if (patternset.@includes.text()) { antFileset.includes += ",${patternset.@includes.text()}" } if (patternset.@excludes.text()) { antFileset.excludes += ",${patternset.@excludes.text()}" } } def matchedFiles = antFileset.files.collect { new File(it.absolutePath) } // 后续自定义逻辑... }
3. 集成到Gradle插件中
如果是写Gradle插件,你可以把这段逻辑封装到自定义Task里,比如:
class ProcessXmlFilesetTask extends DefaultTask { @InputFile File configXml @TaskAction void processFileset() { def config = new XmlSlurper().parse(configXml) def filesetNodes = config.fileset filesetNodes.each { filesetNode -> def antFileset = project.ant.fileset(dir: filesetNode.@dir.text()) // 这里添加上面的属性和子节点处理逻辑... def matchedFiles = antFileset.files.collect { new File(it.absolutePath) } project.logger.lifecycle("从XML Fileset匹配到 ${matchedFiles.size()} 个文件") } } } // 在插件里注册任务 void apply(Project project) { project.tasks.register('processXmlFileset', ProcessXmlFilesetTask) { configXml = project.file('config.xml') } }
这套方案完全利用了Groovy的XML处理能力和Gradle对Ant的内置支持,代码简洁还能完美复用XML里的Fileset定义。
内容的提问来源于stack exchange,提问作者Jörn Guy Süß
相关产品推荐
相关产品推荐

