This chapter looks at some of the details of writing a build script.
Gradle provides a domain specific language, or DSL, for describing builds. This build language is based on Groovy, with some additions to make it easier to describe a build.
In the tutorial in Chapter 7, Java Quickstart we used, for example, the
apply()
method. Where does this method come from? We said earlier that the build script
defines a project in Gradle. For each project in the build creates an instance of type
Project
and associates this Project
object with
the build script. As the build script executes, it configures this Project
object:
Don't forget that your build script is simply Groovy code that drives the Gradle API. And the
Project
interface is your starting point for accessing everything
in the Gradle API. So, if you're wondering what 'tags' are available in your build script, you can
start with the documentation for the Project
interface.
Any method you call in your build script, which is not defined
in the build script, is delegated to the Project
object.
Any property you access in your build script, which is not defined
in the build script, is delegated to the Project
object.
Let's try this out and try to access the name
property of the
Project
object.
Example 15.1. Accessing property of the Project object
build.gradle
println name println project.name
Output of gradle -q check
> gradle -q check projectApi projectApi
Both println
statements print out the same property. The first uses auto-delegation to
the Project
object, for properties not defined in the build script. The other
statement uses the project
property available to any build script, which returns the
associated Project
object. Only if you define a property or a method which has the
same name as a member of the Project
object, you need to use the project
property.
The Project
object provides some standard properties, which are available in
your build script. The following table lists a few of the commonly used ones.
Table 15.1. Project Properties
Name | Type | Default Value |
project |
Project |
The Project instance |
name |
String |
The name of the project directory. |
path |
String |
The absolute path of the project. |
description |
String |
A description for the project. |
projectDir |
File |
The directory containing the build script. |
buildDir |
File |
|
group |
Object |
unspecified |
version |
Object |
unspecified |
ant |
AntBuilder |
An AntBuilder instance |
When Gradle executes a script, it compiles the script into a class which implements Script
.
This means that all of the properties and methods declared by the Script
interface
are available in your script.
Groovy provides plenty of features for creating DSLs, and the Gradle build language takes advantage of these. Understanding how the build language works will help you when you write your build script, and in particular, when you start to write customs plugins and tasks.
Groovy adds lots of useful methods to JVM classes. For example, Iterable
gets
an each
method, which iterates over the elements of the Iterable
:
Example 15.2. Groovy JDK methods
build.gradle
// Iterable gets an each() method
configurations.runtime.each { File f -> println f }
Have a look at http://groovy.codehaus.org/groovy-jdk/ for more details.
Groovy automatically converts a property reference into a call to the appropriate getter or setter method.
Example 15.3. Property accessors
build.gradle
// Using a getter method println project.buildDir println getProject().getBuildDir() // Using a setter method project.buildDir = 'target' getProject().setBuildDir('target')
Parentheses are optional for method calls.
Example 15.4. Method call without parentheses
build.gradle
test.systemProperty 'some.prop', 'value' test.systemProperty('some.prop', 'value')
Groovy provides some shortcuts for defining List
and Map
instances.
Example 15.5. List and map literals
build.gradle
// List literal test.includes = ['org/gradle/api/**', 'org/gradle/internal/**'] List<String> list = new ArrayList<String>() list.add('org/gradle/api/**') list.add('org/gradle/internal/**') test.includes = list // Map literal apply plugin: 'java' Map<String, String> map = new HashMap<String, String>() map.put('plugin', 'java') apply(map)
The Gradle DSL uses closures in many places. You can find out more about closures here. When the last parameter of a method is a closure, you can place the closure after the method call:
Example 15.6. Closure as method parameter
build.gradle
repositories { println "in a closure" } repositories() { println "in a closure" } repositories({ println "in a closure" })
Each closure has a delegate
object, which Groovy uses to look up variable and method
references which are not local variables or parameters of the closure. Gradle uses this for
configuration closures, where the delegate
object is set to
the object to be configured.
Example 15.7. Closure delegates
build.gradle
dependencies { assert delegate == project.dependencies compile('junit:junit:4.8.2') delegate.compile('junit:junit:4.8.2') }