May 25, 2021 Gradle
This chapter looks at some of the details of writing build scripts.
Gradle provides a domain-specific language, or DSL, to describe the build. This build language is based on Groovy and is supplemented to make it easy to describe the build.
In the Java Getting Started tutorial, we used the apply() method. W here does this method come from? W e said earlier that building scripts in Gradle defines a project. I n each project built, Gradle creates an instance of the Project type and associates the Project object in the build script. When the build script executes, it configures this Project object:
Let's try this, try visiting the name property of the Project object.
Access the properties of the Project object
build.gradle
println name
println project.name
The output of the gradle -q check
> gradle -q check
projectApi
projectApi
The two println statements print out the same properties. P roperties that are not defined in the build script are automatically delegated to the Project object the first time they are used. O ther statements use the project property that can be accessed in any build script, returning the associated Project object. You need to use the project property only if you define a property or a member of the method Project object with the same name.
Project objects provide some standard properties that are available in the build script. The following table lists several commonly used properties.
Table 13.1. The Project property
Name | Type | The default |
project
|
Project
|
Project
instance
|
name
|
String
|
The name of the project directory. |
path
|
String
|
The absolute path of the project. |
description
|
String
|
The description of the project. |
projectDir
|
File
|
The directory that contains the build script. |
buildDir
|
File
|
|
group
|
Object
|
未指定
|
version
|
Object
|
未指定
|
ant
|
AntBuilder
|
AntBuilder
instance
|
When Gradle executes a script, it compiles the script into a class that implements the Script interface. This means that all properties and methods declared by the Script interface are available in your script.
There are two types of variables that can be declared in the build script: local variables and additional properties.
Local variables are declared with the def keyword. T hey can only be accessed within the scope within which they are defined. Local variables are a feature of the bottom layer of the Groovy language.
Example 13.2. Use local variables
build.gradle
def dest = "dest"
task copy(type: Copy) {
from "source"
into dest
}
In Gradle's domain model, all enhanced objects can accommodate additional user-defined properties. T his includes, but is not limited to, projects, tasks, and source sets. A dditional properties can be added, read, and set by the ext property of the object to which they belong. Alternatively, you can use ext blocks to add multiple properties at the same time.
13.3 Examples. Use additional properties
build.gradle
apply plugin: "java"
ext {
springVersion = "3.1.0.RELEASE"
emailNotification = "[email protected]"
}
sourceSets.all { ext.purpose = null }
sourceSets {
main {
purpose = "production"
}
test {
purpose = "test"
}
plugin {
purpose = "production"
}
}
task printProperties << {
println springVersion
println emailNotification
sourceSets.matching { it.purpose == "production" }.each { println it.name }
}
The output of the gradle -q printProperties
> gradle -q printProperties
3.1.0.RELEASE
build@master.org
main
plugin
In this example, an ext block of code adds two additional properties to the project object. I n addition, by setting ext.purpose to null, an allowed value, a property named purpose is added to each source set. Once properties are added, they can be read and set like predetermined properties.
By adding a property that requires special syntax, Gradle can fail fast when you try to set a (predefined or additional) property, but the property is misspelled or does not exist. A dditional properties can be accessed anywhere they can access the objects to which they belong, which gives them a wider scope than local variables. Additional properties on the parent project can also be accessed in child projects.
For more information about the additional properties and their APIs, see ExtraPropertiesExtension.
Groovy provides a number of features for creating DSLs, and the Gradle build language leverages them. Understanding how the build language works will help you write build scripts, especially when you start writing custom plug-ins and tasks.
Groovy adds a number of useful methods to JVM classes. For example, the new each method for iterable traverses the elements of iterable:
Groovy JDK's method
build.gradle
// Iterable gets an each() method
configurations.runtime.each { File f -> println f }
Groovy automatically converts a reference to a property to a call to the appropriate getter or setter method.
Property accessor
build.gradle
// Using a getter method
println project.buildDir
println getProject().getBuildDir()
// Using a setter method
project.buildDir = 'target'
getProject().setBuildDir('target')
Parenthesis is optional when a method is called.
Method calls without parentheses
build.gradle
test.systemProperty 'some.prop', 'value'
test.systemProperty('some.prop', 'value')
Groovy provides some quick writing to define List and Map instances.
List and map
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)
Gradle DSL uses closures in many places. Y ou can see more information about the closed package here. When the last argument of the method is a closure, you can put the closure after the method call:
A closure that is used as a 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 that Groovy uses to find references to variables and methods, rather than as local variables or parameters for the closure. Gradle uses it in configuration closures, setting the delegate object as the configured object.
Closure delegate
build.gradle
dependencies {
assert delegate == project.dependencies
compile('junit:junit:4.11')
delegate.compile('junit:junit:4.11')
}