Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle java project replace single line in file during build

Tags:

java

gradle

build

I have a simple Gradle build script to compile and package (similar to the application plugin) my Java application. The only thing I do not accomplish is to replace the current version number in a simple .properties file.

I have created a file 'src/main/resources/app-info.properties' with a single line 'application.version = @version@'. No I want to replace this version string whenever the file is copied to the build folder (think this happens during the build task).

I already tried a simple solution with ants ReplaceTokens. This one replaced the version but also broke my .png files in the resources..

So is there a simple solution to just replace tokens in one single file during the build task (or whatever task handles the copy to the build folder)?

Thank you for any help! Ben

====== Edit based on the comment from Opal =====

Based on the hint I have added the following:

import org.apache.tools.ant.filters.ReplaceTokens
// ... 
build {
    from('src/main/resources') { 
        include '*.properties' 
        filter(ReplaceTokens, tokens: [version : project.version]) 
    } 
} 

Which throws this error:

Could not find method from() for arguments [src/main/resources, build_vbjud9ah7v3pj5e7c5bkm490b$_run_closure6_closure12@43ead1a8] on root project

Seems like I am on the wrong task?

====== Edit for completeness adding the solution based on Opals suggest =====

Thanks man, the following is the working solution!

processResources {
    from('src/main/resources') {
        include '*.properties'
        filter(ReplaceTokens, tokens: [version : project.version])
    }
}
like image 677
Ben Avatar asked Jun 15 '14 15:06

Ben


2 Answers

Books and blogs alike, including the answer from Opal all recommend using a vivid mixture of exclude/include, from() and filter(). And of course, so did I on my first attempt to replace the text {{app javascript library}} in a index.html file to the path of a JavaScript library which depended on a simple project property setting.

The problem that hit me was that my 'war' task produced duplicated index.html files in the war archive and getting rid of the problem, using the pattern described previously, resulted in one huge unreadable hack.

Then I found a really straight forward solution. The following example is from my own build script and you have to customize it a bit to suite your needs:

war {
    eachFile { copyDetails ->
        if (copyDetails.path == 'index.html') {
            filter { line ->
                line.replace('{{app javascript library}}', "lib/someLib.js")
            }
        }
    }
}
like image 161
Martin Andersson Avatar answered Oct 20 '22 23:10

Martin Andersson


Paste sample code. What You need to do is to include file for replacement and exclude other files from replacement. Here is sample usage. Search for ReplaceTokens and You'll see what am I talking about.

You need to add filtering to processResources task. Sample code:

processResources {

    def profile = project.properties['profile']

    def replace_tokens = profile ? filter_tokens[profile] : filter_tokens['default']

    exclude '**/log4j-test.xml'

    from('src/main/resources') {
        exclude '**/*.ttf'
        filter(ReplaceTokens, tokens: replace_tokens)
    }

    from('src/main/resources') {
        include '**/*.ttf'
    }
}

Above ttf (binary) files are excluded from filtering but copied. replace_tokens is a filter taken from map defined in other part of the script.

like image 37
Opal Avatar answered Oct 21 '22 00:10

Opal