From b58bea6fa10033346171ab79fb77a6062ad6f804 Mon Sep 17 00:00:00 2001 From: Andrey Zinovyev Date: Fri, 23 Apr 2021 10:21:33 +0300 Subject: [PATCH] [lombok] IDE plugin with maven import handler --- build.gradle.kts | 1 + .../org/jetbrains/kotlin/utils/KotlinPaths.kt | 6 +- .../org/jetbrains/kotlin/utils/PathUtil.kt | 1 + idea/resources/META-INF/maven.xml | 1 + .../lombok/lombok-ide-plugin/build.gradle.kts | 34 ++++++++++ .../lombok/ide/AbstractMavenImportHandler.kt | 63 +++++++++++++++++++ .../ide/LombokMavenProjectImportHandler.kt | 39 ++++++++++++ .../kotlin/lombok/ide/idePluginUtils.kt | 48 ++++++++++++++ prepare/compiler/build.gradle.kts | 3 +- .../build.gradle.kts | 3 + prepare/idea-plugin/build.gradle.kts | 2 + settings.gradle | 2 + 12 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 plugins/lombok/lombok-ide-plugin/build.gradle.kts create mode 100644 plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/AbstractMavenImportHandler.kt create mode 100644 plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/LombokMavenProjectImportHandler.kt create mode 100644 plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/idePluginUtils.kt create mode 100644 prepare/ide-plugin-dependencies/lombok-compiler-plugin-for-ide/build.gradle.kts diff --git a/build.gradle.kts b/build.gradle.kts index 28857479f07..102632be56a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -962,6 +962,7 @@ tasks { ":prepare:ide-plugin-dependencies:sam-with-receiver-compiler-plugin-for-ide:publish", ":prepare:ide-plugin-dependencies:compiler-components-for-jps:publish", ":prepare:ide-plugin-dependencies:parcelize-compiler-plugin-for-ide:publish", + ":prepare:ide-plugin-dependencies:lombok-compiler-plugin-for-ide:publish", ":kotlin-script-runtime:publish", ":kotlin-script-util:publish", ":kotlin-scripting-common:publish", diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinPaths.kt b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinPaths.kt index 7ad4a76d331..bd436f30111 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinPaths.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinPaths.kt @@ -66,6 +66,9 @@ interface KotlinPaths { val noArgPluginJarPath: File get() = jar(Jar.NoArgPlugin) + val lombokPluginJarPath: File + get() = jar(Jar.LombokPlugin) + // @Deprecated("Obsolete API", ReplaceWith("jar(KotlinPaths.Jars.samWithReceiver)")) val samWithReceiverJarPath: File get() = jar(Jar.SamWithReceiver) @@ -93,6 +96,7 @@ interface KotlinPaths { JsKotlinTest(PathUtil.KOTLIN_TEST_JS_NAME), AllOpenPlugin(PathUtil.ALLOPEN_PLUGIN_NAME), NoArgPlugin(PathUtil.NOARG_PLUGIN_NAME), + LombokPlugin(PathUtil.LOMBOK_PLUGIN_NAME), SamWithReceiver(PathUtil.SAM_WITH_RECEIVER_PLUGIN_NAME), SerializationPlugin(PathUtil.SERIALIZATION_PLUGIN_NAME), Trove4j(PathUtil.TROVE4J_NAME), @@ -150,4 +154,4 @@ open class KotlinPathsFromBaseDirectory(val basePath: File) : KotlinPaths { override fun jar(jar: KotlinPaths.Jar): File = basePath.resolve(jar.baseName + ".jar") override fun sourcesJar(jar: KotlinPaths.Jar): File? = basePath.resolve(jar.baseName + "-sources.jar") -} \ No newline at end of file +} diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt b/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt index 32fe3d2ba10..ffc48d6c480 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/PathUtil.kt @@ -36,6 +36,7 @@ object PathUtil { const val SAM_WITH_RECEIVER_PLUGIN_JAR_NAME = "$SAM_WITH_RECEIVER_PLUGIN_NAME.jar" const val SERIALIZATION_PLUGIN_NAME = "kotlinx-serialization-compiler-plugin" const val SERIALIZATION_PLUGIN_JAR_NAME = "$SERIALIZATION_PLUGIN_NAME.jar" + const val LOMBOK_PLUGIN_NAME = "lombok-compiler-plugin" const val ANDROID_EXTENSIONS_RUNTIME_PLUGIN_JAR_NAME = "android-extensions-runtime.jar" const val PARCELIZE_RUNTIME_PLUGIN_JAR_NAME = "parcelize-runtime.jar" const val JS_LIB_SRC_JAR_NAME = "kotlin-stdlib-js-sources.jar" diff --git a/idea/resources/META-INF/maven.xml b/idea/resources/META-INF/maven.xml index 61d8d60619c..10b741b106a 100644 --- a/idea/resources/META-INF/maven.xml +++ b/idea/resources/META-INF/maven.xml @@ -6,6 +6,7 @@ + diff --git a/plugins/lombok/lombok-ide-plugin/build.gradle.kts b/plugins/lombok/lombok-ide-plugin/build.gradle.kts new file mode 100644 index 00000000000..d2f934ab8c4 --- /dev/null +++ b/plugins/lombok/lombok-ide-plugin/build.gradle.kts @@ -0,0 +1,34 @@ +description = "Lombok IDE plugin" + +plugins { + kotlin("jvm") + id("jps-compatible") +} + +dependencies { + implementation(project(":plugins:lombok:lombok-compiler-plugin")) + + compileOnly(project(":idea")) + compileOnly(project(":idea:idea-jvm")) + compileOnly(project(":idea:idea-jps-common")) + compileOnly(project(":idea:idea-maven")) + compileOnly(intellijDep()) + excludeInAndroidStudio(rootProject) { compileOnly(intellijPluginDep("maven")) } + compileOnly(intellijPluginDep("gradle")) + compileOnly(project(":idea:kotlin-gradle-tooling")) +} + +sourceSets { + "main" { projectDefault() } + "test" { projectDefault() } +} + +runtimeJar() + +sourcesJar() + +javadocJar() + +projectTest(parallel = true) + +apply(from = "$rootDir/gradle/kotlinPluginPublication.gradle.kts") diff --git a/plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/AbstractMavenImportHandler.kt b/plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/AbstractMavenImportHandler.kt new file mode 100644 index 00000000000..e54eff58221 --- /dev/null +++ b/plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/AbstractMavenImportHandler.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.lombok.ide + +import org.jdom.Element +import org.jdom.Text +import org.jetbrains.idea.maven.project.MavenProject +import org.jetbrains.kotlin.idea.facet.KotlinFacet +import org.jetbrains.kotlin.idea.maven.MavenProjectImportHandler +import org.jetbrains.kotlin.idea.maven.KotlinMavenImporter.Companion.KOTLIN_PLUGIN_GROUP_ID +import org.jetbrains.kotlin.idea.maven.KotlinMavenImporter.Companion.KOTLIN_PLUGIN_ARTIFACT_ID +import java.io.File +import org.jetbrains.kotlin.lombok.ide.CompilerPluginSetup.PluginOption + +abstract class AbstractMavenImportHandler : MavenProjectImportHandler { + abstract val compilerPluginId: String + abstract val pluginName: String +// abstract val mavenPluginArtifactName: String + abstract val pluginJarFileFromIdea: File + + override fun invoke(facet: KotlinFacet, mavenProject: MavenProject) { + modifyCompilerArgumentsForPlugin( + facet, getPluginSetup(mavenProject), + compilerPluginId = compilerPluginId, + pluginName = pluginName + ) + } + + abstract fun getOptions(enabledCompilerPlugins: List, compilerPluginOptions: List): List? + + private fun getPluginSetup(mavenProject: MavenProject): CompilerPluginSetup? { + val kotlinPlugin = mavenProject.plugins.firstOrNull { + it.groupId == KOTLIN_PLUGIN_GROUP_ID && it.artifactId == KOTLIN_PLUGIN_ARTIFACT_ID + } ?: return null + + val configuration = kotlinPlugin.configurationElement ?: return null + + val enabledCompilerPlugins = configuration.getElement("compilerPlugins") + ?.getElements() + ?.flatMap { plugin -> plugin.content.mapNotNull { (it as? Text)?.text } } + ?: emptyList() + + val compilerPluginOptions = configuration.getElement("pluginOptions") + ?.getElements() + ?.flatMap { it.content } + ?.mapTo(mutableListOf()) { (it as Text).text } + ?: mutableListOf() + + // We can't use the plugin from Gradle as it may have the incompatible version + val classpath = listOf(pluginJarFileFromIdea.absolutePath) + + val options = getOptions(enabledCompilerPlugins, compilerPluginOptions) ?: return null + return CompilerPluginSetup(options, classpath) + } + + private fun Element.getElement(name: String) = content.firstOrNull { it is Element && it.name == name } as? Element + + @Suppress("UNCHECKED_CAST") + private fun Element.getElements() = content.filterIsInstance() +} diff --git a/plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/LombokMavenProjectImportHandler.kt b/plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/LombokMavenProjectImportHandler.kt new file mode 100644 index 00000000000..1535a470777 --- /dev/null +++ b/plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/LombokMavenProjectImportHandler.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.lombok.ide + +import org.jetbrains.kotlin.lombok.LombokCommandLineProcessor +import org.jetbrains.kotlin.lombok.LombokCommandLineProcessor.Companion.CONFIG_FILE_OPTION +import org.jetbrains.kotlin.lombok.ide.CompilerPluginSetup.PluginOption +import org.jetbrains.kotlin.utils.PathUtil +import java.io.File + +class LombokMavenProjectImportHandler : AbstractMavenImportHandler() { + override val compilerPluginId: String = LombokCommandLineProcessor.PLUGIN_ID + override val pluginName: String = MAVEN_SUBPLUGIN_NAME + override val pluginJarFileFromIdea: File = PathUtil.kotlinPathsForIdeaPlugin.lombokPluginJarPath + + override fun getOptions( + enabledCompilerPlugins: List, + compilerPluginOptions: List + ): List? { + if (!enabledCompilerPlugins.contains(pluginName)) return null + + return compilerPluginOptions.mapNotNull { v -> + if (v.startsWith(CONFIG_FILE_PREFIX)) { + val location = v.substring(CONFIG_FILE_PREFIX.length) + PluginOption(CONFIG_FILE_OPTION.optionName, location) + } else { + null + } + } + } + + companion object { + private const val MAVEN_SUBPLUGIN_NAME = "lombok" + private val CONFIG_FILE_PREFIX = "$MAVEN_SUBPLUGIN_NAME:${CONFIG_FILE_OPTION.optionName}=" + } +} diff --git a/plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/idePluginUtils.kt b/plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/idePluginUtils.kt new file mode 100644 index 00000000000..19e32472899 --- /dev/null +++ b/plugins/lombok/lombok-ide-plugin/src/org/jetbrains/kotlin/lombok/ide/idePluginUtils.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.lombok.ide + +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.idea.facet.KotlinFacet +import java.io.File + +class CompilerPluginSetup(val options: List, val classpath: List) { + class PluginOption(val key: String, val value: String) +} + +internal fun modifyCompilerArgumentsForPlugin( + facet: KotlinFacet, + setup: CompilerPluginSetup?, + compilerPluginId: String, + pluginName: String +) { + val facetSettings = facet.configuration.settings + + // investigate why copyBean() sometimes throws exceptions + val commonArguments = facetSettings.compilerArguments ?: CommonCompilerArguments.DummyImpl() + + /** See [CommonCompilerArguments.PLUGIN_OPTION_FORMAT] **/ + val newOptionsForPlugin = setup?.options?.map { "plugin:$compilerPluginId:${it.key}=${it.value}" } ?: emptyList() + + val oldAllPluginOptions = + (commonArguments.pluginOptions ?: emptyArray()).filterTo(mutableListOf()) { !it.startsWith("plugin:$compilerPluginId:") } + val newAllPluginOptions = oldAllPluginOptions + newOptionsForPlugin + + val oldPluginClasspaths = (commonArguments.pluginClasspaths ?: emptyArray()).filterTo(mutableListOf()) { + val lastIndexOfFile = it.lastIndexOfAny(charArrayOf('/', File.separatorChar)) + if (lastIndexOfFile < 0) { + return@filterTo true + } + !it.drop(lastIndexOfFile + 1).matches("(kotlin-)?(maven-)?$pluginName-.*\\.jar".toRegex()) + } + + val newPluginClasspaths = oldPluginClasspaths + (setup?.classpath ?: emptyList()) + + commonArguments.pluginOptions = newAllPluginOptions.toTypedArray() + commonArguments.pluginClasspaths = newPluginClasspaths.toTypedArray() + + facetSettings.compilerArguments = commonArguments +} diff --git a/prepare/compiler/build.gradle.kts b/prepare/compiler/build.gradle.kts index 2e7b7e61a56..7c4c488e0aa 100644 --- a/prepare/compiler/build.gradle.kts +++ b/prepare/compiler/build.gradle.kts @@ -114,7 +114,8 @@ val distCompilerPluginProjects = listOf( ":plugins:parcelize:parcelize-runtime", ":kotlin-noarg-compiler-plugin", ":kotlin-sam-with-receiver-compiler-plugin", - ":kotlinx-serialization-compiler-plugin" + ":kotlinx-serialization-compiler-plugin", + ":plugins:lombok:lombok-compiler-plugin" ) val distSourcesProjects = listOfNotNull( diff --git a/prepare/ide-plugin-dependencies/lombok-compiler-plugin-for-ide/build.gradle.kts b/prepare/ide-plugin-dependencies/lombok-compiler-plugin-for-ide/build.gradle.kts new file mode 100644 index 00000000000..87c06675b35 --- /dev/null +++ b/prepare/ide-plugin-dependencies/lombok-compiler-plugin-for-ide/build.gradle.kts @@ -0,0 +1,3 @@ +idePluginDependency { + publishProjectJars(listOf(":plugins:lombok:lombok-compiler-plugin")) +} diff --git a/prepare/idea-plugin/build.gradle.kts b/prepare/idea-plugin/build.gradle.kts index c5b00c75d73..76d09302f1a 100644 --- a/prepare/idea-plugin/build.gradle.kts +++ b/prepare/idea-plugin/build.gradle.kts @@ -138,6 +138,7 @@ val libraryProjects = listOf( ":kotlin-allopen-compiler-plugin", ":kotlin-noarg-compiler-plugin", ":kotlin-sam-with-receiver-compiler-plugin", + ":plugins:lombok:lombok-compiler-plugin", ":plugins:android-extensions-compiler", ":plugins:parcelize:parcelize-compiler", ":kotlinx-serialization-compiler-plugin", @@ -193,6 +194,7 @@ dependencies { gradleToolingModel(project(":plugins:parcelize:parcelize-ide")) { isTransitive = false } gradleToolingModel(project(":noarg-ide-plugin")) { isTransitive = false } gradleToolingModel(project(":allopen-ide-plugin")) { isTransitive = false } + gradleToolingModel(project(":plugins:lombok:lombok-ide-plugin")) { isTransitive = false } jpsPlugin(project(":kotlin-jps-plugin")) { isTransitive = false } diff --git a/settings.gradle b/settings.gradle index fa6dfb26513..f9d4aa9b142 100644 --- a/settings.gradle +++ b/settings.gradle @@ -347,6 +347,7 @@ include ":plugins:parcelize:parcelize-compiler", ":kotlin-parcelize-compiler" include ":plugins:lombok:lombok-compiler-plugin", + ":plugins:lombok:lombok-ide-plugin", ":kotlin-lombok" include ":prepare:ide-plugin-dependencies:android-extensions-compiler-plugin-for-ide", @@ -361,6 +362,7 @@ include ":prepare:ide-plugin-dependencies:android-extensions-compiler-plugin-for ":prepare:ide-plugin-dependencies:noarg-compiler-plugin-for-ide", ":prepare:ide-plugin-dependencies:sam-with-receiver-compiler-plugin-for-ide", ":prepare:ide-plugin-dependencies:parcelize-compiler-plugin-for-ide", + ":prepare:ide-plugin-dependencies:lombok-compiler-plugin-for-ide", ":prepare:ide-plugin-dependencies:tests-common-tests-for-ide", ":prepare:ide-plugin-dependencies:compiler-components-for-jps"