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

[[idea_plugin]]
== The IDEA Plugin

The IDEA plugin generates files that are used by http://www.jetbrains.com/idea/[IntelliJ IDEA], thus making it possible to open the project from IDEA (`File` - `Open Project`). Both external dependencies (including associated source and Javadoc files) and project dependencies are considered.

What exactly the IDEA plugin generates depends on which other plugins are used:

.IDEA plugin behavior
[cols="a,a", options="header"]
|===
| Plugin
| Description

| None
| Generates an IDEA module file. Also generates an IDEA project and workspace file if the project is the root project.

| <<java_plugin,Java>>
| Adds Java configuration to the module and project files.
|===

One focus of the IDEA plugin is to be open to customization. The plugin provides a standardized set of hooks for adding and removing content from the generated files.


[[sec:idea_usage]]
=== Usage

To use the IDEA plugin, include this in your build script:

++++
<sample id="useIdeaPlugin" dir="idea" title="Using the IDEA plugin">
            <sourcefile file="build.gradle" snippet="use-plugin"/>
        </sample>
++++

The IDEA plugin adds a number of tasks to your project. The main tasks that you will use are the `idea` and `cleanIdea` tasks.

[[sec:idea_tasks]]
=== Tasks

The IDEA plugin adds the tasks shown below to a project. Notice that the `clean` task does not depend on the `cleanIdeaWorkspace` task. This is because the workspace typically contains a lot of user specific temporary data and it is not desirable to manipulate it outside IDEA.

[[ideatasks]]
.IDEA plugin - Tasks
[cols="a,a,a,a", options="header"]
|===
| Task name
| Depends on
| Type
| Description

| `idea`
| `ideaProject`, `ideaModule`, `ideaWorkspace`
| -
| Generates all IDEA configuration files

| `cleanIdea`
| `cleanIdeaProject`, `cleanIdeaModule`
| api:org.gradle.api.tasks.Delete[]
| Removes all IDEA configuration files

| `cleanIdeaProject`
| -
| api:org.gradle.api.tasks.Delete[]
| Removes the IDEA project file

| `cleanIdeaModule`
| -
| api:org.gradle.api.tasks.Delete[]
| Removes the IDEA module file

| `cleanIdeaWorkspace`
| -
| api:org.gradle.api.tasks.Delete[]
| Removes the IDEA workspace file

| `ideaProject`
| -
| api:org.gradle.plugins.ide.idea.GenerateIdeaProject[]
| Generates the `.ipr` file. This task is only added to the root project.

| `ideaModule`
| -
| api:org.gradle.plugins.ide.idea.GenerateIdeaModule[]
| Generates the `.iml` file

| `ideaWorkspace`
| -
| api:org.gradle.plugins.ide.idea.GenerateIdeaWorkspace[]
| Generates the `.iws` file. This task is only added to the root project.
|===


[[sec:idea_configuration]]
=== Configuration


[[idea-configuration]]
.Configuration of the idea plugin
[cols="a,a,a", options="header"]
|===
| Model
| Reference name
| Description

| api:org.gradle.plugins.ide.idea.model.IdeaModel[]
| `idea`
| Top level element that enables configuration of the idea plugin in a DSL-friendly fashion

| api:org.gradle.plugins.ide.idea.model.IdeaProject[]
| `idea.project`
| Allows configuring project information

| api:org.gradle.plugins.ide.idea.model.IdeaModule[]
| `idea.module`
| Allows configuring module information

| api:org.gradle.plugins.ide.idea.model.IdeaWorkspace[]
| `idea.workspace`
| Allows configuring the workspace XML
|===


[[sec:idea_customizing_the_generated_files]]
=== Customizing the generated files

The IDEA plugin provides hooks and behavior for customizing the generated content. The workspace file can effectively only be manipulated via the `withXml` hook because its corresponding domain object is essentially empty.

The tasks recognize existing IDEA files, and merge them with the generated content.


[[sec:merging_with_idea_files]]
==== Merging

Sections of existing IDEA files that are also the target of generated content will be amended or overwritten, depending on the particular section. The remaining sections will be left as-is.


[[sec:complete_overwrite_of_idea_files]]
===== Disabling merging with a complete overwrite

