How to deactivate the caching of gradle properties? - gradle

Depending on the user, a different set of properties are load from a file.
ext.userProps = new Properties(defaults.userProperties)
file("env/configurations/user_${userName}.properties").withInputStream { userProps.load(it) }
User runs the first build -> everything works fine
User changes a property in the file
Runs the build again -> gradle still uses the old properties
Workaround: running gradlew clean after every change to a properties file. Then it works as expected.
How can I tell gradle directly, to not cache the loaded properties?
Edit:
The properties are then used to make string replacements in configuration files.
ext.dbconfig = ""
ext.siteProps = new Properties(defaults.siteProperties)
file("env/configurations/site_${siteName}.properties").withInputStream { siteProps.load(it) }
ext.userProps = new Properties(defaults.userProperties)
file("env/configurations/user_${userName}.properties").withInputStream { userProps.load(it) }
ext.tokens = [
// WEB-INF/web.xml
smtpHostName : "${siteProps.'mail.smtp.host'}".toString(),
smtpPassword : "${siteProps.'mail.smtp.password'}".toString(),
hibernateSchemaCreation : "${userProps.'hibernate.schema.creation'}".toString(),
documentExportMode : "${userProps.'document.exportMode'}".toString(),
multipartConfigLocation : "${siteProps.'multipartConfigLocation'}".toString(),
// META-INF/context.xml">
'hibernate.datasource.url': "${userProps.'hibernate.datasource.url'}".toString(),
'hibernate.dialect' : "${userProps.'hibernate.dialect'}".toString(),
'hibernate.connection.username' : "${userProps.'hibernate.connection.username'}".toString(),
'hibernate.connection.password' : "${userProps.'hibernate.connection.password'}".toString(),
'hibernate.connection.driver.class': "${userProps.'hibernate.connection.driver.class'}".toString(),
]

The problem is that you are using external data to impact the execution result of some tasks, without letting Gradle know. This breaks the up-to-date checking.
Have a look at the documentation on up-to-date checking and in particular the Runtime API which enables you to tell existing Gradle tasks that another input needs to be considered.
Once all inputs are declared properly, changing these properties file will cause Gradle to re-execute the relevant tasks.
So given what you indicated, you most likely want to enhance the processResource task, which will then properly be run whenever a properties file change. That will in cause change the produced jar, which will cause tests to re-run, etc ...

Related

How to get the Gradle build directory in a Java annotation processor

I am writing a custom annotation processor in Java which needs to create a file.
It seems to me the best location for that file would be in a new folder inside the Gradle's $buildDir.
For a project without modules, the environment property "user.dir" seems to hold a value I could use.
However, that environment property changes if the project has modules and the gradlew build command is executed either from inside or outside a module.
What is the best approach to actually get in Java the Gradle build directory of the module in which the annotation processor is declared ?
P.S.
I do not want to create that file in the "build/generated" folder (this is what processingEnv.getFiler().createSourceFile(..) does).
You should do it the other way around : choose a location and set it up in your build.gradle
tasks.withType(JavaCompile) {
options.annotationProcessorGeneratedSourcesDirectory = file("your/custom/path")
}

Gradle: use file contents as property value

Assume I have a description in a file and I want to use the file contents for setting a property in Gradle. What I'm currently doing is something like that
String myChangeNotes = file('resources/META-INF/change-notes.html').text
String myDescription = file('resources/META-INF/description.html').text
patchPluginXml {
changeNotes = myChangeNotes
pluginDescription = myDescription
}
It works, but it does not reload the file when it changes. I guess I have to make a task that has as input the two HTML files so that Gradle knows when they change, but I'm not sure how to proceed.
How would I do it so that the changeNotes and pluginDescription properties of patchPluginXml are reloaded each time the files change on disk?
You already have a task that has the contents of the files as input. As you read the files in the configuration phase, they are always read freshly when you start your build. The changeNotes and pluginDescription fields of the patchPluginXml task (if we talk about the gradle-intellij plugin) are defined as inputs, so if their value changes, the task will be re-run. So everything seems to be set up correctly.

How to use ant.properties in a `vendor.gradle` vendor settings file?

