<!--
  ~ Copyright 2010 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='writing_build_scripts' xmlns:xi="http://www.w3.org/2001/XInclude">
    <title>Writing Build Scripts</title>
    <para>This chapter looks at some of the details of writing a build script.</para>

    <section id="sec:the_gradle_build_language">
        <title>The Gradle build language</title>
        <para>Gradle provides a <firstterm>domain specific language</firstterm>, or DSL, for describing builds.
            This build language is based on Groovy, with some additions to make it easier to describe a build.
        </para>
        <para>
            A build script can contain any Groovy language element.
            <footnote><para>Any language element except for statement labels.</para></footnote>
            Gradle assumes that each build script is encoded using UTF-8.
        </para>
    </section>
    <section id="sec:project_api">
        <title>The Project API</title>
        <para>In the tutorial in <xref linkend='tutorial_java_projects'/> we used, for example, the
            <literal>apply()</literal> 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, Gradle creates an object of type
            <apilink class='org.gradle.api.Project'/> and associates this <classname>Project</classname> object with
            the build script. As the build script executes, it configures this <classname>Project</classname> object:
        </para>
        <tip>
            <title>Getting help writing build scripts</title>
            <para>Don't forget that your build script is simply Groovy code that drives the Gradle API. And the
                <apilink class='org.gradle.api.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 <classname>Project</classname> interface.
            </para>
        </tip>
        <itemizedlist>
            <listitem>
                <para>Any method you call in your build script which <emphasis>is not defined</emphasis>
                    in the build script, is delegated to the <classname>Project</classname> object.
                </para>
            </listitem>
            <listitem>
                <para>Any property you access in your build script, which <emphasis>is not defined</emphasis>
                    in the build script, is delegated to the <classname>Project</classname> object.
                </para>
            </listitem>
        </itemizedlist>
        <para>Let's try this out and try to access the <literal>name</literal> property of the
            <classname>Project</classname> object.
        </para>
        <sample id="projectApi" dir="userguide/tutorial/projectApi" title="Accessing property of the Project object">
            <sourcefile file="build.gradle" snippet="project-name"/>
            <output args="-q check"/>
        </sample>
        <para>Both <literal>println</literal> statements print out the same property. The first uses auto-delegation to
            the <classname>Project</classname> object, for properties not defined in the build script. The other
            statement uses the <literal>project</literal> property available to any build script, which returns the
            associated <classname>Project</classname> object. Only if you define a property or a method which has the
            same name as a member of the <classname>Project</classname> object, would you need to use the <literal>project</literal>
            property.
        </para>
        <section id="sec:standard_project_properties">
            <title>Standard project properties</title>
            <para>The <classname>Project</classname> object provides some standard properties, which are available in
                your build script. The following table lists a few of the commonly used ones.
            </para>
            <table>
                <title>Project Properties</title>
                <thead>
                    <tr>
                        <td>Name</td>
                        <td>Type</td>
                        <td>Default Value</td>
                    </tr>
                </thead>
                <tr>
                    <td><literal>project</literal></td>
                    <td><apilink class='org.gradle.api.Project'/></td>
                    <td>The <classname>Project</classname> instance</td>
                </tr>
                <tr>
                    <td><literal>name</literal></td>
                    <td><classname>String</classname></td>
                    <td>The name of the project directory.</td>
                </tr>
                <tr>
                    <td><literal>path</literal></td>
                    <td><classname>String</classname></td>
                    <td>The absolute path of the project.</td>
                </tr>
                <tr>
                    <td><literal>description</literal></td>
                    <td><classname>String</classname></td>
                    <td>A description for the project.</td>
                </tr>
                <tr>
                    <td><literal>projectDir</literal></td>
                    <td><classname>File</classname></td>
                    <td>The directory containing the build script.</td>
                </tr>
                <tr>
                    <td><literal>buildDir</literal></td>
                    <td><classname>File</classname></td>
                    <td><filename><replaceable>projectDir</replaceable>/build</filename></td>
                </tr>
                <tr>
                    <td><literal>group</literal></td>
                    <td><classname>Object</classname></td>
                    <td><literal>unspecified</literal></td>
                </tr>
                <tr>
                    <td><literal>version</literal></td>
                    <td><classname>Object</classname></td>
                    <td><literal>unspecified</literal></td>
                </tr>
                <tr>
                    <td><literal>ant</literal></td>
                    <td><apilink class="org.gradle.api.AntBuilder"/></td>
                    <td>An <classname>AntBuilder</classname> instance</td>
                </tr>
            </table>
        </section>
    </section>
    <section id="sec:the_script_api">
        <title>The Script API</title>
        <para>When Gradle executes a script, it compiles the script into a class which implements <apilink class="org.gradle.api.Script"/>.
            This means that all of the properties and methods declared by the <classname>Script</classname> interface
            are available in your script.
        </para>
    </section>
    <section id="sec:declaring_variables">
        <title>Declaring variables</title>
        <para>There are two kinds of variables that can be declared in a build script: local variables and extra properties.
        </para>
        <section id="sec:local_variables">
            <title>Local variables</title>
            <para>Local variables are declared with the <literal>def</literal> keyword. They are only visible in the scope where they have been declared.
                Local variables are a feature of the underlying Groovy language.
            </para>
            <sample id="localVariables" dir="userguide/tutorial/localVariables" title="Using local variables">
                <sourcefile file="build.gradle"/>
            </sample>
        </section>
        <section id="sec:extra_properties">
            <title>Extra properties</title>
            <para>All enhanced objects in Gradle's domain model can hold extra user-defined properties. This includes, but is not limited to, projects, tasks,
                and source sets. Extra properties can be added, read and set via the owning object's <literal>ext</literal> property. Alternatively, an
                <literal>ext</literal> block can be used to add multiple properties at once.
            </para>
            <sample id="extraProperties" dir="userguide/tutorial/extraProperties" title="Using extra properties">
                <sourcefile file="build.gradle" snippet="extraProperties"/>
                <output args="-q printProperties"/>
            </sample>
            <para>In this example, an <literal>ext</literal> block adds two extra properties to the <literal>project</literal> object. Additionally,
                a property named <literal>purpose</literal> is added to each source set by setting <literal>ext.purpose</literal> to
                <literal>null</literal> (<literal>null</literal> is a permissible value). Once the properties have been added, they can be read and set like
                predefined properties.
            </para>
            <para>By requiring special syntax for adding a property, Gradle can fail fast when an attempt is made to set a (predefined or extra) property
                but the property is misspelled or does not exist.
                Extra properties can be accessed from anywhere their owning object can be accessed, giving them a wider scope than local variables.
                Extra properties on a project are visible from its subprojects.
            </para>
            <para>For further details on extra properties and their API, see the <apilink class="org.gradle.api.plugins.ExtraPropertiesExtension"/> class in the API documentation.</para>
        </section>
    </section>
    <section id="sec:configuring_arbitrary_objects">
        <title>Configuring arbitrary objects</title>
        <para>You can configure arbitrary objects in the following very readable way.
        </para>
        <sample id="configureObject" dir="userguide/tutorial/configureObject" title="Configuring arbitrary objects">
            <sourcefile file="build.gradle"/>
            <output args="-q configure"/>
        </sample>
    </section>
    <section id="sec:configuring_arbitrary_objects_using_an_external_script">
        <title>Configuring arbitrary objects using an external script</title>
        <para>You can also configure arbitrary objects using an external script.
        </para>
        <sample id="configureObjectUsingScript" dir="userguide/tutorial/configureObjectUsingScript" title="Configuring arbitrary objects using a script">
            <sourcefile file="build.gradle"/>
            <sourcefile file="other.gradle"/>
            <output args="-q configure"/>
        </sample>
    </section>
    <section id="groovy-dsl-basics">
        <title>Some Groovy basics</title>
        <para>The <ulink url="http://docs.groovy-lang.org/latest/html/documentation/index.html">Groovy language</ulink> 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 custom plugins and tasks.
        </para>
        <section id="sec:groovy_jdk">
            <title>Groovy JDK</title>
            <para>
                Groovy adds lots of useful methods to the standard Java classes. For example, <classname>Iterable</classname> gets
                an <literal>each</literal> method, which iterates over the elements of the <classname>Iterable</classname>:
            </para>
            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Groovy JDK methods">
                <sourcefile file="build.gradle" snippet="groovyJdk"/>
            </sample>
            <para>Have a look at <ulink url="http://groovy-lang.org/gdk.html"/> for more details.</para>
        </section>
        <section id="sec:property_accessors">
            <title>Property accessors</title>
            <para>
               Groovy automatically converts a property reference into a call to the appropriate getter or setter method.
            </para>
            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Property accessors">
                <sourcefile file="build.gradle" snippet="propertyAccessors"/>
            </sample>
        </section>
        <section id="sec:optional_parentheses_on_method_calls">
            <title>Optional parentheses on method calls</title>
            <para>
                Parentheses are optional for method calls.
            </para>
            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Method call without parentheses">
                <sourcefile file="build.gradle" snippet="methodCallWithoutParentheses"/>
            </sample>
        </section>
        <section id="sec:list_and_map_literals">
            <title>List and map literals</title>
            <para>
                Groovy provides some shortcuts for defining <classname>List</classname> and <classname>Map</classname>
                instances.  Both kinds of literals are straightforward, but map literals have some interesting twists.
            </para>
            <para>For instance, the “<literal>apply</literal>” method (where you typically apply plugins) actually
            takes a map parameter.  However, when you have a line like “<literal>apply plugin:'java'</literal>”, you
            aren't actually using a map literal, you're actually using “named parameters”, which have almost exactly
            the same syntax as a map literal (without the wrapping brackets). That named parameter list gets converted
            to a map when the method is called, but it doesn't start out as a map.</para>
            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="List and map literals">
                <sourcefile file="build.gradle" snippet="listAndMapLiterals"/>
            </sample>
        </section>
        <section id="sec:closures_as_the_last_parameter_in_a_method">
            <title>Closures as the last parameter in a method</title>
            <para>The Gradle DSL uses closures in many places. You can find out more about closures <ulink url="http://docs.groovy-lang.org/latest/html/documentation/index.html#_closures">here</ulink>.
                When the last parameter of a method is a closure, you can place the closure after the method call:
            </para>
            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Closure as method parameter">
                <sourcefile file="build.gradle" snippet="closureAsLastParam"/>
            </sample>
        </section>
        <section id="sec:closure_delegate">
            <title>Closure delegate</title>
            <para>
                Each closure has a <literal>delegate</literal> 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
                <firstterm>configuration closures</firstterm>, where the <literal>delegate</literal> object is set to
                the object to be configured.
            </para>
            <sample id="groovyBasics" dir="userguide/tutorial/groovy" title="Closure delegates">
                <sourcefile file="build.gradle" snippet="closureDelegates"/>
            </sample>
        </section>
    </section>
    <section id="script-default-imports">
        <title>Default imports</title>
        <para>To make build scripts more concise, Gradle automatically adds a set of import statements to the Gradle scripts.
            This means that instead of using <literal>throw new org.gradle.api.tasks.StopExecutionException()</literal>
            you can just type <literal>throw new StopExecutionException()</literal>
            instead.
        </para>
        <para>Listed below are the imports added to each script:</para>
        <figure>
            <title>gradle-imports</title>
            <programlisting><xi:include href='../../../build/generated-resources/main/default-imports.txt' parse='text'/></programlisting>
        </figure>
    </section>
</chapter>
