// Copyright 2017 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.

[[writing_build_scripts]]
= Writing Build Scripts

Use a build script to configure a _project_. Each Gradle project corresponds to a software component
that needs to be built, like a library or an application. Each build script is associated
with an object of type link:{groovyDslPath}/org.gradle.api.Project.html[Project].
As the build script executes, it configures this `Project`.

[IMPORTANT]
.Build scripts, Settings scripts, and Init scripts
====
_Build scripts_ define `Project` objects.
Gradle uses other scripts as well:

- <<organizing_gradle_projects.adoc#sec:settings_file,Settings scripts>>
  define link:{groovyDslPath}/org.gradle.api.initialization.Settings.html[Settings] objects.
- <<init_scripts.adoc#init_scripts,Init scripts>>
  define link:{groovyDslPath}/org.gradle.api.invocation.Gradle.html[Gradle] objects.
====

== Properties

Many top-level properties and blocks in a build script are part of the link:{javadocPath}org/gradle/api/Project.html[`Project`] API.
The following build script uses the link:{groovyDslPath}/org.gradle.api.Project.html#org.gradle.api.Project:name[Project.name]
property to print the name of the project:

.Access a Project property
====
include::sample[dir="snippets/tutorial/projectApi/kotlin",files="build.gradle.kts[tags=project-name]"]
include::sample[dir="snippets/tutorial/projectApi/groovy",files="build.gradle[tags=project-name]"]

.Output of **`gradle -q check`**
----
> gradle -q check
include::{snippetsPath}/tutorial/projectApi/tests/projectApi.out[]
----
====

Both `println` statements print out the same property. The first uses the top-level reference
to the `name` property of the `Project` object. The other statement uses the `project` property
available to any build script, which returns the associated `Project` object.

[[sec:standard_project_properties]]
=== Standard project properties

The `Project` object exposes a standard set of properties in your build script.
The following table lists a few commonly used properties:

.Project Properties
[%header%autowidth,compact]
|===
| Name | Type | Default Value

| `project`
| link:{groovyDslPath}/org.gradle.api.Project.html[Project]
| The `Project` instance

| `name`
| `String`
| The name of the project directory.

| `path`
| `String`
| The absolute path of the project.

| `description`
| `String`
| A description for the project.

| `projectDir`
| `File`
| The directory containing the build script.

| `buildDir`
| `File`
| `__projectDir__/build`

| `group`
| `Object`
| `unspecified`

| `version`
| `Object`
| `unspecified`

| `ant`
| link:{javadocPath}/org/gradle/api/AntBuilder.html[AntBuilder]
| An `AntBuilder` instance
|===

[IMPORTANT]
.Script with other targets
====
The _build scripts_ described here target `Project` objects.
There are also <<organizing_gradle_projects.adoc#sec:settings_file,settings scripts>> and <<init_scripts.adoc#init_scripts,init scripts>> that respectively target link:{groovyDslPath}/org.gradle.api.initialization.Settings.html[Settings] and link:{groovyDslPath}/org.gradle.api.invocation.Gradle.html[Gradle] objects.
====

[[sec:the_script_api]]
== The Script API

When Gradle executes a Groovy build script (`.gradle`), it compiles the script into a class that
implements link:{groovyDslPath}/org.gradle.api.Script.html[Script]. As a result, builds scripts
have access to all of the properties and methods declared by the `Script` interface.

When Gradle executes a Kotlin build script (`.gradle.kts`), it compiles the script into a subclass
of link:https://gradle.github.io/kotlin-dsl-docs/api/org.gradle.kotlin.dsl/-kotlin-build-script/index.html[KotlinBuildScript].
As a result, builds scripts have access to all visible properties and functions declared by the `KotlinBuildScript` type.

[[sec:declaring_variables]]
== Declare Variables

Build scripts can declare two kinds of variables: local variables and extra properties.

[[sec:local_variables]]
=== Local Variables