I have a multi-project gradle build with an ant build script that contains a task such as this (simplified):
<target name="get-version">
<!-- Goes out and fetches the versioning for each project and sets prop -->
<property name="version" value="${myDesiredVersion}" />
</target>
and inside my build.gradle script I have an ant script loader and then I depend on this target; my issue is that this isn't being evaluated in a way that allows me to use my ant.properties['version'] in vendor.gradle like
// version = '1.0.2' -- works
version = ant.properties['version'] // doesn't work
I'm a gradle noobie and to top it off I'm migrating an ant project to start using gradle so I could be way off course. It's important to note that I can't just outright include the version in the vendor.gradle file since it's being generated by the ant-script.
I'm not familiar with how I could insert this ahead of the gradle lifecycle... I tried something like this
gradle.beforeProject { p ->
tasks['get-version'].execute() // appears to execute successfully?
configure(p) {
def vendorSettings = file("${myRoot}/vendor.gradle")
if(vendorSettings.exists()){
println "Loading vendor settings for project " + p
println ant.properties['version'] // but outputs null here
// ant.properties is still a valid observable map
apply from: vendorSettings
}
}
}
and the ant version property was still null - note that it works outside of this, I think the scoping is a little different then I think it is in this specific situation
You might have something like
task antTask {
//...
doLast {
file("vendor.properties").withInputStream { is ->
Properties props = new Properties()
props.load(is)
props.each { prop -> ext.set(prop.key, prop.value) }
}
}
}
And after the task is executed you could access properties like ext.version, etc.
But, this won't work if you want to use the properties in task configurations, because all the tasks are configured first, only after that are executed if necessary. So your antTask is running only after all other tasks are already configured. So you probably need to rethink how you generate these ant properties and either precompute them before running gradle, or port the logic to gradle build.

Passing properties to a gradle build

I admit I am quite new to gradle but I did not expect to be unable to understand something as simple as the example below. I can read the gradle documentation about checking whether a project property have been set or not using a hasProperty(String propertyName) call and I am sitting here and have no idea why something so basic does not work.
I believe my mind must be so much "ant like" oriented that for sure I am missing something ordinary basic
task printSystem() << {
println system
println "has property: " + hasProperty("system")
}
and invoking that task with the command below:
$gradle printSystem -Psystem=mySystem
mySystem
has property: null
So my questions would be:
Why system is printed out but hasProperty returns null?
How should I check for the existence of the project property called "system"?
Is there a different way for testing for a project property as opposed to a system property?
How would you pass a system property from the command line?
This is from, the gradle documentation and I believe I am reading it right
19.2.1. Checking for project properties
You can access a project property in your build script simply by using its name as you would use a variable. If this property does not exist, an exception will be thrown and the build will fail. If your build script relies on optional properties the user might set, perhaps in a gradle.properties file, you need to check for existence before you access them. You can do this by using the method hasProperty('propertyName') which returns true or false.
You need to explicitly invoke hasProperty on the project instance - without it, hasProperty is invoked on some local context. The following example works:
task printSystem() << {
println system
println "has property: " + project.hasProperty("system")
}
Because non-existing properties (system is not defined in the script) are taken from the project instance. If you won't pass the system property, an exception will be thrown on println.
project.hasProperty('propName')
Not sure if I understood right, but you can access project properties via the project instance and system properties via the System class.
Using -D switch - gradle -Dprop=value

Resolve a dependency dynamically inside a gradle task

I am trying to build a gradle plugin, which does the following:
As part of one its tasks, it creates a new configuration
It adds a DefaultExternalModuleDependency to this configuration - more specifically, it constructs a dependency to the application server zip file (available on Nexus). This information can be overridden by the invoking project as well.
Tries to resolve this newly added dependency and then unpacks the file to a local folder
All of this was working well when I had the details hard coded in a build file, but it looks like adding dependencies as part of a task are not treated the same way as having that information available at the parsing time.
So my question is, how do I get the project to reload the configurations / dependencies?
The code looks like the following:
#TaskAction
void installAppserver() {
Dependency dependency = new DefaultExternalModuleDependency(group,name,version)
Configuration configuration = project.configurations.detachedConfiguration(dependency)
configuration.setTransitive(false)
configuration.files.each { file ->
if (file.isFile() && file.name.endsWith('.zip')) {
println 'Attempting to unzip: ' + file + ' into folder: ' + appServerFolder
new Copy().from(project.zipTree(file)).into(appServerFolder).execute()
}
}
}
The problem is that the actual artifacts are not getting resolved!
A task can't configure the build model (that's what plugins do). It's fine to create and resolve a detached configuration in a task. If this doesn't work, there is likely a problem with the task's code, or the dependency it tries to resolve. Note that dependencies can only be resolved if the correct repository(s) are defined.
Instead of new DetaultExternalModuleDependency() (which is an internal class), project.dependencies.create() should be used. Instead of new Copy().execute() (Task#execute must not be called from user code), project.copy should be used.

Resources