# Chapter 29. The Idea Plugin

The Idea plugin generates files that are used by IntelliJ Idea IDE, thus making it possible to open the project from Idea (File - Open Project). Both external (including associated source and javadoc files) and project dependencies are considered.

The Idea plugin will create different content depending on what other plugins being used.

## 29.1. Usage

To use the Idea plugin, include in your build script:

Example 29.1. Using the Idea plugin

`build.gradle`

    apply plugin: 'idea'

One focus of the Idea tasks is to be open to customizations. They provide a couple of hooks to add or remove content from the generated files.

## 29.2. Tasks

The Idea plugin adds the tasks shown below to a project.

Table 29.1. Idea plugin - Tasks

Task name | Depends on | Type | Description
`idea` | `ideaProject`, `ideaModule`, `ideaWorkspace` | `-` | Generates all the idea configuration files
`cleanIdea` | `cleanIdeaProject`, `cleanIdeaModule`, `cleanIdeaWorkspace` | `Delete` | Removes all idea configuration files
`cleanIdeaProject` | `-` | `Delete` | Removes the idea project file
`cleanIdeaModule` | `-` | `Delete` | Removes the idea module file
`cleanIdeaWorkspace` | `-` | `Delete` | Removes the idea workspace file
`ideaProject` | `-` | `IdeaProject` | Generates the `.ipr` file. The Idea plugin adds this task only to the root project.
`ideaModule` | `-` | `IdeaModule` | Generates the `.iml` file
`ideaWorkspace` | `-` | `IdeaWorkspace` | Generates the `.iws` file

Table 29.2. IdeaModule task

