<!--
  ~ Copyright 2009 the original author or authors.
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->
<chapter id='more_about_tasks' xmlns:xi="http://www.w3.org/2001/XInclude">
    <title>More about Tasks</title>
    <para>In the introductory tutorial (<xref linkend='tutorial_using_tasks'/>) you have learned how to
        create simple tasks. You have also learned how to add additional behavior to these tasks later on. And you have
        learned how to create dependencies between tasks. This was all about simple tasks. But Gradle takes the concept
        of tasks further. Gradle supports <firstterm>enhanced tasks</firstterm>, that is, tasks which have their own
        properties and methods. This is really different to what you are used to with Ant targets. Such enhanced tasks are
        either provided by you or are provided by Gradle.
    </para>
    <section>
        <title>Defining tasks</title>
        <para>We have already seen how to define tasks using a keyword style in <xref linkend="tutorial_using_tasks"/>.
            There are a few variations on this style, which you may need to use in certain situations. For example,
            the keyword style does not work in expressions.
        </para>
        <sample id="defineAsExpression" dir="userguide/tasks/defineAsExpression" title="Defining tasks">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>You can also use strings for the task names:</para>
        <sample id="defineUsingStringTaskNames" dir="userguide/tasks/defineUsingStringTaskNames" title="Defining tasks - using strings">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>There is an alternative syntax for defining tasks, which you may prefer to use:</para>
        <sample id="addToTaskContainer" dir="userguide/tasks/addToTaskContainer" title="Defining tasks with alternative syntax">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>Here we add tasks to the <literal>tasks</literal> collection. Have a look at
            <apilink class="org.gradle.api.tasks.TaskContainer"/> for more variations of the <literal>add()</literal>
            method.</para>
    </section>
    <section>
        <title>Locating tasks</title>
        <para>You often need to locate the tasks that you have defined in the build file, for example, to configure them
            or use them for dependencies. There are a number of ways you can do this. Firstly, each task is available as
            a property of the project, using the task name as the property name:
        </para>
        <sample id="accessAsProperty" dir="userguide/tasks/accessAsProperty" title="Accessing tasks as properties">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>Tasks are also available through the <literal>tasks</literal> collection.</para>
        <sample id="accessFromTaskContainer" dir="userguide/tasks/accessFromTaskContainer" title="Accessing tasks via tasks collection">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>You can access tasks from any project using the task's path using the <literal>tasks.getByPath()</literal>
            method. You can call the <literal>getByPath()</literal> method with a task name, or a relative path, or an
            absolute path.</para>
        <sample id="accessUsingPath" dir="userguide/tasks/accessUsingPath" title="Accessing tasks by path">
            <sourcefile file="build.gradle"/>
            <output args="-q hello"/>
        </sample>
        <para>Have a look at <apilink class="org.gradle.api.tasks.TaskContainer"/> for more options for locating tasks.</para>
    </section>
    <section id='sec:configuring_tasks'>
        <title>Configuring tasks</title>
        <para>As an example, let's look at the <classname>Copy</classname> task provided by Gradle. To create a
            <classname>Copy</classname> task for your build, you can declare in your build script:
            <footnote>
                <para>If you use the Java Plugin, this task is automatically created and added to your project.
                </para>
            </footnote>
        </para>
        <sample id="declareTask" dir="userguide/tasks/configureUsingClosure" title="Creating a copy task">
            <sourcefile file="build.gradle" snippet="declare-task"/>
        </sample>
        <para>This creates a copy task with no default behavior.
            The task can be configured using its API (see <apilink class="org.gradle.api.tasks.Copy"/>).
			The following examples show several different ways to achieve the same configuration.
        </para>
        <sample id="configureUsingVar" dir="userguide/tasks/configureUsingVar" title="Configuring a task - various ways">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>This is similar to the way we would normally configure objects in Java. You have to repeat the context
            (<literal>myCopy</literal>) in the configuration statement every time. This is a redundancy and not very
            nice to read.
        </para>
        <para>There is a more convenient way of doing this.
        </para>
        <sample id="configureUsingLiterateStyle" dir="userguide/tasks/configureUsingLiterateStyle" title="Configuring a task - fluent interface">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>You might know this approach from the Hibernates Criteria Query API or JMock. Of course the API of a task
            has to support this. The <literal>from</literal>, <literal>to</literal> and <literal>include</literal>
            methods all return an object that may be used to chain to additional configuration methods. Gradle's build-in tasks usually
            support this configuration style.
        </para>
        <para>But there is yet another way of configuring a task. It also preserves the context and it is arguably the
            most readable. It is usually our favorite.
        </para>
        <sample id="configureUsingClosure" dir="userguide/tasks/configureUsingClosure" title="Configuring a task - with closure">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>This works for <emphasis>any</emphasis> task. Line 3 of the example is just a shortcut for the
            <literal>tasks.getByName()</literal> method. It is important to note that if you pass a closure to the
            <literal>getByName()</literal> method, this closure is applied to <emphasis>configure</emphasis> the task.
        </para>
        <para>There is a slightly different ways of doing this.</para>
        <sample id="configureUsingConfigure" dir="userguide/tasks/configureUsingConfigure" title="Configuring a task - with configure() method">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>Every task has a <literal>configure()</literal> method, which you can pass a closure for configuring the task.
            Gradle uses this style for configuring objects in many places, not just for tasks.
        </para>
        <para>You can also use a configuration closure when you define a task.</para>
        <sample id="defineAndConfigure" dir="userguide/tasks/defineAndConfigure" title="Defining a task with closure">
            <sourcefile file="build.gradle" snippet="no-description"/>
        </sample>
    </section>
    <section id='sec:adding_dependencies_to_tasks'>
        <title>Adding dependencies to a task</title>
        <para>There are several ways you can define the dependencies of a task. In
            <xref linkend='sec:task_dependencies'/>
            you were introduced to defining dependencies using task names. Task names can refer to tasks in the same
            project as the task, or to tasks in other projects. To refer to a task in another project, you prefix the
            name of the task with the path of the project it belongs to. Below is an example which adds a dependency
            from
            <literal>projectA:taskX</literal>
            to
            <literal>projectB:taskY</literal>:
        </para>
        <sample id="addDependencyUsingPath" dir="userguide/tasks/addDependencyUsingPath" title="Adding dependency on task from another project">
            <sourcefile file="build.gradle"/>
            <output args="-q taskX"/>
        </sample>
        <para>Instead of using a task name, you can define a dependency using a
            <classname>Task</classname> object, as shown in this example:
        </para>
        <sample id="addDependencyUsingTask" dir="userguide/tasks/addDependencyUsingTask" title="Adding dependency using task object">
            <sourcefile file="build.gradle"/>
            <output args="-q taskX"/>
        </sample>
        <para>For more advanced uses, you can define a task dependency using a closure. When evaluated, the closure is
            passed the task whose dependencies are being calculated. The closure should return a single
            <classname>Task</classname> or collection of <classname>Task</classname> objects, which are then treated
            as dependencies of the task. The following example adds a dependency from <literal>taskX</literal>
            to all the tasks in the project whose name starts with <literal>lib</literal>:
        </para>
        <sample id="addDependencyUsingClosure" dir="userguide/tasks/addDependencyUsingClosure" title="Adding dependency using closure">
            <sourcefile file="build.gradle"/>
            <output args="-q taskX"/>
        </sample>
        <para>For more information about task dependencies, see the <apilink class="org.gradle.api.Task"/> API.</para>
    </section>
    <section>
        <title>Adding a description to a task</title>
        <para>You can add a description to your task. This description is for example displayed when executing
            <code>gradle -t</code>.
        </para>
        <sample id="describeTask" dir="userguide/tasks/defineAndConfigure" title="Adding a description to a task">
            <sourcefile file="build.gradle"/>
        </sample>
    </section>
    <section>
        <title>Replacing tasks</title>
        <para>Sometimes you want to replace a task. For example if you want to exchange a task added by the Java Plugin
            with a custom task of a different type. You can achieve this with:
        </para>
        <sample id="replaceTask" dir="userguide/tutorial/replaceTask" title="Overwriting a task">
            <sourcefile file="build.gradle"/>
            <output args="-q copy"/>
        </sample>
        <para>Here we replace a task of type <literal>Copy</literal> with a simple task. When creating the simple
            task, you have to set the <literal>overwrite</literal> property to true. Otherwise Gradle throws an
            exception, saying that a task with such a name already exists.
        </para>
    </section>
    <section>
        <title>Skipping tasks</title>
        <para>Gradle offers multiple ways to skip the execution of a task.</para>

        <section>
            <title>Using a predicate</title>
            <para>You can use the <literal>onlyIf()</literal> method to attach a predicate to a task. The task's
                actions are only executed if the predicate evaluates to true. You implement the predicate as a closure.
                The closure is passed the task as a parameter, and should return true if the task should execute
                and false if the task should be skipped. The predicate is evaluated just before the task is due
                to be executed.
                </para>
            <sample id="taskOnlyIf" dir="userguide/tutorial/taskOnlyIf" title="Skipping a task using a predicate">
                <sourcefile file="build.gradle"/>
                <output args="hello -PskipHello"/>
            </sample>
        </section>

        <section>
        <title>Using StopExecutionException</title>
        <para>If the rules for skipping a task can't be expressed with predicate, you can use the
            <apilink class="org.gradle.api.tasks.StopExecutionException"/>. If this exception is thrown by an action,
            the further execution of this action as well as the execution of
            any following action of this task is skipped. The build continues with executing the next task.
        </para>
        <sample id="stopExecutionException" dir="userguide/tutorial/stopExecutionException" title="Skipping tasks with StopExecutionException">
            <sourcefile file="build.gradle"/>
            <output args="-q myTask"/>
        </sample>
        <para>This feature is helpful if you work with tasks provided by Gradle. It allows you to add
            <emphasis>conditional</emphasis> execution of the built-in actions of such a task.
            <footnote>
                <para>You might be wondering why there is neither an import for the
                    <literal>StopExecutionException</literal>
                    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 <xref linkend='ide_support'/>).
                </para>
            </footnote>
        </para>
        </section>

        <section>
        <title>Enabling and disabling tasks</title>
        <para>Every task has also an <literal>enabled</literal>
            flag which defaults to <literal>true</literal>. Setting it to <literal>false</literal> prevents the
            execution of any of the task's actions.
        </para>
        <sample id="disableTask" dir="userguide/tutorial/disableTask" title="Enabling and disabling tasks">
            <sourcefile file="build.gradle"/>
            <output args="disableMe"/>
        </sample>
        </section>
    </section>
    
    <section>
        <title>Task rules</title>
        <para>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: 
        </para>
        <sample id="taskRule" dir="userguide/tasks/addRules" title="Task rule">
            <sourcefile file="build.gradle" snippet="task-rule"/>
            <output args="-q pingServer1"/>
        </sample>
        <para>The String parameter is used as a description for the rule. This description is shown when doing
            for example <code>gradle -t</code>.
        </para>
        <para>Rules not just work for calling tasks from the command line. You can also create dependsOn relations
            on rule based tasks:
        </para>
        <sample id="taskRuleDependsOn" dir="userguide/tasks/addRules" title="Dependency on rule based tasks">
            <sourcefile file="build.gradle"/>
            <output args="-q groupPing"/>
        </sample>
    </section>
    <section id='sec:the_idea_behind_gradle_tasks'>
        <title>Summary</title>
        <para>If you are coming from Ant, such an enhanced Gradle task as <emphasis>Copy</emphasis> 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 the enhanced
            Gradle tasks also include the Ant task aspects. All of Gradle's tasks share a common 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.
        </para>
    </section>
</chapter>
