I have this really strange behavior in Gradle and I cannot find a way out of it. In my gradle.properties file, I am using this checking condition:
//gradle.properties
if ( "${System.Property['DATABASE_DIR']}".compareTo('swdb') == 0 ) {
PROJECT_DATABASE_PATH=../database/swdb/include
}
else {
PROJECT_DATABASE_PATH=../database/include/
}
I created a new task called printProperties and it looks like this.
//build.gradle
task printProperties {
println "${System.properties['DATABASE_DIR']}".compareTo('swdb') == 0
println PROJECT_DATABASE_PATH
}
I get the following output when I run the printProperties task.
$gradle printProperties -DDATABASE_DIR=swdb
true
../database/include/
:printProperties UP-TO-DATE
BUILD SUCCESSFUL
Total time: 1.07 secs
It is really strange that the task prints true but the gradle.properties file does not evaluate the same condition correctly. Could anybody help me with this?
Your code shall take place in a init.gradle script.
You can find documentation here : https://docs.gradle.org/current/userguide/init_scripts.html
gradle.properties file is only for key=value pairs
Related
Have in build.gradle
task hello {
doLast {
println 'Hello World!'
}
}
task count {
println "one"
doLast{
4.times {print "$it "}
}
println "two"
doFirst{
2.times {println "$it - 1 "}
}
3.times {println( "$it -3")}
}
task intro(dependsOn: hello){
doLast{
println("I'm Gradle!")
}
}
run in shell
gradle intro
and get
one
two
0 -3
1 -3
2 -3
:hello
Hello World!
:intro
I'm Gradle!
BUILD SUCCESSFUL
but it's not correct!!!
the correct output is
:hello
Hello World!
:intro
I'm Gradle!
BUILD SUCCESSFUL
What did I do wrong?
ps
adding details to because there is too much code here :(
adding details to because there is too much code here :(
adding details to because there is too much code here :(
adding details to because there is too much code here :(
Why do you think it's wrong? Probably it is absolutely correct. This is all due to configuration of the build. Read about it in the official user guide.
There are a number of phases take place during the build. One of them is configuration phase. All the output you don't expect to see - is the configuration's output. When you do something in task's closure, it's executed at the configuration of your build, untill you place it into the doLast or doFirst closure to run at the execution phase (or task's closure is declared with << that's the same as doLast).
Note that configuration is executed for all tasks, no matter if they will be executed or not. That is the reason of your unexpected output - it's just done as a part of your build configuration, though they are declared within some task.
I have the following simple task in my build:
task generateFile << {
def file = new File("$buildDir/setclasspath.sh")
file.text = "sample"
outputs.file(file)
}
task createDistro(type: Zip, dependsOn: ['copyDependencies','packageEnvironments','jar', 'generateFile']) <<{
from generateClasspathScript {
fileMode = 0755
into 'bin'
}
}
When I run gradle clean build I see the following output:
Cannot call TaskOutputs.file(Object) on task ':generateFile' after task has started execution. Check the configuration of task ':generateFile' as you may have misused '<<' at task declaration
How do I declare the task file creation outputs as an input to the zip task while also ensuring they happen in the execution phase?
If I leave off the << then the clean task wipes the generated file before the ZIP can use it. If I keep them, I get the above error.
It's the opposite as what is being suggested in the comments. You are trying to set the outputs in execution phase. The correct way to do what you are probably trying to do is for example:
task generateFile {
def file = new File("$buildDir/setclasspath.sh")
outputs.file(file)
doLast {
file.text = "sample"
}
}
I want to automatically add a serverRun task when doing functional tests in Gradle, so I add a dependency :
funcTestTask.dependsOn(serverRun)
Which results in the task running whether or not the funcTestTask even runs
:compile
:serverRun
:funcTestTask (and associate compile tasks... etc)
:serverStop
OR
:compile UP-TO-DATE
:serverRun <-- unnecessary
:funcTestTask UP-TO-DATE
:serverStop
The cost of starting the server is pretty high and I only want it to start if the functionalTest isn't UP-TO-DATE, I'd like to do or something :
if(!funcTestTask.isUpToDate) {
funcTestTask.dependsOn(serverRun)
}
So I know I can't know the up-to-date status of funcTestTask until all it's inputs/outputs are decided BUT can I inherit it's uptoDate checker?
serverRun.outputs.upToDateWhen(funcTestTask.upToDate)
The alternative is to "doFirst" the ServerRun in the FuncTest, which I believe is generally frowned upon?
funcTestTask.doFirst { serverRun.execute() }
Is there a way to conditionally run a task before another?
UPDATE 1
Tried settings inputs/outputs the same
serverRun.inputs.files(funcTestTask.inputs.files)
serverRun.outputs.files(funcTestTask.outputs.files)
and this seems to rerun the server on recompiles (good), skips reruns after successful unchanged functional tests (also good), but wont rerun tests after a failed test like the following
:compile
:serverRun
:funcTestTask FAILED
then
:compile UP-TO-DATE
:serverRun UP-TO-DATE <-- wrong!
:funcTestTask FAILED
Having faced the same problem I found a very clean solution. In my case I want an eclipse project setup to be generated when the build is run, but only at the times when a new jar is generated. No project setup should be executed when the jar is up to date. Here is how one can accomplish that:
tasks.eclipse {
onlyIf {
!jar.state.upToDate
}
}
build {
dependsOn tasks.eclipse
}
Since the task is a dependent tasks of the one you are trying to control then you can try:
tasks {
onlyIf {
dependsOnTaskDidWork()
}
}
I ended up writing to a 'failure file' and making that an input on the serverRun task:
File serverTrigger = project.file("${buildDir}/trigger")
project.gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph ->
// make the serverRun task have the same inputs/outputs + extra trigger
serverRun.inputs.files(funcTestTask.inputs.files, serverTrigger)
serverRun.outputs.files(funcTestTask.outputs.files)
}
project.gradle.taskGraph.afterTask { Task task, TaskState state ->
if (task.name == "funcTestTask" && state.failure) {
serverRun.trigger << new Date()
}
}
With information from an answer to my question on the Gradle forums :
http://forums.gradle.org/gradle/topics/how-can-i-start-a-server-conditionally-before-a-functionaltestrun
I had the same problem but the solution I came up is much simpler.
This starts up the server only if testing is necessary
test {
doFirst {
exec {
executable = 'docker/_ci/run.sh'
args = ['--start']
}
}
doLast {
exec {
executable = 'docker/_ci/run.sh'
args = ['--stop']
}
}
}
Assuming you have task1 and task2 which depends on task1 and you need to run task2 only if task1 is not up-to-date, the following example may be used:
task task1 {
// task1 definition
}
task task2(dependsOn: task1) {
onlyIf { task1.didWork }
}
In this case task2 will run only when task1 is not up-to-date. It's important to use didWork only for tasks which are defined in dependsOn, in order to ensure that didWork is evaluated after that task (task1 in our example) had chance to run.
I have searched for a while for this problem and am not able to solve it. I pulled a project down from a private git repo. Some people are able to build while others like myself are getting the following error:
Error:Gradle:Execution failed for task ':ProjectName:buildNative'.
> execCommand == null!
If anybody has encountered this and knows how to fix it, please let me know, it does not seem like a problem which is specific to the project I am on.
I think this is the part in the Gradle file where it is failing:
task buildNative(type: Exec) {
if (System.env.ANDROID_NDK_HOME != null) {
def ndkBuild = new File(System.env.ANDROID_NDK_HOME, 'ndk-build')
commandLine ndkBuild
} else {
doLast {
println '##################'
println 'Skipping NDK build'
println 'Reason: ANDROID_NDK_HOME not set.'
println '##################'
}
}
}
Seems like you don't have an ANDROID_NDK_HOME environment variable set. The code above doesn't treat that case correctly. As such, the problem is specific to your build. One way to fix it is to replace doLast with doFirst and to insert throw new StopExecutionException() after the printlns. Additionally you may have to set commandLine (or executable) to a dummy value.
I have a very simple build script like so
task hello{
println("hello World")
}
task bye {
println("bye")
}
On the command line I run
gradle hello and I get the following output:
hello World
bye
:hello UP-TO-DATE
Why is it executing the task "bye" (I'm assuming it gets executed since "bye" gets printed)? Thanks.
It's a common pitfall:
task hello {
println("Any code in here is about *configuring* the\
task. By default, all tasks always get configured.")
doLast {
println("Any code in here is about *executing* the task.\
This code only gets run if and when Gradle decides to execute the task.")
}
}
The distinction between configuration phase and execution phase is probably the single most important concept to understand in Gradle. It can be confusing at first, and may go away in the future. A kind of analogue in the Ant/Maven world is that these tools first parse XML build scripts and build an object model (perhaps resolving some properties along the way), and only then execute the build.
Adding to Peter answer, If you want to execute all task , you can specify the defaultTasks list.
defaultTasks 'clean', 'run'
task clean {
doLast {
println 'Default Cleaning!'
}
}
task run {
doLast {
println 'Default Running!'
}
}
task other {
doLast {
println "I'm not a default task!"
}
}
Output
Output of gradle -q
> gradle -q
Default Cleaning!
Default Running!
More details can be found here
https://docs.gradle.org/current/userguide/tutorial_using_tasks.html