Resource Filtering


(Steve Cohen) #1

Is this document up-to-date? I am concerned with the resource filtering section. I am porting a maven project and would like to be able to do this. However, it says

Maven has a phase called process-resources that has the goal resources:resources
bound to it by default. This gives the build author an opportunity to
perform variable substitution on various files, such as web resources,
packaged properties files, etc.
The Java plugin for Gradle provides a processResources task to do the same thing. Here’s an example configuration:
processResources {
expand(version: version, buildNumber: currentBuildNumber)
}
So the left hand side of each colon is the token name and
the right hand side is a project property. This variable substitution
will apply to all your resource files (the ones under src/main/resources usually).

I am not sure where “currentBuildNumber” is defined as a project property and I’d also like to filter in a “build timestamp”.

Is this still the current state of the art and if not, can you tell me what is?


(Steve Cohen) #2

OK, I’ve verified that this still works and I don’t see a better way.


(Vlasev) #3

This is quite an old topic, but it describes well what I needed and struggled for couple of days to make it work. That’s too much time spend on a chore, so I decided to share my experience. Someone may benefit from it. Gradle newbie here, so I guess it’s not a great solution.

What I needed:

  • to have markers in resources replaced: e.g. ${value_to_be_replaced}
  • to have different set of values in separate .properties files
  • to use only one of these files for marker replacement during processResources
  • to make gradle track changes in these .properties files and run processResources task if necessary
  • to have these .properties files not present in projects build artefacts

Frankly I’ve expected solution for such requirements to exist built-in with this state-of-the-art build tool. But I faild to find one.

My solution:

  • use “build-config” folder within project resources to place .properties with marker values files in it
  • let processResources copy it in the build
  • delete it with doLast{} block
    / These three options gave me separate .properties files, tracked by gradle resources processor, missing from the build/
  • use project property to choose properties file name: e.g. $gradle -PbuildEnv=staging --> looking for staging.properties; default: local.properties
  • amend processResources for all projects via the script bellow, placed in root-project/build.gradle
  • expand() each resource, replacing markers with values loaded from the selected properties file

Received downsides:

  • markers can’t use dot separation syntax: e.g. dont use “smtp.host.port”, but “smtp_host_port”
  • gradle is not suggestive on marker replacement failure; use --stacktrace to gain some insight

afterEvaluate {

subprojects {
	it.processResources {

// process resources always, to make sure -PbuildEnv=<env_name> takes effect
// this is quick and dirty solution. Should persist last used environment name and check it along with the original up-to-date check.
outputs.upToDateWhen {
false
}

		def propsFileName;
		def buildEnvSet = project.hasProperty("buildEnv")
		
		
		if (buildEnvSet) {
			propsFileName = buildEnv
		} else {
			propsFileName = "local"
		}
		
	
		def propsFile = file("src/main/resources/build-config/" + propsFileName + ".properties")
		
		if (propsFile.exists()) {
			def myProps = new Properties()

			propsFile.withInputStream {
				myProps.load(it);
			}
			
			filesNotMatching("**/build-config/**" ) {
				println "expanding (marker replacement) " + it
				expand(myProps)
			}
		}
		
		doLast {
			File buildConfigDir = file(getDestinationDir().path + "/build-config")
			
			if (buildConfigDir.exists()) {
				delete buildConfigDir
			}
		}
	}
}

}

Improvement suggestions are welcome.


(Sverre Moe) #4

The documentaton on Resource Filtering is lacking how to use resource filtering on a different resource location than the default src/main/resources.

I have some additional resources under src/main/deploy for JavaFX resources to javapackager.

This is an old article I found, but it still works on newer versions of Gradle.

This is my build script code for resource filtering:

import org.apache.tools.ant.filters.ReplaceTokens
processResources {
    with copySpec {
        from 'src/main/resources'

        into('deploy') {
            from 'src/main/deploy'
            filter ReplaceTokens, tokens: [
                projectName: projectName,
                applicationName: applicationName,
                applicationVersion: applicationVersion,
                applicationRelease: applicationRelease
            ]
        }
    }
}

This example uses resources filtering only on src/main/deploy. For it to work also on src/main/resources just move the filter block outside in the copySpec block.

All occurences of maven ${VAR} must be changed with @VAR@. This is not mentioned in the documentation.