IDEA 插件与配置缓存不兼容。

IDEA 插件生成由IntelliJ IDEA使用的文件,从而可以在 IDEA 中打开项目(File - Open Project)。外部依赖项(包括相关的源文件和 Javadoc 文件)和项目依赖项都会被考虑。

如果您只是想将 Gradle 项目加载到 IntelliJ IDEA 中,请使用 IDE 的导入功能。导入项目到 IDEA 中不需要应用此插件,但如果您应用了,导入过程将考虑您可能有的任何不直接修改生成文件的额外 IDEA 配置 — 详情请参阅配置部分。

IDEA 插件具体生成哪些文件取决于使用了哪些其他插件

始终

生成 IDEA 模块文件。如果项目是根项目,还会生成 IDEA 项目文件和工作区文件。

Java 插件

此外,将 Java 配置添加到 IDEA 模块文件和项目文件中。

IDEA 插件的一个重点是允许自定义。该插件提供了一套标准化的钩子,用于添加和移除生成文件中的内容。

用法

要使用 IDEA 插件,请在您的构建脚本中包含以下内容

build.gradle.kts
plugins {
    idea
}
build.gradle
plugins {
    id 'idea'
}

IDEA 插件会向您的项目添加一些任务。idea 任务会为项目生成一个 IDEA 模块文件。当项目是根项目时,idea 任务还会生成 IDEA 项目文件和工作区文件。IDEA 项目包括 Gradle 构建中每个项目的模块。

当项目是根项目时,IDEA 插件还会添加一个 openIdea 任务。此任务生成 IDEA 配置文件并在 IDEA 中打开结果。这意味着您可以简单地从根项目运行 ./gradlew openIdea,一步到位生成并在 IDEA 中打开 IDEA 项目。

IDEA 插件还会向项目添加一个 cleanIdea 任务。如果生成的文件存在,该任务会将其删除。

任务

IDEA 插件会向项目添加以下任务。请注意,clean 任务不依赖于 cleanIdeaWorkspace 任务。这是因为工作区通常包含大量用户特定的临时数据,并且不希望在 IDEA 之外操作它。

idea

依赖于: ideaProject, ideaModule, ideaWorkspace

生成所有 IDEA 配置文件

openIdea

依赖于: idea

生成所有 IDEA 配置文件并在 IDEA 中打开项目

cleanIdeaDelete

依赖于: cleanIdeaProject, cleanIdeaModule

移除所有 IDEA 配置文件

cleanIdeaProjectDelete

移除 IDEA 项目文件

cleanIdeaModuleDelete

移除 IDEA 模块文件

cleanIdeaWorkspaceDelete

移除 IDEA 工作区文件

ideaProjectGenerateIdeaProject

生成 .ipr 文件。此任务仅添加到根项目。

ideaModuleGenerateIdeaModule

生成 .iml 文件

ideaWorkspaceGenerateIdeaWorkspace

生成 .iws 文件。此任务仅添加到根项目。

配置

该插件添加了一些配置选项,允许自定义其生成的 IDEA 项目文件和模块文件。这些选项既包括模型属性,也包括直接修改生成文件的底层机制。例如,您可以添加源目录和资源目录,以及注入您自己的 XML 片段。前一种配置会被 IDEA 的导入功能识别,而后者则不会。

以下是您可以使用的配置属性

ideaIdeaModel

顶级元素,以 DSL 友好方式启用 IDEA 插件的配置

idea.project IdeaProject

允许配置项目信息

idea.module IdeaModule

允许配置模块信息

idea.workspace IdeaWorkspace

允许配置工作区 XML

请点击链接查看这些配置属性的类型及其使用示例。

自定义生成的文件

IDEA 插件提供了钩子和行为,用于以更受控和详细的方式自定义生成的内容。此外,withXml 钩子是修改工作区文件的唯一实际方法,因为其对应的领域对象基本上是空的。

本节讨论的技术不适用于 IDEA 的导入功能

这些任务会识别现有的 IDEA 文件并将其与生成的内容合并。

合并

现有 IDEA 文件中作为生成内容目标的部分将根据具体部分进行修改或覆盖。其余部分将保持原样。

完全覆盖以禁用合并

要完全重写现有的 IDEA 文件,请执行清理任务及其相应的生成任务,例如“gradle cleanIdea idea”(按此顺序)。如果您想将其设为默认行为,请在您的构建脚本中添加“tasks.idea.dependsOn(cleanIdea)”。这样就不需要显式执行清理任务了。

此策略也可用于插件将生成的单个文件。例如,对于“.iml”文件,可以使用“gradle cleanIdeaModule ideaModule”来完成。

钩入生成生命周期

