第十四章. 教程 - 杂七杂八

Chapter 14. Tutorial - 'This and That'

14.1. 创建目录

14.1. Directory creation

有一个常见的情况是,有多个任务依赖于某个目录的存在。当然,你可以在这些任务开始时执行mkdir来解决这个问题。但这是一种臃肿的解决方法。更好的解决方案是这样的(仅适用于需要某个目录的这些任务有依赖关系的情况):
There is a common situation, that multiple tasks depend on the existence of a directory. Of course you can deal with this by adding a mkdir to the beginning of those tasks. But this is kind of bloated. There is a better solution (works only if the tasks that need the directory have a dependsOn relationship):

示例 14.1. 使用 mkdir 创建目录 - Example 14.1. Directory creation with mkdir

build.gradle

def classesDir = new File('build/classes')

task resources << {
    classesDir.mkdirs()
    // do something
}
task compile(dependsOn: 'resources') << {
    if (classesDir.isDirectory()) {
        println 'The class directory exists. I can operate'
    }
    // do something
}

gradle -q compile的输出结果
Output of gradle -q compile

> gradle -q compile
The class directory exists. I can operate

14.2. Gradle 属性和系统属性

14.2. Gradle properties and system properties

Gradle提供了多种方式可以向构建添加属性。使用-D命令行选项可以将系统属性传给运行Gradle的JVM。gradle命令的-D选项与java命令的-D选项具有同样的效果。
Gradle offers a variety of ways to add properties to your build. With the -D command line option you can pass a system property to the JVM which runs Gradle. The -D option of the gradle command has the same effect as the -D option of the java command.

你也可以使用属性文件直接向项目对象添加属性。你可以在Gradle用户主目录(默认为USER_HOME/.gradle),或是项目目录中放一个gradle.properties文件。对于多项目构建,gradle.properties文件可以放在任何子项目的目录中。gradle.properties的属性可以通过project对象访问。用户主目录中的属性文件会比项目目录中的属性文件更先被访问到。
You can also directly add properties to your project objects using properties files. You can place a gradle.properties file in the Gradle user home directory (defaults to USER_HOME/.gradle) or in your project directory. For multi-project builds you can place gradle.properties files in any subproject directory. The properties of the gradle.properties can be accessed via the project object. The properties file in the user's home directory has precedence over property files in the project directories.

您还可以通过-P命令行选项直接添加属性到project对象。在更多的用法中,你甚至可以通过系统和环境属性把属性直接传到project对象。例如,如果你在持续集成服务器上运行构建,但你没有这台机器的管理员权限,而你的构建脚本需要一些属性,这些属性又不能让其他人看到。那么你就不能使用-P选项。在这种情况下,您可以在项目管理部分(对普通用户不可见)添加一个环境属性。 [6]如果这个环境属性遵循ORG_GRADLE_PROJECT_propertyName=someValue的模式, propertyName就会被添加到你的项目对象中。我们也支持系统属性相同的机制。唯一的区别就是模式,它是org.gradle.project.propertyName
You can also add properties directly to your project object via the -P command line option. For more exotic use cases you can even pass properties directly to the project object via system and environment properties. For example if you run a build on a continuous integration server where you have no admin rights for the machine. Your build script needs properties which values should not be seen by others. Therefore you can't use the -P option. In this case you can add an environment property in the project administration section (invisible to normal users). [6] If the environment property follows the pattern ORG_GRADLE_PROJECT_propertyName=somevalue, propertyName is added to your project object. We also support the same mechanism for system properties. The only difference is the pattern, which is org.gradle.project.propertyName.

通过gradle.properties文件,你还可以设置一些系统属性。如果这类文件中的属性具有systemProp.前缀,该属性及其值将被添加到系统属性中,而不带此前缀。在多项目建设中,非根目录下的systemProp.属性会被忽略。也就是说,只有在根项目中的gradle.properties文件里的systemProp.属性才会被设置为系统属性。
With the gradle.properties files you can also set system properties. If a property in such a file has the prefix systemProp. the property and its value are added to the system properties, without the prefix. In a multi project build, systemProp. properties set in any project except the root will be ignored. That is, only systemProp. in the root project's gradle.properties file will be set as system properties.

示例 14.2. 使用 gradle.properties 文件设置属性 - Example 14.2. Setting properties with a gradle.properties file

gradle.properties

gradlePropertiesProp=gradlePropertiesValue
systemProjectProp=shouldBeOverWrittenBySystemProp
envProjectProp=shouldBeOverWrittenByEnvProp
systemProp.system=systemValue

build.gradle

task printProps << {
    println commandLineProjectProp
    println gradlePropertiesProp
    println systemProjectProp
    println envProjectProp
    println System.properties['system']
}

