<!--
  ~ 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='organizing_build_logic' xmlns:xi="http://www.w3.org/2001/XInclude">
    <title>Organizing Build Logic</title>
    <para>Gradle offers a variety of ways to organize your build logic. First of all you can put your build logic
        directly in the action closure of a task. If a couple of tasks share the same logic you can extract this logic
        into a method. If multiple projects of a multi-project build share some logic you can define this method in the
        parent project. If the build logic gets too complex for being properly modeled by methods then you likely should
        implement your logic with classes to encapsulate your logic.
        <footnote>
            <para>Which might range from a single class to something very complex.
            </para>
        </footnote>
        Gradle makes this very easy. Just drop your classes in a certain directory and Gradle automatically compiles them
        and puts them in the classpath of your build script.
    </para>
    <para>Here is a summary of the ways you can organise your build logic:</para>
    <itemizedlist>
        <listitem>
            <para>POGOs. You can declare and use plain old Groovy objects (POGOs) directly in your build script. The
                build script is written in Groovy, after all, and Groovy provides you with lots of excellent ways to
                organize code.
            </para>
        </listitem>
        <listitem>
            <para><link linkend="sec:inherited_properties_and_methods">Inherited properties and methods</link>. In a
                multi-project build, sub-projects inherit the properties and methods of their parent project.</para>
        </listitem>
        <listitem>
            <para><link linkend="sec:injected_configuration">Configuration injection</link>. In a
                multi-project build, a project (usually the root project) can inject properties and methods into another
                project.</para>
        </listitem>
        <listitem>
            <para><link linkend="sec:build_sources"><filename>buildSrc</filename> project</link>. Drop the source for
                your build classes into a certain directory and Gradle automatically compiles them and includes them
                in the classpath of your build script.
            </para>
        </listitem>
        <listitem>
            <para><link linkend="sec:configuring_using_external_script">Shared scripts</link>. Define common configuration
                in an external build, and apply the script to multiple projects, possibly across different builds.
            </para>
        </listitem>
        <listitem>
            <para><link linkend="custom_tasks">Custom tasks</link>. Put your build logic into a custom task, and
                reuse that task in multiple places.</para>
        </listitem>
        <listitem>
            <para><link linkend="custom_plugins">Custom plugins</link>. Put your build logic into a custom plugin,
                and apply that plugin to multiple projects. The plugin must be in the classpath of your build script.
                You can achieve this either by using <link linkend="sec:build_sources"><filename>build sources</filename></link> or
                by adding an <link linkend="sec:external_dependencies">external library</link> that contains the plugin.
            </para>
        </listitem>
        <listitem>
            <para><link linkend="sec:external_build">Execute an external build</link>. Execute another Gradle build from the
                current build.</para>
        </listitem>
        <listitem>
            <para><link linkend="sec:external_dependencies">External libraries</link>. Use external libraries directly
                in your build file.
            </para>
        </listitem>
    </itemizedlist>

    <section id="sec:inherited_properties_and_methods">
        <title>Inherited properties and methods</title>
        <para>Any method or property defined in a project build script is also visible to all the sub-projects. You
            can use this to define common configurations, and to extract build logic into methods which can be reused
            by the sub-projects.
        </para>
        <sample id="inheritedBuildLogic" dir="userguide/organizeBuildLogic/inherited" title="Using inherited properties and methods">
            <sourcefile file="build.gradle"/>
            <sourcefile file="child/build.gradle"/>
            <output args="-q show"/>
        </sample>
    </section>

    <section id="sec:injected_configuration">
        <title>Injected configuration</title>
        <para>You can use the configuration injection technique discussed in <xref linkend="sec:cross_project_configuration"/>
            and <xref linkend="sec:subproject_configuration"/> to inject properties and methods into various projects.
            This is generally a better option than inheritance, for a number of reasons: The injection is
            explicit in the build script, You can inject different logic into different projects, And you can inject
            any kind of configuration such as repositories, plug-ins, tasks, and so on.
            The following sample shows how this works.
        </para>
        <sample id="injectedBuildLogic" dir="userguide/organizeBuildLogic/injected" title="Using injected properties and methods">
            <sourcefile file="build.gradle"/>
            <sourcefile file="child1/build.gradle"/>
            <output args="-q show"/>
        </sample>
    </section>

    <section id="sec:configuring_using_external_script">
        <title>Configuring the project using an external build script</title>
        <para>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.
        </para>
        <sample id="configureProjectUsingScript" dir="userguide/tutorial/configureProjectUsingScript" title="Configuring the project using an external build script">
            <sourcefile file="build.gradle"/>
            <sourcefile file="other.gradle"/>
            <output args="-q hello"/>
        </sample>
    </section>

    <section id='sec:build_sources'>
        <title>Build sources in the <filename>buildSrc</filename> project</title>
        <para>When you run Gradle, it checks for the existence of a directory called <filename>buildSrc</filename>.
            Gradle then automatically compiles and tests this code and puts it in the classpath of your build script.
            You don't need to provide any further instruction. This can be a good place to add your custom tasks and plugins.
        </para>
        <para>For multi-project builds there can be only one <filename>buildSrc</filename> directory, which has to be
            in the root project directory.
        </para>
        <para>Listed below is the default build script that Gradle applies to the <filename>buildSrc</filename> project:</para>
        <figure>
            <title>Default buildSrc build script</title>
            <programlisting><xi:include href='../../../../../subprojects/core/src/main/resources/org/gradle/initialization/buildsrc/defaultBuildSourceScript.txt' parse='text'/></programlisting>
        </figure>
        <para>
            This means that you can just put your build source code in this directory and stick to the layout convention for a
            Java/Groovy project (see <xref linkend='javalayout'/>).
        </para>
        <para>
            If you need more flexibility, you can provide your own <filename>build.gradle</filename>. Gradle applies the default build script
            regardless of whether there is one specified. This means you only need to declare the extra things you need. Below is an example.
            Notice that this example does not need to declare a dependency on the Gradle API, as this is done by the default build script:
        </para>
        <sample id="customBuildSrcBuild" dir="java/multiproject" title="Custom buildSrc build script">
            <sourcefile file="buildSrc/build.gradle"/>
        </sample>
        <para>
            The <filename>buildSrc</filename> project can be a multi-project build, just like any other regular multi-project build. However,
            all of the projects that should be on the classpath of the actual build must be <literal>runtime</literal> dependencies of the root project in
            <filename>buildSrc</filename>. You can do this by adding this to the configuration of each project you wish to export:
        </para>
        <sample id="multiProjectBuildSrc" dir="multiProjectBuildSrc" includeLocation="true" title="Adding subprojects to the root buildSrc project">
            <sourcefile file="buildSrc/build.gradle" snippet="addToRootProject"/>
        </sample>
    </section>

    <section id="sec:external_build">
        <title>Running another Gradle build from a build</title>
        <para>You can use the <apilink class="org.gradle.api.tasks.GradleBuild"/> task. You can use either of the
            <literal>dir</literal> or <literal>buildFile</literal> properties to specify which build to execute,
            and the <literal>tasks</literal> property to specify which tasks to execute.
        </para>
        <sample id="nestedBuild" dir="userguide/organizeBuildLogic/nestedBuild" title="Running another build from a build">
            <sourcefile file="build.gradle" snippet="execute-build"/>
            <sourcefile file="other.gradle"/>
            <output args="-q build"/>
        </sample>
    </section>

    <section id='sec:external_dependencies'>
        <title>External dependencies for the build script</title>
        <para>If your build script needs to use external libraries, you can add them to the script's classpath in the
            build script itself. You do this using the <literal>buildscript()</literal> method, passing in a closure which
            declares the build script classpath.
        </para>
        <sample id="declareExternalBuildDependency" dir="userguide/organizeBuildLogic/externalDependency" title="Declaring external dependencies for the build script">
            <sourcefile file="build.gradle" snippet="declare-classpath"/>
        </sample>
        <para>The closure passed to the <literal>buildscript()</literal> method configures a
            <apilink class="org.gradle.api.initialization.dsl.ScriptHandler"/> instance. You declare the build script
            classpath by adding dependencies to the <literal>classpath</literal> configuration. This is the same way
            you declare, for example, the Java compilation classpath. You can use any of the dependency types described
            in <xref linkend='sec:how_to_declare_your_dependencies'/>, except project dependencies.</para>
        <para>Having declared the build script classpath, you can use the classes in your build script as you would
            any other classes on the classpath. The following example adds to the previous example, and uses classes
            from the build script classpath.</para>
        <sample id="externalBuildDependency" dir="userguide/organizeBuildLogic/externalDependency" title="A build script with external dependencies">
            <sourcefile file="build.gradle"/>
            <output args="-q encode"/>
        </sample>
        <para>
            For multi-project builds, the dependencies declared with a project's <literal>buildscript()</literal> method
            are available to the build scripts of all its sub-projects.
        </para>
        <para>
            Build script dependencies may be Gradle plugins.
            Please consult <xref linkend="plugins"/> for more information on Gradle plugins.
        </para>
        <para>
            Every project automatically has a <literal>buildEnvironment</literal> task of type <apilink class="org.gradle.api.tasks.diagnostics.BuildEnvironmentReportTask" />
            that can be invoked to report on the resolution of the build script dependencies.
        </para>
    </section>

    <section id='sec:ant_optional_dependencies'>
        <title>Ant optional dependencies</title>
        <para>For reasons we don't fully understand yet, external dependencies are not picked up by Ant's optional
            tasks. But you can easily do it in another way.
            <footnote>
                <para>In fact, we think this is a better solution. Only if your buildscript and Ant's optional
                    task need the <emphasis>same</emphasis> library would you have to define it twice. In such a
                    case it would be nice if Ant's optional task would automatically pick up the classpath defined
                    in the “<filename>gradle.settings</filename>” file.
                </para>
            </footnote>
        </para>
        <sample id="buildLogic" dir="userguide/organizeBuildLogic" title="Ant optional dependencies">
            <sourcefile file="build.gradle"/>
        </sample>
        <para>This is also a good example for the usage of client modules. The POM file in Maven Central for the
        ant-commons-net task does not provide the right information for this use case.</para>
    </section>
    <section id='sec:philosophy'>
        <title>Summary</title>
        <para>Gradle offers you a variety of ways of organizing your build logic. You can choose what is right for your
            domain and find the right balance between unnecessary indirections, and avoiding redundancy and a hard to
            maintain code base. It is our experience that even very complex custom build logic is rarely shared between
            different builds. Other build tools enforce a separation of this build logic into a separate project. Gradle
            spares you this unnecessary overhead and indirection.
        </para>
    </section>
</chapter>