该插件提供对象,用于建模由 Gradle 生成的元数据文件的部分。生成生命周期如下

  1. 读取文件;如果文件不存在,则使用 Gradle 提供的默认版本

  2. 执行 beforeMerged 钩子,使用表示现有文件的领域对象

  3. 将现有内容与从 Gradle 构建推断的或在 eclipse DSL 中明确定义的配置合并

  4. 执行 whenMerged 钩子,使用表示要持久化的文件内容的领域对象

  5. 执行 withXml 钩子,使用将要持久化的 XML 的原始表示

  6. 最终 XML 被持久化

以下是每种模型类型使用的领域对象

IdeaProject
IdeaModule
IdeaWorkspace

部分重写现有内容

“完全重写”会导致所有现有内容被丢弃,从而丢失直接在 IDE 中进行的任何更改。beforeMerged 钩子使得仅覆盖现有内容的某些部分成为可能。以下示例从 Module 领域对象中移除所有现有依赖项

build.gradle.kts
import org.gradle.plugins.ide.idea.model.Module

idea.module.iml {
    beforeMerged(Action<Module> {
        dependencies.clear()
    })
}
build.gradle
idea.module.iml {
    beforeMerged { module ->
        module.dependencies.clear()
    }
}

生成的模块文件将只包含 Gradle 生成的依赖项条目,而不会包含原始文件中可能存在的任何其他依赖项条目。(对于依赖项条目,这也是默认行为。)模块文件的其他部分将保持原样或被合并。项目文件中的模块路径也可以执行相同的操作

build.gradle.kts
import org.gradle.plugins.ide.idea.model.Project

idea.project.ipr {
    beforeMerged(Action<Project> {
        modulePaths.clear()
    })
}
build.gradle
idea.project.ipr {
    beforeMerged { project ->
        project.modulePaths.clear()
    }
}

修改完全填充的领域对象

whenMerged 钩子允许您操作完全填充的领域对象。这通常是自定义 IDEA 文件的首选方法。以下是如何导出 IDEA 模块的所有依赖项

示例 4. 导出依赖项
build.gradle.kts
import org.gradle.plugins.ide.idea.model.Module
import org.gradle.plugins.ide.idea.model.ModuleDependency

idea.module.iml {
    whenMerged(Action<Module> {
        dependencies.forEach {
            (it as ModuleDependency).isExported = true
        }
    })
}
build.gradle
idea.module.iml {
    whenMerged { module ->
        module.dependencies*.exported = true
    }
}

修改 XML 表示

withXml 钩子允许您在文件写入磁盘之前操作内存中的 XML 表示。虽然 Groovy 的 XML 支持和 Kotlin 的扩展函数弥补了很多不足,但这种方法不如操作领域对象方便。作为回报,您可以完全控制生成的文件,包括未由领域对象建模的部分。

示例 5. 自定义 XML
build.gradle.kts
import org.w3c.dom.Element

idea.project.ipr {
    withXml(Action<XmlProvider> {
        fun Element.firstElement(predicate: (Element.() -> Boolean)) =
            childNodes
                .run { (0 until length).map(::item) }
                .filterIsInstance<Element>()
                .first { it.predicate() }

        asElement()
            .firstElement { tagName == "component" && getAttribute("name") == "VcsDirectoryMappings" }
            .firstElement { tagName == "mapping" }
            .setAttribute("vcs", "Git")
    })
}
build.gradle
idea.project.ipr {
    withXml { provider ->
        provider.node.component
                .find { it.@name == 'VcsDirectoryMappings' }
                .mapping.@vcs = 'Git'
    }
}

识别额外的测试目录

将此插件与Java 插件一起使用时,在添加额外的源集后,您可能希望在它们包含测试源而非生产源时通知 IDEA,以便 IDE 可以适当地处理这些目录。这可以通过使用此插件的 Module 块来实现。

build.gradle.kts
sourceSets {
    create("intTest") {
        java {
            setSrcDirs(listOf("src/integration"))
        }
    }
}

idea {
    module {
        testSources.from(sourceSets["intTest"].java.srcDirs)
    }
}
build.gradle
sourceSets {
    intTest {
        java {
            srcDirs = ['src/integration']
        }
    }
}

idea {
    module {
        testSources.from(sourceSets.intTest.java.srcDirs)
    }
}
使用JVM Test Suite 插件时,测试源将自动正确识别。

进一步考虑的事项

生成的 IDEA 文件中的依赖项路径是绝对路径。如果您手动定义一个指向 Gradle 依赖项缓存的路径变量,IDEA 将自动用此路径变量替换绝对依赖项路径。您可以通过“idea.pathVariables”属性配置此路径变量,以便能够进行适当的合并而不会创建重复项。