Replace placeholder in file with gradle - gradle

I have gradle task swagger-codegen with the following configuration:
swaggerSources {
testProject {
inputFile = file("$buildDir/generated/input.json")
code {
language = 'csharp'
configFile = file('swaggergen-config.json')
}
}
}
The file swaggergen-config.json contains:
{
"packageName": "Package.Test",
"packageVersion" : {version},
"netCoreProjectFile": true
}
How to properly replace {version} placeholder with project.version?

The swagger generator plugin looks for a file which makes this a little bit more complicated than just parsing the string and replacing the token.
A solution could be to treat the configuration file as a generated input to the generateSwaggerCode task. This can be done via a copy task that copies your swaggergen-config.json "template" and replaces the {version} with token rootProject.version using an ant ReplaceTokens filter during copy. Note: You'll want to switch {version} to the ant-style token format (e.g. #version#), though.
The swaggerSources.code.configFile closure could then be set to use the newly generated configuration.
This would be added to your build.gradle:
task generateSwaggerGenConfig(type: Copy) {
from swaggergen-config.json
into $buildDir/generated/swaggergen-config.json
filter(org.apache.tools.ant.filters.ReplaceTokens, tokens:['version:rootProject.version])
}
generateSwaggerCode.dependsOn generateSwaggerGenConfig
swaggerSources {
testProject {
inputFile = file("$buildDir/generated/input.json")
code {
language = 'csharp'
configFile = file("$buildDir/generated/swaggergen-config.json")
}
}
}
The generated swaggergen-config.json would look like this
{
"packageName": "Package.Test",
"packageVersion" : #version#,
"netCoreProjectFile": true
}

Related

xjc, generate java classes from xsd (using URL) in gradle 7.2

I use plugin com.github.bjornvester.xjc to generate java classes from xsd:
xjc {
xjcVersion.set("2.3.3")
outputJavaDir = file("${buildDir}/generated-sources/jaxb")
ext.downloaded = file("$buildDir/xjc/downloaded/schema2.wsdl")
doFirst {
mkdir downloaded.parentFile
downloaded.text = new URL("http://www.example.com/foo.xsd").text}
groups {
register("schema1") {
xsdFiles = files(xsdDir.file("${projectDir}/src/main/resources/wsdl/schema1.wsdl"))
defaultPackage.set("pl.com.project.schema1")
}
register("schema2") {
xsdFiles = files(downloaded)
defaultPackage.set("pl.com.project.schema2")
}
}
}
And I got an error in line "xjc {" :
In my previous attempt I incorrectly assumed that xjc was a task. After looking at the github page I can see that "xjc" is an extension object, not a task
So try this:
tasks.register('downloadXsd') {
ext.xsd = file("$buildDir/downloadXsd/foo.xsd")
outputs.file xsd // important!!! configures the task outputs
doLast {
mkdir xsd.parentFile
xsd.text = new URL("http://www.example.com/foo.xsd").text
}
}
xjc {
...
groups {
register("schema1") {
// assuming the plugin is written properly, this should configure a task dependency
xsdFiles = files(tasks.named('downloadXsd'))
...
}
...
}
}
You could improve this using the download task to download the xsd which shows progress of the download and also has caching options

Re-using properties of custom gradle task

I'm defining gradle task like this:
task assembleAppPackage() {
File distDir = file("${projectDir}/dist")
File binDir = file("${distDir}/bin")
File configDir = file("${distDir}/config")
File libDir = file("${distDir}/lib")
doLast {
...using distDir , binDir, etc...
}
}
Somewhere later I want to add some functionality to assembleAppPackage, so I expect something like this to work:
assembleAppPackage {
doLast {
copy {
from "${projectDir}/bin"
into binDir #binDir from original task definition
}
}
}
And gradle claims there is no binDir in scope:
Could not get unknown property 'binDir' for object of type org.gradle.api.internal.file.copy.CopySpecWrapper_Decorated.
How to define task properties which could be later accessed on task extensions? Is it only possible with defining task class?
You can use extra properties for this I think:
task assembleAppPackage() {
ext.distDir = file("${projectDir}/dist")
ext.binDir = file("${distDir}/bin")
ext.configDir = file("${distDir}/config")
ext.libDir = file("${distDir}/lib")
doLast {
...using distDir , binDir, etc...
}
}
(rest of your code unchanged)
On most gradle entities you can use that concept: Set a property using "ext." or
ext {
name1 = value1
name2 = value2
}
See https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtraPropertiesExtension.html or google for "gradle extra properties"

Gradle Zip Task: Replace Entire File Content While Being Copied

I currently have a set of files that contain a DSL that needs to be parsed and converted to XML before being copied over to the destination build directory.
I'm using the eachFile hook to accomplish this, but when I replace the content of the file the source file is being changed as well:
task build(type: Zip) {
with {
archiveName = "${project.name}-${project.version}.${extension}"
destinationDir = buildDir
}
from('workflow/dsl') {
eachFile { fileDetails ->
String xml = new OozieDslParser().parse(fileDetails.getFile())
fileDetails.setName(fileDetails.getName().replaceFirst(~/\.[^\.]+$/, '.xml')
fileDetails.getFile().text = xml //This changes the source file as well.
}
}
from('workflow/resources')
}
What is the best way to approach this problem?
Unfortunately, the 'expand' and 'filter' options don't seem to work as the former just expands properties and the latter only feeds me one line at a time.
Thanks!
I used a custom FilterReader to solve this problem:
class OozieDslFilter extends FilterReader {
OozieDslFilter(Reader input) {
super(new StringReader(new OozieDslParser().parse(input.text)))
}
}
task build(type: Zip) {
with {
archiveName = "${project.name}-${project.version}.${extension}"
destinationDir = buildDir
}
from('workflow/resources')
from('workflow/dsl') {
rename { it - ~/\.[^\.]+$/ + '.xml' }
filter(OozieDslFilter)
}
}

How can I define two different 'distribution' tasks in gradle?

The normal behavior of the distTar and distZip tasks from the application plugin in gradle seems to be to copy the contents of src/dist into the zip and tar files, but I have a subfolder in src/dist that I want to exclude from the default distribution, and include it for a new (extended) task, possibly to be called distZipWithJRE.
I have been able to exclude this folder in the default task as follows:
distributions.main {
contents {
from('build/config/main') {
into('config')
}
from('../src/dist') {
exclude('jre')
}
}
}
How can I define a second task that behaves just like the original (unmodified) task?
Using Gradle 4.8 I had to tweak the answer to use 'with' from CopySpec instead
distributions {
zipWithJRE {
baseName = 'zipWithJRE'
contents {
with distributions.main.contents
}
}
}
It seems that what you're looking for is in the docs. You need to leave current settings as is and for zipWithJRE create and configure custom distribution:
distributions {
zipWithJRE {
baseName = 'zipWithJRE'
contents {
from { distributions.main.contents }
}
}
}

Is resource filtering in Gradle possible without using tokens?

The recommended way to do resource filtering in Gradle is by having tokens in the properties file and then replacing them when processing.
Example
# config.properties
hostname = #myhost#
and in build.gradle do something like below
processResources {
filter ReplaceTokens, tokens: [
"myhost": project.property('myhost')
]
}
The problem with this approach is that it won't work when running from IDEs like eclipse. I would like the property files to be free of Gradle specific tokens i.e just have
hostname = localhost
but have option to replace it when building from Gradle.
You could use the following (not tested):
processResources {
filesMatching('**/config.properties') {
filter {
it.replace('localhost', project.property('myhost'))
}
}
}
Or you could have a default file, used during development in your IDE, and have another file containing tokens and replacing the development one when building using gradle. Something like this (not tested)
processResources {
exclude '**/config.properties'
filesMatching('**/config-prod.properties') {
setName 'config.properties'
filter ReplaceTokens, tokens: [
"myhost": project.property('myhost')
]
}
}
Can use thing like placeholder if you want.
In config.properties file
var1=${var1}
var2=${var2}
In gradle.properties file
processResources {
filesMatching('**config.properties') {
expand(
'var1': project.property('var1'),
'var2': project.property('var2'),
)
}
}
The spring-boot approach
project.version=X.X.X.X
info.build.version=#project.version#
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#production-ready-application-info-automatic-expansion
# File: application.yml
# forward gradle properties to spring boot properties
version: #version#
Setup gradle task (tested with Gradle 7.4):
import org.apache.tools.ant.filters.ReplaceTokens
processResources {
with copySpec {
from 'src/main/resources'
include 'application*.yml'
duplicatesStrategy 'include'
project.properties.findAll {it.value != null}.each {
filter(ReplaceTokens, tokens: [(it.key): it.value.toString()])
}
}
}
Resulting file:
# File: application.yml
# forward gradle properties to spring boot properties
version: 0.0.1-SNAPSHOT

Resources