ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 01.01.2026
Просмотров: 1130
Скачиваний: 0
6
Build Script Basics
6.1. Projects and tasks
Everything in Gradle sits on top of two basic concepts: projects and tasks.
Every Gradle build is made up of one or more projects. A project represents some component of your software which can be built. What this means exactly depends on what it is that you are building. For example, a project might represent a library JAR or a web application. It might represent a distribution ZIP assembled from the JARs produced by other projects. A project does not necessarily represent a thing to be built. It might represent a thing to be done, such as deploying your application to staging or production environments. Don't worry if this seems a littl vague for now. Gradle's build-by-convention support adds a more concrete definition for what project is.
Each project is made up of one or more tasks. A task represents some atomic piece of work which a build performs. This might be compiling some classes, creating a JAR, generating javadoc, or publishing some archives to a repository.
For now, we will look at defining some simple tasks in a build with one project. Later chapters will look at working with multiple projects and more about working with projects and tasks.
6.2. Hello world
You run a Gradle build using the gradle command. The gradle command looks for a file called bui in the current directory. [2] We call this build.gradle file a build script, although strictly speaking it is a build configuration script, as we will see later. The build script defines a project and its tasks.
To try this out, create the following build script named build.gradle.
Page 26 of 343
Example 6.1. The first build script
build.gradle
task hello { doLast {
println 'Hello world!'
}
}
In a command-line shell, enter into the containing directory and execute the build script by running
:
Example 6.2. Execution of a build script
Output of gradle -q hello
> gradle -q hello Hello world!
What's going on here? This build script defines a single task, called hello, and adds an action to it. When you run
gradle hello, Gradle executes the hello task, which in turn executes the action you've provided. The action is simply a closure containing some Groovy code to execute.
If you think this looks similar to Ant's targets, well, you are right. Gradle tasks are the equivalent to Ant targets. But as you will see, they are much more powerful. We have used a different terminology than Ant as we think the word task is more expressive than the word target. Unfortunately this introduces a terminology clash with Ant, as Ant calls its commands, such as javac or copy, tasks. So when we
talk about tasks, we always mean Gradle tasks, which are the equivalent to Ant's targets. If we tal about Ant tasks (Ant commands), we explicitly say ant task.
6.3. A shortcut task definition
There is a shorthand way to define a task like our hello task above, which is more concise.
Example 6.3. A task definition shortcut
build.gradle
task hello << {
println 'Hello world!'
}
Again, this defines a task called hello with a single closure to execute. We will use this task
Page 27 of 343
definition style throughout the user guide.
6.4. Build scripts are code
Gradle's build scripts expose to you the full power of Groovy. As an appetizer, have a look at this:
Example 6.4. Using Groovy in Gradle's tasks
build.gradle
task upper << {
String someString = 'mY_nAmE' println "Original: " + someString
println "Upper case: " + someString.toUpperCase()
}
Output of gradle -q upper
> gradle -q upper Original: mY_nAmE Upper case: MY_NAME
or
Example 6.5. Using Groovy in Gradle's tasks
build.gradle
task count << {
4.times { print "$it " }
}
Output of gradle -q count
> gradle -q count 0 1 2 3
6.5. Task dependencies
As you probably have guessed, you can declare dependencies between your tasks.
Page 28 of 343
Example 6.6. Declaration of dependencies between tasks
build.gradle
task hello << {
println 'Hello world!'
}
task intro(dependsOn: hello) << { println "I'm Gradle"
}
Output of gradle -q intro
> gradle -q intro Hello world!
I'm Gradle
To add a dependency, the corresponding task does not need to exist.
Example 6.7. Lazy dependsOn - the other task does not exist (yet)
build.gradle
task taskX(dependsOn: 'taskY') << { println 'taskX'
}
task taskY << { println 'taskY'
}
Output of gradle -q taskX
> gradle -q taskX taskY
taskX
The dependency of taskX to taskY is declared before taskY is defined. This is very important for multi-project builds. Task dependencies are discussed in more detail in Section 17.4, “Addin dependencies to a task”.
Please notice, that you can't use a shortcut notation (seeSection 6.8, “Shortcut notations”)when referring to task, which is not defined yet.
6.6. Dynamic tasks
The power of Groovy can be used for more than defining what a task does. For example, you can also use it to dynamically create tasks.
Page 29 of 343
Example 6.8. Dynamic creation of a task
build.gradle
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
Output of gradle -q task1
> gradle -q task1 I'm task number 1
6.7. Manipulating existing tasks
Once tasks are created they can be accessed via an API. This is different to Ant. For example you can create additional dependencies.
Example 6.9. Accessing a task via API - adding a dependency
build.gradle
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
task0.dependsOn task2, task3
Output of gradle -q task0
> gradle -q task0 I'm task number 2 I'm task number 3 I'm task number 0
Or you can add behavior to an existing task.
Page 30 of 343
Example 6.10. Accessing a task via API - adding behaviour
build.gradle
task hello << {
println 'Hello Earth'
}
hello.doFirst {
println 'Hello Venus'
}
hello.doLast {
println 'Hello Mars'
}
hello << {
println 'Hello Jupiter'
}
Output of gradle -q hello
> gradle -q hello Hello Venus
Hello Earth
Hello Mars Hello Jupiter
The calls doFirst and doLast can be executed multiple times. They add an action to the beginning or the end of the task's actions list. When the task executes, the actions in the action lis are executed in order. The << operator is simply an alias for doLast.
6.8. Shortcut notations
As you might have noticed in the previous examples, there is a convenient notation for accessing an existing task. Each task is available as a property of the build script:
Example 6.11. Accessing task as a property of the build script
build.gradle
task hello << {
println 'Hello world!'
}
hello.doLast {
println "Greetings from the $hello.name task."
}
Output of gradle -q hello
> gradle -q hello Hello world!
Greetings from the hello task.
This enables very readable code, especially when using the out of the box tasks provided by the plugins (e.g. compile).
Page 31 of 343
6.9. Extra task properties
You can add your own properties to a task. To add a property named myProperty, set ext.myPr to an initial value. From that point on, the property can be read and set like a predefined task property.
Example 6.12. Adding extra properties to a task
build.gradle
task myTask
myTask.ext.myProperty = 'myCustomPropValue'
task showProps << {
println myTask.myProperty
}
Output of gradle -q showProps
> gradle -q showProps myCustomPropValue
Extra properties aren't limited to tasks. You can read more about them inSection 16.4.2, “Extra properties”.
6.10. Using Ant Tasks
Ant tasks are first-class citizens in Gradle. Gradle provides excellent integration for Ant tasks simply by relying on Groovy. Groovy is shipped with the fantastic AntBuilder. Using Ant tasks from Gradle is as convenient and more powerful than using Ant tasks from a build.xml file. From below example you can learn how to execute ant tasks and how to access ant properties:
Page 32 of 343
Example 6.13. Using AntBuilder to execute ant.loadfile target build.gradle
task loadfile << {
def files = file('../antLoadfileResources').listFiles().sort() files.each { File file ->
if (file.isFile()) {
ant.loadfile(srcFile: file, property: file.name) println " *** $file.name ***"
println "${ant.properties[file.name]}"
}
}
}
Output of gradle -q loadfile
> gradle -q loadfile
*** agile.manifesto.txt ***
Individuals and interactions over processes and tools Working software over comprehensive documentation Customer collaboration over contract negotiation Responding to change over following a plan
*** gradle.manifesto.txt ***
Make the impossible possible, make the possible easy and make the easy elegant (inspired by Moshe Feldenkrais)
There is lots more you can do with Ant in your build scripts. You can find out more in Chapter 20,
Using Ant from Gradle.
6.11. Using methods
Gradle scales in how you can organize your build logic. The first level of organizing your build logic for the example above, is extracting a method.
Page 33 of 343
Example 6.14. Using methods to organize your build logic build.gradle
task checksum << { fileList('../antLoadfileResources').each {File file ->
ant.checksum(file: file, property: "cs_$file.name")
println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
}
}
task loadfile << { fileList('../antLoadfileResources').each {File file ->
ant.loadfile(srcFile: file, property: file.name) println "I'm fond of $file.name"
}
}
File[] fileList(String dir) {
file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}
Output of gradle -q loadfile
> gradle -q loadfile
I'm fond of agile.manifesto.txt I'm fond of gradle.manifesto.txt
Later you will see that such methods can be shared among subprojects in multi-project builds. If your build logic becomes more complex, Gradle offers you other very convenient ways to organize it. We have devoted a whole chapter to this. See Chapter 52, Organizing Build Logic.
6.12. Default tasks
Gradle allows you to define one or more default tasks for your build.
Page 34 of 343
Example 6.15. Defining a default tasks
build.gradle
defaultTasks 'clean', 'run'
task clean << {
println 'Default Cleaning!'
}
task run << {
println 'Default Running!'
}
task other << {
println "I'm not a default task!"
}
Output of gradle -q
> gradle -q Default Cleaning! Default Running!
This is equivalent to running gradle clean run. In a multi-project build every subproject can have its own specific default tasks. If a subproject does not specify default tasks, the default tasks of the parent project are used (if defined).
6.13. Configure by DAG
As we describe in full detail later (See Chapter 48, The Build Lifecycle) Gradle has a configuration phase and an execution phase. After the configuration phase Gradle knows all tasks that should be executed. Gradle offers you a hook to make use of this information. A use-case for this would be to check if the release task is part of the tasks to be executed. Depending on this you can assign different values to some variables.
In the following example, execution of distribution and release tasks results in different value of version variable.
Page 35 of 343
Example 6.16. Different outcomes of build depending on chosen tasks
build.gradle
task distribution << {
println "We build the zip with version=$version"
}
task release(dependsOn: 'distribution') << { println 'We release now'
}
gradle.taskGraph.whenReady {taskGraph -> if (taskGraph.hasTask(release)) {
version = '1.0' } else {
version = '1.0-SNAPSHOT'
}
}
Output of gradle -q distribution
> gradle -q distribution
We build the zip with version=1.0-SNAPSHOT
Output of gradle -q release
> gradle -q release
We build the zip with version=1.0 We release now
The important thing is, that the fact that the release task has been chosen, has an effect before the release task gets executed. Nor has the release task to be the primary task (i.e. the task passed to the gradle command).
6.14. Where to next?
In this chapter, we have had a first look at tasks. But this is not the end of the story for tasks. If you want to jump into more of the details, have a look at Chapter 17, More about Tasks.
Otherwise, continue on to the tutorials in Chapter 7, Java Quickstart and Chapter 8, Dependency Management Basics.
[2] There are command line switches to change this behavior. See Appendix C, Gradle Command Line)
Page 36 of 343