From 44e707011825c34f72f6af7c503704a962b7e7e5 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Thu, 24 May 2018 00:27:43 +0300 Subject: [PATCH] Configuration: Use 'plugins' block in generated/modified Gradle scripts Follow-up for 172/173/AS3.1/AS3.2 bunches --- .../GradleBuildScriptManipulator.kt.172 | 70 +++++++++++++++ .../GradleBuildScriptManipulator.kt.173 | 69 +++++++++++++++ ...linGradleMultiplatformModuleBuilder.kt.172 | 6 +- .../KotlinWithGradleConfigurator.kt.as31 | 66 +++++++++----- .../KotlinWithGradleConfigurator.kt.as32 | 66 +++++++++----- .../gradleModuleBuilderUtils.kt.172 | 86 +++++++++++++++++++ 6 files changed, 320 insertions(+), 43 deletions(-) create mode 100644 idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GradleBuildScriptManipulator.kt.172 create mode 100644 idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GradleBuildScriptManipulator.kt.173 create mode 100644 idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/gradleModuleBuilderUtils.kt.172 diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GradleBuildScriptManipulator.kt.172 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GradleBuildScriptManipulator.kt.172 new file mode 100644 index 00000000000..a737dadc79a --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GradleBuildScriptManipulator.kt.172 @@ -0,0 +1,70 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * 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. + */ + +package org.jetbrains.kotlin.idea.configuration + +import com.intellij.openapi.roots.DependencyScope +import com.intellij.openapi.roots.ExternalLibraryDescriptor +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.gradle.util.GradleVersion +import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder + +interface GradleBuildScriptManipulator { + val scriptFile: Psi + val preferNewSyntax: Boolean + + fun isConfiguredWithOldSyntax(kotlinPluginName: String): Boolean + fun isConfigured(kotlinPluginExpression: String): Boolean + + fun configureModuleBuildScript( + kotlinPluginName: String, + kotlinPluginExpression: String, + stdlibArtifactName: String, + version: String, + jvmTarget: String? + ): Boolean + + fun configureProjectBuildScript(kotlinPluginName: String, version: String): Boolean + + fun changeCoroutineConfiguration(coroutineOption: String): PsiElement? + + fun changeLanguageVersion(version: String, forTests: Boolean): PsiElement? + + fun changeApiVersion(version: String, forTests: Boolean): PsiElement? + + fun addKotlinLibraryToModuleBuildScript( + scope: DependencyScope, + libraryDescriptor: ExternalLibraryDescriptor, + isAndroidModule: Boolean + ) + + fun getKotlinStdlibVersion(): String? + + // For settings.gradle/settings.gradle.kts + + fun addMavenCentralPluginRepository() + fun addPluginRepository(repository: RepositoryDescription) + + fun addResolutionStrategy(pluginId: String) +} + +val MIN_GRADLE_VERSION_FOR_NEW_PLUGIN_SYNTAX = GradleVersion.version("4.4") + +// Kept for compatibility reasons (pre-181.3 IDEAs) +fun GradleBuildScriptManipulator<*>.useNewSyntax(kotlinPluginName: String) = false +val BuildScriptDataBuilder.gradleVersion get() = GradleVersion.version("0.0") +fun BuildScriptDataBuilder.addPluginDefinitionInPluginsGroup(pluginId: String) {} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GradleBuildScriptManipulator.kt.173 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GradleBuildScriptManipulator.kt.173 new file mode 100644 index 00000000000..ddc1c9a24e8 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GradleBuildScriptManipulator.kt.173 @@ -0,0 +1,69 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * 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. + */ + +package org.jetbrains.kotlin.idea.configuration + +import com.intellij.openapi.roots.DependencyScope +import com.intellij.openapi.roots.ExternalLibraryDescriptor +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiFile +import org.gradle.util.GradleVersion +import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder + +interface GradleBuildScriptManipulator { + val scriptFile: Psi + val preferNewSyntax: Boolean + + fun isConfiguredWithOldSyntax(kotlinPluginName: String): Boolean + fun isConfigured(kotlinPluginExpression: String): Boolean + + fun configureModuleBuildScript( + kotlinPluginName: String, + kotlinPluginExpression: String, + stdlibArtifactName: String, + version: String, + jvmTarget: String? + ): Boolean + + fun configureProjectBuildScript(kotlinPluginName: String, version: String): Boolean + + fun changeCoroutineConfiguration(coroutineOption: String): PsiElement? + + fun changeLanguageVersion(version: String, forTests: Boolean): PsiElement? + + fun changeApiVersion(version: String, forTests: Boolean): PsiElement? + + fun addKotlinLibraryToModuleBuildScript( + scope: DependencyScope, + libraryDescriptor: ExternalLibraryDescriptor, + isAndroidModule: Boolean + ) + + fun getKotlinStdlibVersion(): String? + + // For settings.gradle/settings.gradle.kts + + fun addMavenCentralPluginRepository() + fun addPluginRepository(repository: RepositoryDescription) + + fun addResolutionStrategy(pluginId: String) +} + +val MIN_GRADLE_VERSION_FOR_NEW_PLUGIN_SYNTAX = GradleVersion.version("4.4") + +// Kept for compatibility reasons (pre-181.3 IDEAs) +fun GradleBuildScriptManipulator<*>.useNewSyntax(kotlinPluginName: String) = false +val BuildScriptDataBuilder.gradleVersion get() = GradleVersion.version("0.0") \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleMultiplatformModuleBuilder.kt.172 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleMultiplatformModuleBuilder.kt.172 index bf30980c66d..09d84ad7857 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleMultiplatformModuleBuilder.kt.172 +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleMultiplatformModuleBuilder.kt.172 @@ -65,7 +65,7 @@ class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() { val module = modifiableRootModel.module val buildScriptData = getBuildScriptData(module) ?: return val sdk = modifiableRootModel.sdk - GradleKotlinMPPCommonFrameworkSupportProvider().addSupport(buildScriptData, sdk) + GradleKotlinMPPCommonFrameworkSupportProvider().addSupport(buildScriptData, module, sdk, true) } } @@ -110,7 +110,7 @@ class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() { rootModule: Module, contentRoot: VirtualFile ) = setupChildModule(rootModule, contentRoot, commonModuleName) { builder, sdk -> - GradleKotlinMPPCommonFrameworkSupportProvider().addSupport(builder, sdk) + GradleKotlinMPPCommonFrameworkSupportProvider().addSupport(builder, rootModule, sdk, true) } private fun setupPlatformModule( @@ -120,7 +120,7 @@ class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() { supportProvider: GradleKotlinFrameworkSupportProvider, sdk: Sdk? = null ) = setupChildModule(rootModule, contentRoot, platformModuleName, sdk) { builder, finalSdk -> - supportProvider.addSupport(builder, finalSdk) + supportProvider.addSupport(builder, rootModule, finalSdk, true) val dependency = commonModuleName ?: "" builder.addDependencyNotation("expectedBy project(\":$dependency\")") } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as31 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as31 index 5af0cbe204c..2ab69a5ee7f 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as31 +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as31 @@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.WritingAccessProvider import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager +import com.intellij.util.PathUtil import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.CoroutineSupport import org.jetbrains.kotlin.config.LanguageFeature @@ -82,7 +83,11 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { protected open fun getMinimumSupportedVersion() = "1.0.0" - private fun isFileConfigured(buildScript: PsiFile): Boolean = getManipulator(buildScript).isConfigured(kotlinPluginName) + protected fun PsiFile.isKtDsl() = this is KtFile + + private fun isFileConfigured(buildScript: PsiFile): Boolean = with(getManipulator(buildScript)) { + isConfiguredWithOldSyntax(kotlinPluginName) || isConfigured(getKotlinPluginExpression(buildScript.isKtDsl())) + } @JvmSuppressWildcards override fun configure(project: Project, excludeModules: Collection) { @@ -152,6 +157,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { val jvmTarget = getJvmTarget(sdk, version) return getManipulator(file).configureModuleBuildScript( kotlinPluginName, + getKotlinPluginExpression(file.isKtDsl()), getStdlibArtifactName(sdk, version), version, jvmTarget @@ -163,6 +169,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { protected open fun getJvmTarget(sdk: Sdk?, version: String): String? = null protected abstract val kotlinPluginName: String + protected abstract fun getKotlinPluginExpression(forKotlinDsl: Boolean): String protected open fun addElementsToFile( file: PsiFile, @@ -170,7 +177,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { version: String ): Boolean { if (!isTopLevelProjectFile) { - var wasModified = configureProjectFile(file, version) + var wasModified = getManipulator(file).configureProjectBuildScript(kotlinPluginName, version) wasModified = wasModified or configureModuleBuildScript(file, version) return wasModified } @@ -256,21 +263,20 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { } companion object { - fun getManipulator(file: PsiFile): GradleBuildScriptManipulator = when (file) { - is KtFile -> KotlinBuildScriptManipulator(file) - is GroovyFile -> GroovyBuildScriptManipulator(file) + fun getManipulator(file: PsiFile, preferNewSyntax: Boolean = true): GradleBuildScriptManipulator<*> = when (file) { + is KtFile -> KotlinBuildScriptManipulator(file, preferNewSyntax) + is GroovyFile -> GroovyBuildScriptManipulator(file, preferNewSyntax) else -> error("Unknown build script file type!") } val GROUP_ID = "org.jetbrains.kotlin" val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin" - val CLASSPATH = "classpath \"$GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\"" - private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts" + private val KOTLIN_SETTINGS_SCRIPT_NAME = "settings.gradle.kts" - fun getGroovyDependencySnippet(artifactName: String, scope: String) = - "$scope \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\"" + fun getGroovyDependencySnippet(artifactName: String, scope: String, withVersion: Boolean) = + "$scope \"org.jetbrains.kotlin:$artifactName${if (withVersion) ":\$kotlin_version" else ""}\"" fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'" @@ -325,28 +331,37 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { } } - fun configureProjectFile(file: PsiFile, version: String): Boolean = getManipulator(file).configureProjectBuildScript(version) - private fun canConfigureFile(file: PsiFile): Boolean = WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null) - private fun Module.getBuildScriptPsiFile() = getBuildScriptFile()?.getPsiFile(project) + private fun Module.getBuildScriptPsiFile() = + getBuildScriptFile(GradleConstants.DEFAULT_SCRIPT_NAME, KOTLIN_BUILD_SCRIPT_NAME)?.getPsiFile(project) - private fun Project.getTopLevelBuildScriptPsiFile() = basePath?.let { findBuildGradleFile(it)?.getPsiFile(this) } + fun Module.getBuildScriptSettingsPsiFile() = + getBuildScriptSettingsFile(GradleConstants.SETTINGS_FILE_NAME, KOTLIN_SETTINGS_SCRIPT_NAME)?.getPsiFile(project) - private fun Module.getBuildScriptFile(): File? { + private fun Project.getTopLevelBuildScriptPsiFile() = basePath?.let { + findBuildGradleFile(it, GradleConstants.DEFAULT_SCRIPT_NAME, KOTLIN_BUILD_SCRIPT_NAME)?.getPsiFile(this) + } + + fun Module.getTopLevelBuildScriptSettingsPsiFile() = + ExternalSystemApiUtil.getExternalRootProjectPath(this)?.let { externalProjectPath -> + findBuildGradleFile(externalProjectPath, GradleConstants.SETTINGS_FILE_NAME, KOTLIN_SETTINGS_SCRIPT_NAME)?.getPsiFile(project) + } + + private fun Module.getBuildScriptFile(vararg fileNames: String): File? { val moduleDir = File(moduleFilePath).parent - findBuildGradleFile(moduleDir)?.let { + findBuildGradleFile(moduleDir, *fileNames)?.let { return it } ModuleRootManager.getInstance(this).contentRoots.forEach { root -> - findBuildGradleFile(root.path)?.let { + findBuildGradleFile(root.path, *fileNames)?.let { return it } } ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath -> - findBuildGradleFile(externalProjectPath)?.let { + findBuildGradleFile(externalProjectPath, *fileNames)?.let { return it } } @@ -354,9 +369,20 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { return null } - private fun findBuildGradleFile(path: String): File? = - File(path + "/" + GradleConstants.DEFAULT_SCRIPT_NAME).takeIf { it.exists() } - ?: File(path + "/" + KOTLIN_BUILD_SCRIPT_NAME).takeIf { it.exists() } + private fun Module.getBuildScriptSettingsFile(vararg fileNames: String): File? { + ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath -> + return generateSequence(externalProjectPath) { + PathUtil.getParentPath(it).let { if (it.isBlank()) null else it } + }.mapNotNull { + findBuildGradleFile(it, *fileNames) + }.firstOrNull() + } + + return null + } + + private fun findBuildGradleFile(path: String, vararg fileNames: String): File? = + fileNames.asSequence().map { File(path + "/" + it) }.firstOrNull { it.exists() } private fun File.getPsiFile(project: Project) = VfsUtil.findFileByIoFile(this, true)?.let { PsiManager.getInstance(project).findFile(it) diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as32 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as32 index 5af0cbe204c..2ab69a5ee7f 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as32 +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as32 @@ -24,6 +24,7 @@ import com.intellij.openapi.vfs.WritingAccessProvider import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager +import com.intellij.util.PathUtil import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.CoroutineSupport import org.jetbrains.kotlin.config.LanguageFeature @@ -82,7 +83,11 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { protected open fun getMinimumSupportedVersion() = "1.0.0" - private fun isFileConfigured(buildScript: PsiFile): Boolean = getManipulator(buildScript).isConfigured(kotlinPluginName) + protected fun PsiFile.isKtDsl() = this is KtFile + + private fun isFileConfigured(buildScript: PsiFile): Boolean = with(getManipulator(buildScript)) { + isConfiguredWithOldSyntax(kotlinPluginName) || isConfigured(getKotlinPluginExpression(buildScript.isKtDsl())) + } @JvmSuppressWildcards override fun configure(project: Project, excludeModules: Collection) { @@ -152,6 +157,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { val jvmTarget = getJvmTarget(sdk, version) return getManipulator(file).configureModuleBuildScript( kotlinPluginName, + getKotlinPluginExpression(file.isKtDsl()), getStdlibArtifactName(sdk, version), version, jvmTarget @@ -163,6 +169,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { protected open fun getJvmTarget(sdk: Sdk?, version: String): String? = null protected abstract val kotlinPluginName: String + protected abstract fun getKotlinPluginExpression(forKotlinDsl: Boolean): String protected open fun addElementsToFile( file: PsiFile, @@ -170,7 +177,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { version: String ): Boolean { if (!isTopLevelProjectFile) { - var wasModified = configureProjectFile(file, version) + var wasModified = getManipulator(file).configureProjectBuildScript(kotlinPluginName, version) wasModified = wasModified or configureModuleBuildScript(file, version) return wasModified } @@ -256,21 +263,20 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { } companion object { - fun getManipulator(file: PsiFile): GradleBuildScriptManipulator = when (file) { - is KtFile -> KotlinBuildScriptManipulator(file) - is GroovyFile -> GroovyBuildScriptManipulator(file) + fun getManipulator(file: PsiFile, preferNewSyntax: Boolean = true): GradleBuildScriptManipulator<*> = when (file) { + is KtFile -> KotlinBuildScriptManipulator(file, preferNewSyntax) + is GroovyFile -> GroovyBuildScriptManipulator(file, preferNewSyntax) else -> error("Unknown build script file type!") } val GROUP_ID = "org.jetbrains.kotlin" val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin" - val CLASSPATH = "classpath \"$GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\"" - private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts" + private val KOTLIN_SETTINGS_SCRIPT_NAME = "settings.gradle.kts" - fun getGroovyDependencySnippet(artifactName: String, scope: String) = - "$scope \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\"" + fun getGroovyDependencySnippet(artifactName: String, scope: String, withVersion: Boolean) = + "$scope \"org.jetbrains.kotlin:$artifactName${if (withVersion) ":\$kotlin_version" else ""}\"" fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'" @@ -325,28 +331,37 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { } } - fun configureProjectFile(file: PsiFile, version: String): Boolean = getManipulator(file).configureProjectBuildScript(version) - private fun canConfigureFile(file: PsiFile): Boolean = WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null) - private fun Module.getBuildScriptPsiFile() = getBuildScriptFile()?.getPsiFile(project) + private fun Module.getBuildScriptPsiFile() = + getBuildScriptFile(GradleConstants.DEFAULT_SCRIPT_NAME, KOTLIN_BUILD_SCRIPT_NAME)?.getPsiFile(project) - private fun Project.getTopLevelBuildScriptPsiFile() = basePath?.let { findBuildGradleFile(it)?.getPsiFile(this) } + fun Module.getBuildScriptSettingsPsiFile() = + getBuildScriptSettingsFile(GradleConstants.SETTINGS_FILE_NAME, KOTLIN_SETTINGS_SCRIPT_NAME)?.getPsiFile(project) - private fun Module.getBuildScriptFile(): File? { + private fun Project.getTopLevelBuildScriptPsiFile() = basePath?.let { + findBuildGradleFile(it, GradleConstants.DEFAULT_SCRIPT_NAME, KOTLIN_BUILD_SCRIPT_NAME)?.getPsiFile(this) + } + + fun Module.getTopLevelBuildScriptSettingsPsiFile() = + ExternalSystemApiUtil.getExternalRootProjectPath(this)?.let { externalProjectPath -> + findBuildGradleFile(externalProjectPath, GradleConstants.SETTINGS_FILE_NAME, KOTLIN_SETTINGS_SCRIPT_NAME)?.getPsiFile(project) + } + + private fun Module.getBuildScriptFile(vararg fileNames: String): File? { val moduleDir = File(moduleFilePath).parent - findBuildGradleFile(moduleDir)?.let { + findBuildGradleFile(moduleDir, *fileNames)?.let { return it } ModuleRootManager.getInstance(this).contentRoots.forEach { root -> - findBuildGradleFile(root.path)?.let { + findBuildGradleFile(root.path, *fileNames)?.let { return it } } ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath -> - findBuildGradleFile(externalProjectPath)?.let { + findBuildGradleFile(externalProjectPath, *fileNames)?.let { return it } } @@ -354,9 +369,20 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { return null } - private fun findBuildGradleFile(path: String): File? = - File(path + "/" + GradleConstants.DEFAULT_SCRIPT_NAME).takeIf { it.exists() } - ?: File(path + "/" + KOTLIN_BUILD_SCRIPT_NAME).takeIf { it.exists() } + private fun Module.getBuildScriptSettingsFile(vararg fileNames: String): File? { + ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath -> + return generateSequence(externalProjectPath) { + PathUtil.getParentPath(it).let { if (it.isBlank()) null else it } + }.mapNotNull { + findBuildGradleFile(it, *fileNames) + }.firstOrNull() + } + + return null + } + + private fun findBuildGradleFile(path: String, vararg fileNames: String): File? = + fileNames.asSequence().map { File(path + "/" + it) }.firstOrNull { it.exists() } private fun File.getPsiFile(project: Project) = VfsUtil.findFileByIoFile(this, true)?.let { PsiManager.getInstance(project).findFile(it) diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/gradleModuleBuilderUtils.kt.172 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/gradleModuleBuilderUtils.kt.172 new file mode 100644 index 00000000000..166a92cd2c8 --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/gradleModuleBuilderUtils.kt.172 @@ -0,0 +1,86 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.idea.configuration + +import com.intellij.framework.addSupport.FrameworkSupportInModuleConfigurable +import com.intellij.ide.util.frameworkSupport.FrameworkSupportModel +import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.ModifiableModelsProvider +import com.intellij.openapi.roots.ModifiableRootModel +import com.intellij.openapi.util.Key +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiFile +import com.intellij.psi.codeStyle.CodeStyleManager +import org.jetbrains.kotlin.idea.core.copied +import org.jetbrains.kotlin.idea.refactoring.toPsiFile +import org.jetbrains.kotlin.psi.UserDataProperty +import org.jetbrains.plugins.gradle.frameworkSupport.GradleFrameworkSupportProvider +import org.jetbrains.plugins.gradle.service.project.wizard.GradleModuleBuilder +import org.jetbrains.plugins.gradle.util.GradleConstants +import java.io.File + +internal var Module.gradleModuleBuilder: GradleModuleBuilder? by UserDataProperty(Key.create("GRADLE_MODULE_BUILDER")) +private var Module.editableSettingsPsiFileCopy: PsiFile? by UserDataProperty(Key.create("EDITABLE_SETTINGS_PSI_FILE_COPY")) + +internal fun findSettingsGradleFile(module: Module): VirtualFile? { + val contentEntryPath = module.gradleModuleBuilder?.contentEntryPath ?: return null + if (contentEntryPath.isEmpty()) return null + val contentRootDir = File(contentEntryPath) + val modelContentRootDir = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(contentRootDir) ?: return null + return modelContentRootDir.findChild(GradleConstants.SETTINGS_FILE_NAME) + ?: module.project.baseDir.findChild(GradleConstants.SETTINGS_FILE_NAME) +} + +// Circumvent write actions and modify the file directly +// TODO: Get rid of this hack when IDEA API allows manipulation of settings script similarly to the main script itself +internal fun updateSettingsScript(module: Module, updater: (PsiFile) -> Unit) { + val storedCopy = module.editableSettingsPsiFileCopy + val settingsPsiCopy = storedCopy ?: findSettingsGradleFile(module)?.toPsiFile(module.project)?.copied() ?: return + if (storedCopy == null) { + module.editableSettingsPsiFileCopy = settingsPsiCopy + } + updater(settingsPsiCopy) +} + +internal fun flushSettingsGradleCopy(module: Module) { + try { + val settingsFile = findSettingsGradleFile(module) + val settingsPsiCopy = module.editableSettingsPsiFileCopy + if (settingsPsiCopy != null && settingsFile != null) { + CodeStyleManager.getInstance(module.project).reformat(settingsPsiCopy) + VfsUtil.saveText(settingsFile, settingsPsiCopy.text) + } + } finally { + module.gradleModuleBuilder = null + module.editableSettingsPsiFileCopy = null + } +} + +class KotlinGradleFrameworkSupportInModuleConfigurable( + private val model: FrameworkSupportModel, + private val supportProvider: GradleFrameworkSupportProvider +) : FrameworkSupportInModuleConfigurable() { + override fun createComponent() = null + + override fun addSupport( + module: Module, + rootModel: ModifiableRootModel, + modifiableModelsProvider: ModifiableModelsProvider + ) { + val buildScriptData = GradleModuleBuilder.getBuildScriptData(module) + if (buildScriptData != null) { + val builder = model.moduleBuilder + try { + module.gradleModuleBuilder = builder as? GradleModuleBuilder + supportProvider.addSupport(module, rootModel, modifiableModelsProvider, buildScriptData) + } finally { + flushSettingsGradleCopy(module) + } + } + } +} \ No newline at end of file