If I change my ~/.gradle/init.gradle to the following:
def hi() {
println "hello"
}
hi()
initscript {
}
Then running a gradle build outputs:
hello
> Task :prepareKotlinBuildScriptModel UP-TO-DATE
BUILD SUCCESSFUL in 366ms
But if I change ~/.gradle/init.gradle to this:
def hi() {
println "hello"
}
initscript {
hi()
}
Then the gradle build outputs:
FAILURE: Build failed with an exception.
* Where:
Initialization script '~/.gradle/init.gradle' line: 6
* What went wrong:
A problem occurred evaluating initialization script.
> Could not find method hi() for arguments [] on object of type org.gradle.api.internal.initialization.DefaultScriptHandler.
Why is this?
And how can I invoke hi() from within the initscript block?
see link below to understand the initscript closure better - in short you can not do actions inside; you can only configure - see diff example of linking actions to tasks https://docs.gradle.org/current/userguide/init_scripts.html#sec:writing_an_init_script
Credit to ephemient from the Gradle community-support slack channel:
buildscript, initscript, plugins, and pluginManagement are all
special blocks that extracted and run separately, before any other
part of the script. this is necessary because Gradle needs to use them
to set up the build environment for the rest of the script. you cannot
use anything defined outside of the block, in these blocks.
Another note: if I change init.gradle to
initscript {
def hi() {
println "hello"
}
hi()
}
then the following error is output:
FAILURE: Build failed with an exception.
* Where:
Initialization script '~/.gradle/init.gradle' line: 2
* What went wrong:
Could not compile initialization script '/Users/aloneitan/.gradle/init.gradle'.
> startup failed:
initialization script '~/.gradle/init.gradle': 2: Method definition not expected here. Please define the method at an appropriate place or perhaps try using a block/Closure instead. at line: 2 column: 5. File: _BuildScript_ # line 2, column 5.
def hi() {
^
1 error
It appears that the answer is that it is not possible to define a method to be used inside initscript using Groovy
It is worth noting that it is possible in Kotlin, though.
Related
How can I configure Gradle to fail build at the end (not fail fast) if there is anything printed on standard error output by any task or plugin?
I haven't found a way to do it in the official API.
Here’s a sample build.gradle that shows how this can work:
// create a listener which collects stderr output:
def errMsgs = []
StandardOutputListener errListener = { errMsgs << it }
// add the listener to both the project *and* all tasks:
project.logging.addStandardErrorListener errListener
project.tasks.all { it.logging.addStandardErrorListener errListener }
// evaluate the collected stderr output at the end of the build:
gradle.buildFinished {
if (errMsgs) {
// (or fail in whatever other way makes sense for you)
throw new RuntimeException(errMsgs.toString())
}
}
// example showing that the project-level capturing of stderr logs works:
if (project.hasProperty('projErr'))
System.err.print('proj stderr msg')
// example showing that the task-level capturing of stderr logs works:
task foo {
doLast {
System.err.print('task stderr msg')
}
}
// example showing that stdout logs are not captured:
task bar {
doLast {
System.out.print('task stdout msg')
}
}
The examples in the second half are only there to show that it works as expected. Try the build with various command line args/options:
# doesn’t fail:
./gradlew bar
# fails due to project error:
./gradlew -PprojErr bar
# fails due to task error:
./gradlew foo
# fails due to both task and project error:
./gradlew -PprojErr foo
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 got a little problem with variables / ext properties in gradle.
In my root project i have this:
task foo {
println project.fooContent
}
in my child project fooContent is defined like this:
ext { fooContent='somethingProjectSpecific' }
When executing :childproject:foo it says variable is not set.
Do you know how to circumvent that problem?
This variable is not set since you try to print it at configuration phase. Try with an action (<<) it will be printed on execution phase:
task foo << {
println project.fooContent
}
I'm trying to configure the following custom task:
task antecedeRelease(type: AntecedeReleaseTask) {
antecedeWithVersion = project.'antecede-with-version'
antecedeToVersion = project.'antecede-to-version'
}
The problem is that the properties antecede-with-version and antecede-to-version are to be set through the command line with a -P option. If they're not set and antecedeRelease isn't being called, that shouldn't be a cause for an error:
$ ./gradlew tasks
org.gradle.api.GradleScriptException: A problem occurred evaluating project ...
Caused by: groovy.lang.MissingPropertyException: Could not find property 'antecede-with-version' on project ...
I could conditionally define the antecedeRelease task such that it's defined only if those properties are defined but I'd like to keep the build.gradle file as clean as possible.
If you need the antecedeRelease task to run "lazily" as-in, at the end of the configuration phase, or at the beginning of the execution phase, your best bet is to use doFirst
task antecedeRelease(type: AntecedeReleaseTask) {
doFirst {
antecedeWithVersion = project.'antecede-with-version'
antecedeToVersion = project.'antecede-to-version'
}
}
One option might be to use Groovy's elvis operator like so:
task antecedeRelease(type: AntecedeReleaseTask) {
antecedeWithVersion = project.ext.get('antecede-with-version') ?: 'unused'
antecedeToVersion = project.ext.get('antecede-with-version') ?: 'unused'
}
If this fails still, you can consider project.ext.has('property') when setting the 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