如何在Gradle中应用补丁文件?

时间:2013-06-12 11:16:43

标签: gradle patch

我有一个Gradle构建脚本,可以成功构建我的项目并编译我需要的所有工件。

但是,在某些情况下,我想让其他开发人员选择修补一些文件。例如,在其中一个档案中有一个xml文件,其中包含有关数据库挂钩的信息 - 一些开发人员使用其他版本(甚至引擎),并且需要在使用构建输出之前更改这些。

我不想让他们对版本控制的文件进行更改(他们可能会错误地提交),而是让他们选择使用构建脚本适用的本地个人补丁文件。

在旧的蚂蚁脚本中,我们做了类似的事情

<target name="appcontext-patch" if="applicationContext.patch.file">
    <patch patchfile="${applicationContext.patch.file}" originalfile="${dist.dir}/applicationContext.xml"/>
</target>

但我无法弄清楚如何在Gradle中进行等效操作。有没有比尝试直接将其转换为对ant.patch的调用更好(即更惯用)的方式?

某些背景
这就是文件首先在存档中结束的方式:

into('META-INF') {
    from 'deployment', {
        include 'applicationContext.xml'
        rename { fn ->  "jboss-spring.xml" }
    }
}

如果我能做一些类似

的事情,那将是 fantabulous
into('META-INF') {
    from 'deployment', {
        include 'applicationContext.xml'
        rename { fn -> "jboss-spring.xml' }
        patch 'local/applicationContext.xml.patch'
    }
}

并在将文件放入存档之前应用补丁文件。我不介意编写一些代码来实现这一点,但我对Gradle很新,我不知道从哪里开始。

3 个答案:

答案 0 :(得分:4)

你应该能够直接将你的蚂蚁电话翻译成gradle。

The gradle doc on how to do this generically.基本上,属性成为命名参数,子标记成为闭包。文档中有很多很好的例子。

完成翻译的ant任务后,您可以在适当的任务中输入doFirst或doLast块。

我的第一个猜测是这样的:

apply plugin: 'java'

assemble.doFirst {
    ant.patch(patchfile: applicationContext.patch.file,
              originalFile: "${dist.dir}/applicationContext.xml")
}

那是未经测试的,所以但我很确定它会让你开始走上正确的道路。目的是在java插件组装您的存档之前,您希望gradle调用一个闭包。在这种情况下,闭包将执行修补xml的ant动作。

或者,您可以使用上面的任务执行复制和标记。

task myCopyTask(type: Copy) {
    ...
} << {
    ant.patch(patchfile: applicationContext.patch.file,
              originalFile: "${dist.dir}/applicationContext.xml")
}

在这种情况下,您自己编写任务,左移操作符(<<)相当于.doLast,但整个冷却程度更低。我不确定你喜欢哪种方法,但如果你已经有一个复制任务首先获取文件,我认为doLast使相关代码块尽可能保持彼此接近。

答案 1 :(得分:1)

如果你想在飞行中更多地这样做,我可以想到两种主要技巧。两者都涉及编写一些代码,但它们可能对您更具吸引力,我非常有信心gradle没有内置任何内容的这种行为。

就我个人而言,我认为#1是更好的解决方案,因为您不需要复制Copy任务的内部。自定义过滤器感觉更清洁,更可重复使用。

1)编写您在复制任务中指定的自定义过滤器。我无法帮助详细说明如何编写自定义过滤器,但我会开始here.您应该能够将自定义过滤器放在buildSrc中(有关gradle.org的大量信息),然后您只需将其导入gradle文件的顶部即可。如果你用groovy写它,我想你甚至可以再次使用ant.patch()

task copyAndPatch() {
    into('META-INF') {
    from 'deployment', {
        include 'applicationContext.xml'
        rename { fn -> "jboss-spring.xml' }
        filter(MyCustomFilterThatDoesAPatch, patchFile: 'local/applicationContext.xml.patch')
    }
}

2)编写自定义任务。再说一次,我leave the details to the experts但是你可以放弃复制任务的子类,添加一个'patch'属性,然后在执行期间跳进去做脏工作。

答案 2 :(得分:1)

RFC 5621定义了一种XML修补语言,该语言使用XPath来定位要修补的文档中的位置。它非常适合调整配置文件。

open source implementation in Java(免责声明:我是作者)。它包括一个过滤器,可以在Gradle中使用该过滤器在任何实现CopySpec的任务期间修补XML文件。例如:

buildscript {
    repositories { jcenter() }
    dependencies { classpath "com.github.dnault:xml-patch:0.3.0" }
}

import com.github.dnault.xmlpatch.filter.XmlPatch

task copyAndPatch(type: Copy) {
    // Patch file in RFC 5621 format
    def patchPath = 'local/applicationContext-patch.xml'

    inputs.file patchPath

    into('META-INF') {
        from 'deployment', {
            include 'applicationContext.xml'
            rename { 'jboss-spring.xml' }
            filter(XmlPatch, patch: patchPath)
        }
    }
}