To completely rewrite existing IDEA files, execute a clean task together with its corresponding generation task, like “`gradle cleanIdea idea`” (in that order). If you want to make this the default behavior, add “`tasks.idea.dependsOn(cleanIdea)`” to your build script. This makes it unnecessary to execute the clean task explicitly.

This strategy can also be used for individual files that the plugin would generate. For instance, this can be done for the “`.iml`” file with “`gradle cleanIdeaModule ideaModule`”.

[[sec:hooking_into_the_idea_generation_lifecycle]]
==== Hooking into the generation lifecycle

The plugin provides objects modeling the sections of the metadata files that are generated by Gradle. The generation lifecycle is as follows:

. The file is read; or a default version provided by Gradle is used if it does not exist
. The `beforeMerged` hook is executed with a domain object representing the existing file
. The existing content is merged with the configuration inferred from the Gradle build or defined explicitly in the eclipse DSL
. The `whenMerged` hook is executed with a domain object representing contents of the file to be persisted
. The `withXml` hook is executed with a raw representation of the XML that will be persisted
. The final XML is persisted
 The following table lists the domain object used for each of the model types:

[[idea-hooks]]
.Idea plugin hooks
[cols="a,a,a,a", options="header"]
|===
| Model
| `beforeMerged { arg -> }` argument type
| `whenMerged { arg -> }` argument type
| `withXml { arg -> }` argument type

| api:org.gradle.plugins.ide.idea.model.IdeaProject[]
| api:org.gradle.plugins.ide.idea.model.Project[]
| api:org.gradle.plugins.ide.idea.model.Project[]
| api:org.gradle.api.XmlProvider[]

| api:org.gradle.plugins.ide.idea.model.IdeaModule[]
| api:org.gradle.plugins.ide.idea.model.Module[]
| api:org.gradle.plugins.ide.idea.model.Module[]
| api:org.gradle.api.XmlProvider[]

| api:org.gradle.plugins.ide.idea.model.IdeaWorkspace[]
| api:org.gradle.plugins.ide.idea.model.Workspace[]
| api:org.gradle.plugins.ide.idea.model.Workspace[]
| api:org.gradle.api.XmlProvider[]
|===


[[sec:partial-rewrite]]
===== Partial rewrite of existing content

A <<sec:complete-rewrite,complete rewrite>> causes all existing content to be discarded, thereby losing any changes made directly in the IDE. The `beforeMerged` hook makes it possible to overwrite just certain parts of the existing content. The following example removes all existing dependencies from the `Module` domain object:
++++
<sample id="partialRewrites" dir="idea" title="Partial Rewrite for Module">
                        <sourcefile file="build.gradle" snippet="module-before-merged"/>
                    </sample>
++++

The resulting module file will only contain Gradle-generated dependency entries, but not any other dependency entries that may have been present in the original file. (In the case of dependency entries, this is also the default behavior.) Other sections of the module file will be either left as-is or merged. The same could be done for the module paths in the project file:

++++
<sample id="partialRewritesProject" dir="idea" title="Partial Rewrite for Project">
                        <sourcefile file="build.gradle" snippet="project-before-merged"/>
                    </sample>
++++


[[sec:idea_modify_domain_objects]]
===== Modifying the fully populated domain objects

The `whenMerged` hook allows you to manipulate the fully populated domain objects. Often this is the preferred way to customize IDEA files. Here is how you would export all the dependencies of an IDEA module:
++++
<sample id="exportDependencies" dir="idea" title="Export Dependencies">
                        <sourcefile file="build.gradle" snippet="module-when-merged"/>
                    </sample>
++++


[[sec:idea_modify_xml]]
===== Modifying the XML representation

The `withXml` hook allows you to manipulate the in-memory XML representation just before the file gets written to disk. Although Groovy's XML support makes up for a lot, this approach is less convenient than manipulating the domain objects. In return, you get total control over the generated file, including sections not modeled by the domain objects.
++++
<sample id="projectWithXml" dir="idea" title="Customizing the XML">
                        <sourcefile file="build.gradle" snippet="project-with-xml"/>
                        <test args="idea"/>
                    </sample>
++++


[[sec:further_things_to_consider]]
=== Further things to consider

The paths of dependencies in the generated IDEA files are absolute. If you manually define a path variable pointing to the Gradle dependency cache, IDEA will automatically replace the absolute dependency paths with this path variable. you can configure this path variable via the “`idea.pathVariables`” property, so that it can do a proper merge without creating duplicates.