gradle -q -PcommandLineProjectProp=commandLineProjectPropValue -Dorg.gradle.project.systemProjectProp=systemPropertyValue printProps的输出结果
Output of gradle -q -PcommandLineProjectProp=commandLineProjectPropValue -Dorg.gradle.project.systemProjectProp=systemPropertyValue printProps

> gradle -q -PcommandLineProjectProp=commandLineProjectPropValue -Dorg.gradle.project.systemProjectProp=systemPropertyValue printProps
commandLineProjectPropValue
gradlePropertiesValue
systemPropertyValue
envPropertyValue
systemValue

14.2.1.检查项目的属性

14.2.1. Checking for project properties

你可以通过属性的名称在构建脚本里访问这个属性,如同使用一个变量一样。如果这个属性不存在,那么就会抛出异常并且构建失败。如果你的构建脚本依赖于一些可选属性,而这些属性用户可能在比如gradle.properties文件中设置,你就需要在访问它们之前先检查它们是否存在。你可以通过使用 hasProperty('propertyName') 方法来进行检查,它会返回truefalse
You can access a project property in your build script simply by using its name as you would use a variable. In case this property does not exists, an exception is thrown and the build fails. If your build script relies on optional properties the user might set for example in a gradle.properties file, you need to check for existence before you can access them. You can do this by using the method hasProperty('propertyName') which returns true or false.

14.3. 使用外部构建脚本配置项目

14.3. Configuring the project using an external build script

你可以使用外部构建脚本来配置当前项目。所有的Gradle构建语言都可以在外部脚本中使用,甚至你也可以从外部脚本应用其他脚本。
You can configure the current project using an external build script. All of the Gradle build language is available in the external script. You can even apply other scripts from the external script.

示例14.3. 使用外部构建脚本配置项目 - Example 14.3. Configuring the project using an external build script

build.gradle

apply from: 'other.gradle'

other.gradle

println "configuring $project"
task hello << {
    println 'hello from other script'
}

gradle -q hello的输出结果
Output of gradle -q hello

> gradle -q hello
configuring root project 'configureProjectUsingScript'
hello from other script

14.4. 配置任意对象

14.4. Configuring arbitrary objects

你可以使用以下非常易于理解的方式配置任意对象。
You can configure arbitrary objects in the following very readable way.

示例 14.4. 配置任意对象 - Example 14.4. Configuring arbitrary objects

build.gradle

task configure << {
    def pos = configure(new java.text.FieldPosition(10)) {
        beginIndex = 1
        endIndex = 5
    }
    println pos.beginIndex
    println pos.endIndex
}

gradle -q configure的输出结果
Output of gradle -q configure

> gradle -q configure
1
5

14.5. 使用外部脚本配置任意对象

14.5. Configuring arbitrary objects using an external script

你还可以使用外部脚本配置任意对象。
You can also configure arbitrary objects using an external script.

示例14.5. 使用脚本配置任意对象 - Example 14.5. Configuring arbitrary objects using a script

build.gradle

task configure << {
    def pos = new java.text.FieldPosition(10)
    // Apply the script
    apply from: 'other.gradle', to: pos
    println pos.beginIndex
    println pos.endIndex
}

other.gradle


      

gradle -q configure的输出结果
Output of gradle -q configure

> gradle -q configure
1
5

14.6. 缓存

14.6. Caching

为了提高响应速度,Gradle默认情况下会缓存所有已编译的脚本,包括所有构建脚本,初始化脚本和其他脚本。当你第一次运行项目构建时,Gradle会创建一个.gradle目录用于存放已编译的脚本。下次运行此构建时,如果脚本上次编译之后没有更改,则Gradle将使用已编译的脚本。否则该脚本会被重新编译,并把新版本存储在缓存中。如果你使用 --recompile-scripts选项来执行Gradle,那么会放弃所缓存的脚本,然后重新编译脚本并将其存在缓存中。通过这种方式,你就可以强制Gradle重新生成缓存。
To improve responsiveness Gradle caches all compiled scripts by default. This includes all build scripts, initialization scripts, and other scripts. The first time you run a build for a project, Gradle creates a .gradle directory in which it puts the compiled script. The next time you run this build, Gradle uses the compiled script, if the script has not changed since it was compiled. Otherwise the script gets compiled and the new version is stored in the cache. If you run Gradle with the --recompile-scripts option, the cached script is discarded and the script is compiled and stored in the cache. This way you can force Gradle to rebuild the cache.



[6] TeamcityBamboo就是作为提供这一功能的 CI 服务器的例子。
[6] Teamcity or Bamboo are for example CI servers which offer this functionality.