<!--
  ~ 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='init_scripts'>
    <title>Initialization Scripts</title>
    <para>Gradle provides a powerful mechanism to allow customizing the build based on the current environment.  This
        mechanism also supports tools that wish to integrate with Gradle.
    </para>
    <section id='sec:basic_usage'>
        <title>Basic usage</title>
        <para>Initialization scripts (a.k.a. <firstterm>init scripts</firstterm>) are similar to other scripts in Gradle.
            These scripts, however, are run before the build starts.  Here are several possible uses:
            <itemizedlist>
                <listitem>
                    <para>Set up enterprise-wide configuration, such as where to find custom plugins.</para>
                </listitem>
                <listitem>
                    <para>Set up properties based on the current environment, such as a developer's machine vs. a
                        continuous integration server.
                    </para>
                </listitem>
                <listitem>
                    <para>Supply personal information about the user that is required by the build, such as repository or database
                        authentication credentials.
                    </para>
                </listitem>
                <listitem>
                    <para>Define machine specific details, such as where JDKs are installed.
                    </para>
                </listitem>
                <listitem>
                    <para>Register build listeners.  External tools that wish to listen to Gradle events might find
                        this useful.
                    </para>
                </listitem>
                <listitem>
                    <para>Register build loggers.  You might wish to customise how Gradle logs the events that it generates.
                    </para>
                </listitem>
            </itemizedlist>
            One main limitation of init scripts is that they cannot access classes in the buildSrc project (see
            <xref linkend='sec:build_sources'/> for details of this feature).
        </para>
    </section>
    <section>
        <title>Using an init script</title>
        <para>There are several ways to use an init script:
        </para>
        <itemizedlist>
            <listitem>
                <para>Specify a file on the command line.  The command line option is <option>-I</option> or <option>--init-script</option> followed
                    by the path to the script.  The command line option can appear more than once, each time adding another init script.</para>
            </listitem>
            <listitem>
                <para>Put a file called <filename>init.gradle</filename> in the <filename><replaceable>USER_HOME</replaceable>/.gradle/</filename> directory.</para>
            </listitem>
            <listitem>
                <para>Put a file that ends with <filename>.gradle</filename> in the <filename><replaceable>USER_HOME</replaceable>/.gradle/init.d/</filename> directory.</para>
            </listitem>
            <listitem>
                <para>Put a file that ends with <filename>.gradle</filename> in the <filename><replaceable>GRADLE_HOME</replaceable>/init.d/</filename>
                    directory, in the Gradle distribution. This allows you to package up a custom Gradle distribution containing some custom build logic and plugins. You can
                    combine this with the <link linkend="gradle_wrapper">Gradle wrapper</link> as a way to make custom logic available to all builds
                    in your enterprise.
                </para>
            </listitem>
        </itemizedlist>
        <para>
            If more than one init script is found they will all be executed, in the order specified above. Scripts in a given directory are executed
            in alphabetical order.
            This allows, for example, a tool to specify an init script on the command line and the user to put one in their home directory for defining
            the environment and both scripts will run when Gradle is executed.
        </para>
    </section>
    <section>
        <title>Writing an init script</title>
        <para>Similar to a Gradle build script, an init script is a groovy script. Each init script has a
            <apilink class="org.gradle.api.invocation.Gradle"/> instance associated with it. Any property reference
            and method call in the init script will delegate to this <classname>Gradle</classname> instance.
        </para>
        <para>Each init script also implements the <apilink class="org.gradle.api.Script"/> interface.</para>
        <section>
            <title>Configuring projects from an init script</title>
            <para>You can use an init script to configure the projects in the build. This works in a similar way to configuring projects in a
                multi-project build.
                The following sample shows how to perform extra configuration from an init script <emphasis>before</emphasis> the projects are evaluated.
                This sample uses this feature to configure an extra repository to be used only for certain environments.
            </para>
            <sample id="initScriptConfiguration" dir="userguide/initScripts/configurationInjection" title="Using init script to perform extra configuration before projects are evaluated">
                <sourcefile file="build.gradle"/>
                <sourcefile file="init.gradle"/>
                <output args="--init-script init.gradle -q showRepos"/>
            </sample>
        </section>
    </section>
    <section id='sec:custom_classpath'>
        <title>External dependencies for the init script</title>
        <para>In <xref linkend='sec:external_dependencies'/> is was explained how to add external dependencies to a
            build script. Init scripts can similarly have external dependencies defined.  You do this using the
            <literal>initscript()</literal> method, passing in a closure which declares the init script classpath.
        </para>
        <sample id="declareExternalInitDependency" dir="userguide/initScripts/externalDependency" title="Declaring external dependencies for an init script">
            <sourcefile file="init.gradle" snippet="declare-classpath"/>
        </sample>
        <para>The closure passed to the <literal>initscript()</literal> method configures a
            <apilink class="org.gradle.api.initialization.dsl.ScriptHandler"/> instance. You declare the init 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 init script classpath, you can use the classes in your init script as you would
            any other classes on the classpath. The following example adds to the previous example, and uses classes
            from the init script classpath.</para>
        <sample id="externalInitDependency" dir="userguide/initScripts/externalDependency" title="An init script with external dependencies">
            <sourcefile file="init.gradle"/>
            <output args="--init-script init.gradle -q doNothing"/>
        </sample>
    </section>
    <section>
            <title>Init script plugins</title>
            <para>Similar to a Gradle build script or a Gradle settings file, plugins can be applied on init scripts.
            </para>
            <sample id="usePluginsInInitScripts" dir="userguide/initScripts/plugins" title="Using plugins in init scripts">
                    <sourcefile file="init.gradle" snippet="init-script-plugin"/>
            </sample>
            <para>The plugin in the sample init scripts ensures, that only a specified repository is used when running the build.
            </para>
            <para>When applying plugins within the init script, Gradle instantiates the plugin and calls the plugin
                instance's <apilink class="org.gradle.api.Plugin" method="apply"/> method. The <literal>gradle</literal> object is passed as a parameter,
                which can be used to configure all aspects of a build.
                Of course, the applied plugin can be resolved as external dependency as described in <xref linkend='sec:custom_classpath'/>
            </para>
        </section>
</chapter>
