How to apply a patch file in Gradle?

I have a Gradle build script that successfully creates my project and compiles all the artifacts I need.

However, in several cases, I would like to give other developers the opportunity to fix some of the files. For example, in one of the archives there is an xml file with information about database bindings - some of the developers use other versions (or even engines) and must change them before they can use the assembly output.

Instead of making changes to the version control file, which they might have made by mistake, I would like to give them the opportunity to have a local, individual patch file to which the script assembly applies.

In the old ant script, we did something like this

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

but I can't figure out how to make an equivalent in Gradle. Is there a better (i.e. more idiomatic) way to do this than trying to directly convert this to an ant.patch call?

Some context
This is how the file gets to the archive in the first place:

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

It would be fantastic if I could just do something like

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

and the patch file is applied before the file is archived. I don't mind writing code to make this possible, but I'm completely new to Gradle, and I don't know where to start.

+4
source share
3 answers

You should be able to translate the ant call to gradle pretty straight forward.

A gradle document on how to do this in general. Basically, attributes become named arguments, and child tags become private. There are tons of good examples in the documentation.

Once you have the translated ant task, you can insert the corresponding task into the doFirst or doLast block.

My first guess would be something like this:

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

This is untested, so, but I'm sure it will lead you to the right path. The goal is that before the java plugin builds your archive, you want gradle to cause a close. In this case, the closure will perform the ant action, which fixes your xml.

Alternatively, you can use the task above that runs a copy and tag on it.

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

In this case, you write the task yourself, and the left-shift operator ( << ) is equivalent to .doLast , but much colder. I'm not sure which method you prefer, but if you already have a copy task that gets the file there, first of all, I think that doLast keeps the corresponding blocks of code as close to each other as possible.

+3
source

If you want to do this more on the fly, I can come up with two main methods. Both include coding, but they may be more attractive to you, and I'm sure gradle doesn't have this behavior anywhere.

Personally, I believe that # 1 is the best solution, since you don’t have to guess with the internal components of the Copy task. Custom filter feels cleaner and more reusable.

1) Write a custom filter specified in the copy task. I cannot help with the details of writing a custom filter, but I would start here. You should be able to put a custom filter in buildSrc (a lot of information on this is at gradle.org), and then you just need to import it at the top of your gradle file. If you write it in groovy, I think you can even just use ant.patch() again.

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

2) Write a custom task. Again, I leave the details to the experts , but you can probably get away with subclassing the Copy task by adding the patch property and then jump at runtime to do the dirty work.

+1
source

RFC 5621 defines an XML correction language that XPath uses to orient the location in a correction document. This is great for setting up configuration files.

open source implementation in Java (Disclaimer: I am the author). It includes a filter that you can use from Gradle to fix XML files during any task that implements CopySpec. For instance:

 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) } } } 
+1
source

Source: https://habr.com/ru/post/1485792/


All Articles