[.multi-language-text.lang-kotlin]
Declare local variables with the `val` keyword. Local variables are only visible in the scope where they have been declared. They are a feature of the underlying Kotlin language.

[.multi-language-text.lang-groovy]
Declare local variables with the `def` keyword. Local variables are only visible in the scope where they have been declared. They are a feature of the underlying Groovy language.

.Declare a local variable
====
include::sample[dir="snippets/tutorial/localVariables/kotlin",files="build.gradle.kts[]"]
include::sample[dir="snippets/tutorial/localVariables/groovy",files="build.gradle[]"]
====

[[sec:extra_properties]]
=== Extra Properties

All of Gradle's enhanced objects, including projects, tasks, and source sets, can hold user-defined properties.

[.multi-language-text.lang-kotlin]
Add, read, and set extra properties via the owning object's `extra` property. Alternatively, you can access extra properties via Kotlin delegated properties using `by extra`.

[.multi-language-text.lang-groovy]
Add, read, and set extra properties via the owning object's `ext` property. Alternatively, you can use an `ext` block to add multiple properties at once.

.Use extra properties
====
include::sample[dir="snippets/tutorial/extraProperties/kotlin",files="build.gradle.kts[tags=extraProperties]"]
include::sample[dir="snippets/tutorial/extraProperties/groovy",files="build.gradle[tags=extraProperties]"]

.Output of **`gradle -q printProperties`**
----
> gradle -q printProperties
include::{snippetsPath}/tutorial/extraProperties/tests/extraProperties.out[]
----
====

[.multi-language-text.lang-kotlin]
This example adds two extra properties to the `project` object via `by extra`. Additionally, this example adds a property named `purpose` to each source set by setting `extra["purpose"]` to `null`. Once added, you can read and set all of these properties via `extra`.

[.multi-language-text.lang-groovy]
This example adds two extra properties to the `project` object via an `ext` block. Additionally, this example adds a property named `purpose` to each source set by setting `ext.purpose` to `null`. Once added, you can read and set all of these properties just like predefined properties.

Gradle requires special syntax for adding a property so it can fail fast. For example, this allows Gradle to recognize
when a script attempts to set a property that does not exist. You can access extra properties anywhere where you can
access their owning object. This gives extra properties a wider scope than local variables.
Subprojects can access extra properties on their parent projects.

For more information about extra properties, see
link:{groovyDslPath}/org.gradle.api.plugins.ExtraPropertiesExtension.html[ExtraPropertiesExtension] in the API documentation.

[[sec:configuring_arbitrary_objects]]
== Configure Arbitrary Objects

Configure arbitrary objects with `configure()`:

.Configure arbitrary objects
====
include::sample[dir="snippets/tutorial/configureObject/kotlin",files="build.gradle.kts[]"]
include::sample[dir="snippets/tutorial/configureObject/groovy",files="build.gradle[]"]

.Output of **`gradle -q configure`**
----
> gradle -q configure
include::{snippetsPath}/tutorial/configureObject/tests/configureObject.out[]
----
====

[[sec:configuring_arbitrary_objects_using_an_external_script]]
=== Configure Objects in an External Script

You can also configure arbitrary objects using an external script:

[CAUTION]
.Not supported in Kotlin
====
The Kotlin DSL does not support arbitrary object configuration using an external script.
For more information, see link:https://github.com/gradle/kotlin-dsl/issues/659[gradle/kotlin-dsl#659].
====

.Configure arbitrary objects using a script
====
include::sample[dir="snippets/tutorial/configureObjectUsingScript/groovy",files="build.gradle[];other.gradle[]"]

.Output of `gradle -q configure`
----
> gradle -q configure
include::{snippetsPath}/tutorial/configureObjectUsingScript/tests/configureObjectUsingScript.out[]
----
====

[[groovy-dsl-basics]]
== Helpful Groovy Syntax

https://docs.groovy-lang.org/latest/html/documentation/index.html[Groovy] provides many features to help create DSLs. These features can help you write more idiomatic build scripts, plugins, and tasks.