Property | Type | Default Value | Default Value with Java Plugin | Description
`moduleDir` | File | `projectDir` | `projectDir` | The content root directory of the module. Must not be null.
`outputFile` | File | `projectDir`/`<project.name>` `.iml` | - | The iml file. Used to look for existing files and as the target for generation. Must not be null.
`sourceDirs` | Set<File> | empty set | The source dirs of `sourceSets.main` | The dirs containing the production sources. Must not be null.
`testSourceDirs` | Set<File> | empty set | The source dirs of `sourceSets.test` | The dirs containing the test sources. Must not be null.
`excludeDirs` | Set<File> | empty set | - | The dirs to be excluded by idea. Must not be null.
`outputDir` | File | null | `sourceSets.main.classesDir` | The idea output dir for the production sources. If null no entry for output dirs is created.
`testOutputDir` | File | null | `sourceSets.test.classesDir` | The idea output dir for the test sources. If null no entry for test output dirs is created.
`javaVersion` | String | null | - | If this is null the value of the existing or default ipr XML (inherited) is used. If it is set to `inherited`, the project SDK is used. Otherwise the SDK for the corresponding value of java version is used for this module
`downloadSources` | boolean | true | - | Whether to download and add source jars associated with the dependency jars.
`downloadJavadoc` | boolean | false | - | Whether to download and add javadoc jars associated with the dependency jars.
`scopes` | Map | [:] | COMPILE(compile), RUNTIME(runtime - compile), TEST(testRuntime - runtime) | The keys of this map are the Idea scopes. Each key points to another map that has two keys, plus and minus. The values of those keys are sets of Configuration objects. The files of the plus configurations are added minus the files from the minus configurations.
`gradleCacheVariable` | String | null | - | If this variable is set, dependencies in the existing iml file will be parsed for this variable. If they use it, it will be replaced with a path that has the $MODULE_DIR$ variable as a root and then a relative path to {@link #gradleCacheHome} . That way Gradle can recognize equal dependencies.
`gradleCacheVariable` | File | null | The gradle cache dir | This property is used in conjunction with `gradleCacheVariable`

Table 29.3. IdeaProject task

Property | Type | Default Value | Default Value with Java Plugin | Description
`subprojects` | Set<Project> | `rootProject.allprojects` | - | The subprojects that should be mapped to modules in the `ipr` file. The subprojects will only be mapped, if the Idea plugin has been applied to them.
`outputFile` | File | `projectDir`/`<project.name>` `.ipr` | - | The ipr file. Used to look for existing files and as the target for generation. Must not be null.
`javaVersion` | String | 1.6 | - | The java version used for defining the project sdk.
`wildcards` | Set<String> | ['!?*.java', '!?*.groovy'] | - | The wildcard resource patterns. Must not be null.

Table 29.4. IdeaWorkspace task

Property | Type | Default Value | Default Value with Java Plugin | Description
`outputFile` | File | `projectDir`/`<project.name>` `.ipr` | - | The iws file. Used to look for existing files and as the target for generation. Must not be null.

Table 29.5. Task Hooks

Method | Project Task Argument | Module Task Argument | Workspace Task Argument | Description
``beforeConfigured { arg -> }`` | `Project` | `Module` | n/a | Gets called directly after the domain objects have been populated with the content of the existing XML file (if there is one).
``whenConfigured { arg -> }`` | `Project` | `Module` | n/a | Gets called after the domain objects have been populated with the content of the existing XML file and the content from the build script.
``withXml { arg -> }`` | `XmlProvider` | `XmlProvider` | `XmlProvider` | The root node of the XML just before the XML is written to disk.

## 29.3. Customizing the generated files

Both, the `IdeaProject` and the `IdeaModule` task provide the same hooks and behavior for customizing the generated content. The `IdeaWorkspace` only provides a hook for direct XML manipulation.

The plugin recognizes existing idea files. If an idea module, project or workspace file does not exists, a default one is used. Otherwise the existing ones are merged.

### 29.3.1. Merging

The first option to customize the Idea files is to have an existing Idea `ipr` or `iml` file before the tasks are run. Existing files will be merged together with the generated content. Any section of the existing Idea files that are not the target of generated content will neither be changed nor removed.

#### 29.3.1.1. Disabling merging with a complete overwrite

If you want Gradle to completely overwrite existing Idea files you can specify this on the command line by executing something like `gradle cleanIdea idea` or `gradle cleanIdeaModule ideaModule`. You can specify this also in the build script. Just make the generating tasks depending on the deleting tasks. You can tailor this to your needs. You could make the `idea` task dependent on the `cleanIdea` task. If you only want to overwrite for example the module files you simply make the `ideaModule` task dependent on the `cleanIdeaModule` task.

### 29.3.2. Hooking into the generation lifecycle

The Idea plugin provides a couple of domain classes that model Idea project and module files. But only the sections that are autogenerated by Gradle. The generation lifecycle is the following. If there is an existing Idea file, its whole XML is parsed and stored in memory. Then the domain objects are populated with the relevant content of the the existing XML. After that the build script information is used to further populate those objects (e.g. add additional dependencies). Then all sections modelled by the domain objects are removed from the XML in memory. After that the domain objects are used to inject their content into the XML. Finally the XML is written to disk. The lifecycle provides hooks to modify the result according to your needs.

#### 29.3.2.1. Partial Overwrite

Doing a complete overwrite removes all your manual customizations. This might be not what you want. Therefore Gradle provides the option for a partial overwrite. You can hook into the phase just after the existing Idea files have populated the domain objects. You could then for example remove all the dependencies from the `module` object.

Example 29.2. Partial Overwrite for Module

`build.gradle`

    ideaModule {
        beforeConfigured { module ->
            module.dependencies.clear()
        }
    }

The generated XML will have all sections of the existing Idea module file, except for the dependencies, where only the information of the build script is used. You could do something similar for the project file.

Example 29.3. Partial Overwrite for Project

`build.gradle`

    ideaProject {
        beforeConfigured { project ->
            project.modules.clear()
        }
    }

#### 29.3.2.2. Modifying the fully populated domain objects

You can also hook into the phase after the existing Idea files and the build script metadata have populated the domain objects. You could then for example export all the dependencies of the `module` object.

Example 29.4. Export Dependencies

`build.gradle`

    ideaModule {
        whenConfigured { module ->
            module.dependencies*.exported = true
        }
    }

#### 29.3.2.3. Modifying the XML

You can also hook into the phase after the XML DOM is fully populated but not written to disk. That hook provides total control over what is generated.

Example 29.5. Customizing the XML

`build.gradle`

    ideaProject {
        withXml { root ->
            root.component.find { it.@name == 'VcsDirectoryMappings' }.mapping.@vcs = 'Git'
        }
    }

## 29.4. Further things to consider

The paths of the 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. If you use such a path variable, you need to tell the ideaModule task the name of this variable, so that it can do a proper merge without creating duplicates.