Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Gradle.pdf
Скачиваний:
9
Добавлен:
24.03.2015
Размер:
1.4 Mб
Скачать

17.8. Skipping tasks that are up-to-date

If you are using one of the tasks that come with Gradle, such as a task added by the Java plugin, you might have noticed that Gradle will skip tasks that are up-to-date. This behaviour is also available for your tasks, not just for built-in tasks.

17.8.1. Declaring a task's inputs and outputs

Let's have a look at an example. Here our task generates several output files from a source XM file. Let's run it a couple of times.

Example 17.21. A generator task

build.gradle

task transform {

ext.srcFile = file('mountains.xml') ext.destDir = new File(buildDir, 'generated') doLast {

println "Transforming source file." destDir.mkdirs()

def mountains = new XmlParser().parse(srcFile) mountains.mountain.each { mountain ->

def name = mountain.name[0].text()

def height = mountain.height[0].text()

def destFile = new File(destDir, "${name}.txt") destFile.text = "$name -> ${height}\n"

}

}

}

Output of gradle transform

> gradle transform :transform

Transforming source file.

Output of gradle transform

> gradle transform :transform

Transforming source file.

Notice that Gradle executes this task a second time, and does not skip the task even though nothing has changed. Our example task was defined using an action closure. Gradle has no idea what the closure does and cannot automatically figure out whether the task is up-to-date or not. To use Gradle's up-to-date checking, you need to declare the inputs and outputs of the task.

Each task has an inputs and outputs property, which you use to declare the inputs and outputs of the task. Below, we have changed our example to declare that it takes the source XML file as an input and produces output to a destination directory. Let's run it a couple of times.

Page 95 of 343

Example 17.22. Declaring the inputs and outputs of a task build.gradle

task transform {

ext.srcFile = file('mountains.xml') ext.destDir = new File(buildDir, 'generated') inputs.file srcFile

outputs.dir destDir doLast {

println "Transforming source file." destDir.mkdirs()

def mountains = new XmlParser().parse(srcFile) mountains.mountain.each { mountain ->

def name = mountain.name[0].text()

def height = mountain.height[0].text()

def destFile = new File(destDir, "${name}.txt") destFile.text = "$name -> ${height}\n"

}

}

}

Output of gradle transform

> gradle transform :transform

Transforming source file.

Output of gradle transform

> gradle transform :transform UP-TO-DATE

Now, Gradle knows which files to check to determine whether the task is up-to-date or not.

The task'sinputs property is of type TaskInputs. The task'soutputs property is of type

TaskOutputs.

17.8.2. How does it work?

Before a task is executed for the first time, Gradle takes a snapshot of the inputs. This snapshot contains the set of input files and a hash of the contents of each file. Gradle then executes the task. If the task completes successfully, Gradle takes a snapshot of the outputs. This snapshot contains the set of output files and a hash of the contents of each file. Gradle takes note of any files created, changed or deleted in the output directories of the task. Gradle persists both snapshots for next time the task is executed.

Each time after that, before the task is executed, Gradle takes a new snapshot of the inputs and outputs. If the new snapshots are the same as the previous snapshots, Gradle assumes that the outputs are up to date and skips the task. If they are not the same, Gradle executes the task. Gradle persists both snapshots for next time the task is executed.

Page 96 of 343

17.9. Task rules

Sometimes you want to have a task which behavior depends on a large or infinite number value range of parameters. A very nice and expressive way to provide such tasks are task rules:

Example 17.23. Task rule

build.gradle

tasks.addRule("Pattern: ping<ID>") { String taskName -> if (taskName.startsWith("ping")) {

task(taskName) << {

println "Pinging: " + (taskName - 'ping')

}

}

}

Output of gradle -q pingServer1

> gradle -q pingServer1 Pinging: Server1

The String parameter is used as a description for the rule. This description is shown when running for example gradle tasks.

Rules not just work for calling tasks from the command line. You can also create dependsOn relations on rule based tasks:

Example 17.24. Dependency on rule based tasks

build.gradle

tasks.addRule("Pattern: ping<ID>") { String taskName -> if (taskName.startsWith("ping")) {

task(taskName) << {

println "Pinging: " + (taskName - 'ping')

}

}

}

task groupPing {

dependsOn pingServer1, pingServer2

}

Output of gradle -q groupPing

> gradle -q groupPing Pinging: Server1 Pinging: Server2

Page 97 of 343

17.10. Summary

If you are coming from Ant, such an enhanced Gradle task as Copy looks like a mixture between an Ant target and an Ant task. And this is actually the case. The separation that Ant does between tasks and targets is not done by Gradle. The simple Gradle tasks are like Ant's targets and th enhanced Gradle tasks also include the Ant task aspects. All of Gradle's tasks share a commo API and you can create dependencies between them. Such a task might be nicer to configure than an Ant task. It makes full use of the type system, is more expressive and easier to maintain.

[7] You might be wondering why there is neither an import for the StopExecutionException nor do we access it via its fully qualified name. The reason is, that Gradle adds a set of default imports to your script. These imports are customizable (see Appendix D, Existing IDE Support and how to cope without it).

Page 98 of 343

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]