[TIP]
Looking for helpful Kotlin syntax? Check out the link:https://kotlinlang.org/docs/reference/[Kotlin reference documentation] and link:https://kotlinlang.org/docs/tutorials/koans.html[Kotlin Koans].

[[sec:groovy_jdk]]
=== Convenience Methods

Groovy adds convenience methods to the standard Java classes.
For example, `Iterable` gets an `each` method, which iterates over the elements of the `Iterable`:

.Groovy JDK methods
====
include::sample[dir="snippets/tutorial/groovy/groovy",files="build.gradle[tags=groovyJdk]"]
====

For more information, see https://groovy-lang.org/gdk.html[the GDK documentation].

[[sec:property_accessors]]
=== Automatic Property Accessors

Groovy automatically converts property references into getter or setter method calls:

.Property accessors
====
include::sample[dir="snippets/tutorial/groovy/groovy",files="build.gradle[tags=propertyAccessors]"]
====

[[sec:optional_parentheses_on_method_calls]]
=== Optional Parentheses on Method Calls

Groovy doesn't require parentheses for method calls:

.Method call without parentheses
====
include::sample[dir="snippets/tutorial/groovy/groovy",files="build.gradle[tags=methodCallWithoutParentheses]"]
====

[[sec:list_and_map_literals]]
=== List and Map Instantiation Shortcuts

Groovy provides shortcuts to define `List` and `Map` instances.
For example, consider the “`apply`” method, which accepts a map parameter.
When you apply a plugin (`apply plugin:'java'`), you don't use a map literal.
Plugin application uses "named parameters" instead. Named parameters and map
literals use similar syntax, but named parameters don't use wrapping brackets.
When you call `apply`, Groovy converts the named parameter list to a map.

.List and map literals
====
include::sample[dir="snippets/tutorial/groovy/groovy",files="build.gradle[tags=listAndMapLiterals]"]
====

[[sec:closures_as_the_last_parameter_in_a_method]]
=== Last Closure Parameter Syntax

The Gradle DSL uses closures in many places.
You can find out more about closures https://docs.groovy-lang.org/latest/html/documentation/index.html#_closures[here].
When the last parameter of a method is a closure, you can place the closure after the method call:

.Closure as method parameter
====
include::sample[dir="snippets/tutorial/groovy/groovy",files="build.gradle[tags=closureAsLastParam]"]
====

[[sec:closure_delegate]]
=== Closure Delegates

Each closure has a `delegate` object. Groovy uses this delegate to look up variable and method
references to nonlocal variables and closure parameters. Gradle uses this for _configuration closures_,
where the `delegate` object refers to the object being configured.

.Closure delegates
====
include::sample[dir="snippets/tutorial/groovy/groovy",files="build.gradle[tags=closureDelegates]"]
====

[[script-default-imports]]
== Default Imports

To make build scripts more concise, Gradle automatically adds a set of import statements to scripts.
As a result, instead of writing `throw new org.gradle.api.tasks.StopExecutionException()`,
you can write `throw new StopExecutionException()` instead.

Gradle implicitly adds the following imports to each script:

.Gradle default imports
[source,groovy]
----
include::default-imports.txt[]
----

[[sec:groovy_script_variables]]
== Groovy Script Variables

Groovy has two types of script variables:

- Variables declared with a type modifier or `def` are visible within closures but not visible within methods.
- Variables declared without a modifier are visible anywhere in the script.

Prefer declaring variables with `def` to make their scope explicit.


[source,groovy]
.scope.groovy
----
include::{snippetsPath}/tutorial/groovyScope/groovy/src/main/groovy/scope.groovy[]
----

.Output of `groovy scope.groovy`
----
> groovy scope.groovy
include::{snippetsPath}/tutorial/groovyScope/tests/scope.out[]
----

[TIP]
For more information about Groovy syntax, see https://docs.groovy-lang.org/latest/html/documentation/index.html[the Groovy documentation].
