Configuration: Use 'plugins' block in generated/modified Gradle scripts
#KT-20665 Fixed
This commit is contained in:
+6
-3
@@ -32,17 +32,20 @@ class KotlinAndroidGradleModuleConfigurator internal constructor() : KotlinWithG
|
||||
|
||||
override val kotlinPluginName: String = KOTLIN_ANDROID
|
||||
|
||||
override fun getKotlinPluginExpression(forKotlinDsl: Boolean): String =
|
||||
if (forKotlinDsl) "kotlin(\"android\")" else "id 'org.jetbrains.kotlin.android' "
|
||||
|
||||
override fun addElementsToFile(file: PsiFile, isTopLevelProjectFile: Boolean, version: String): Boolean {
|
||||
val manipulator = getManipulator(file)
|
||||
val manipulator = getManipulator(file, false)
|
||||
val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk }
|
||||
val jvmTarget = getJvmTarget(sdk, version)
|
||||
|
||||
return if (isTopLevelProjectFile) {
|
||||
manipulator.configureProjectBuildScript(version)
|
||||
manipulator.configureProjectBuildScript(kotlinPluginName, version)
|
||||
}
|
||||
else {
|
||||
manipulator.configureModuleBuildScript(
|
||||
kotlinPluginName,
|
||||
getKotlinPluginExpression(file.isKtDsl()),
|
||||
getStdlibArtifactName(sdk, version),
|
||||
version,
|
||||
jvmTarget
|
||||
|
||||
+33
-3
@@ -16,21 +16,31 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
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.kotlin.idea.util.module
|
||||
import org.jetbrains.plugins.gradle.settings.GradleSettings
|
||||
|
||||
interface GradleBuildScriptManipulator {
|
||||
fun isConfigured(kotlinPluginName: String): Boolean
|
||||
interface GradleBuildScriptManipulator<out Psi: PsiFile> {
|
||||
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(version: String): Boolean
|
||||
fun configureProjectBuildScript(kotlinPluginName: String, version: String): Boolean
|
||||
|
||||
fun changeCoroutineConfiguration(coroutineOption: String): PsiElement?
|
||||
|
||||
@@ -45,4 +55,24 @@ interface GradleBuildScriptManipulator {
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
fun GradleBuildScriptManipulator<*>.useNewSyntax(kotlinPluginName: String): Boolean {
|
||||
if (!preferNewSyntax) return false
|
||||
|
||||
val module = scriptFile.module ?: return false
|
||||
val path = ExternalSystemApiUtil.getExternalProjectPath(module) ?: return false
|
||||
val gradleVersion = GradleSettings.getInstance(module.project).getLinkedProjectSettings(path)?.resolveGradleVersion() ?: return false
|
||||
if (gradleVersion < MIN_GRADLE_VERSION_FOR_NEW_PLUGIN_SYNTAX) return false
|
||||
|
||||
return !isConfiguredWithOldSyntax(kotlinPluginName)
|
||||
}
|
||||
+79
-23
@@ -24,6 +24,7 @@ import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.ModifiableModelsProvider
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.versions.*
|
||||
import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder
|
||||
@@ -46,7 +47,7 @@ abstract class GradleKotlinFrameworkSupportProvider(
|
||||
}
|
||||
|
||||
override fun createConfigurable(model: FrameworkSupportModel): FrameworkSupportInModuleConfigurable {
|
||||
val configurable = super.createConfigurable(model)
|
||||
val configurable = KotlinGradleFrameworkSupportInModuleConfigurable(model, this)
|
||||
return object : FrameworkSupportInModuleConfigurable() {
|
||||
override fun addSupport(module: Module, rootModel: ModifiableRootModel, modifiableModelsProvider: ModifiableModelsProvider) {
|
||||
configurable.addSupport(module, rootModel, modifiableModelsProvider)
|
||||
@@ -62,50 +63,75 @@ abstract class GradleKotlinFrameworkSupportProvider(
|
||||
modifiableModelsProvider: ModifiableModelsProvider,
|
||||
buildScriptData: BuildScriptDataBuilder
|
||||
) {
|
||||
addSupport(buildScriptData, rootModel.sdk)
|
||||
addSupport(buildScriptData, module, rootModel.sdk, true)
|
||||
}
|
||||
|
||||
open fun addSupport(buildScriptData: BuildScriptDataBuilder, sdk: Sdk?) {
|
||||
open fun addSupport(buildScriptData: BuildScriptDataBuilder, module: Module, sdk: Sdk?, specifyPluginVersionIfNeeded: Boolean) {
|
||||
var kotlinVersion = bundledRuntimeVersion()
|
||||
val additionalRepository = getRepositoryForVersion(kotlinVersion)
|
||||
if (isSnapshot(bundledRuntimeVersion())) {
|
||||
kotlinVersion = LAST_SNAPSHOT_VERSION
|
||||
}
|
||||
|
||||
if (additionalRepository != null) {
|
||||
val oneLineRepository = additionalRepository.toGroovyRepositorySnippet().replace('\n', ' ')
|
||||
buildScriptData.addBuildscriptRepositoriesDefinition(oneLineRepository)
|
||||
val useNewSyntax = buildScriptData.gradleVersion >= MIN_GRADLE_VERSION_FOR_NEW_PLUGIN_SYNTAX
|
||||
if (useNewSyntax) {
|
||||
if (additionalRepository != null) {
|
||||
val oneLineRepository = additionalRepository.toGroovyRepositorySnippet().replace('\n', ' ')
|
||||
updateSettingsScript(module) {
|
||||
with(KotlinWithGradleConfigurator.getManipulator(it)) {
|
||||
addPluginRepository(additionalRepository)
|
||||
addMavenCentralPluginRepository()
|
||||
}
|
||||
}
|
||||
buildScriptData.addRepositoriesDefinition("mavenCentral()")
|
||||
buildScriptData.addRepositoriesDefinition(oneLineRepository)
|
||||
}
|
||||
|
||||
buildScriptData.addRepositoriesDefinition("mavenCentral()")
|
||||
buildScriptData.addRepositoriesDefinition(oneLineRepository)
|
||||
buildScriptData.addPluginDefinitionInPluginsGroup(
|
||||
getPluginExpression() + if (specifyPluginVersionIfNeeded) " version '$kotlinVersion'" else ""
|
||||
)
|
||||
} else {
|
||||
if (additionalRepository != null) {
|
||||
val oneLineRepository = additionalRepository.toGroovyRepositorySnippet().replace('\n', ' ')
|
||||
buildScriptData.addBuildscriptRepositoriesDefinition(oneLineRepository)
|
||||
|
||||
buildScriptData.addRepositoriesDefinition("mavenCentral()")
|
||||
buildScriptData.addRepositoriesDefinition(oneLineRepository)
|
||||
}
|
||||
|
||||
buildScriptData
|
||||
.addPluginDefinition(KotlinWithGradleConfigurator.getGroovyApplyPluginDirective(getPluginId()))
|
||||
|
||||
.addBuildscriptRepositoriesDefinition("mavenCentral()")
|
||||
.addRepositoriesDefinition("mavenCentral()")
|
||||
|
||||
.addBuildscriptPropertyDefinition("ext.kotlin_version = '$kotlinVersion'")
|
||||
}
|
||||
|
||||
buildScriptData
|
||||
.addPluginDefinition(KotlinWithGradleConfigurator.getGroovyApplyPluginDirective(getPluginId()))
|
||||
|
||||
.addBuildscriptRepositoriesDefinition("mavenCentral()")
|
||||
.addRepositoriesDefinition("mavenCentral()")
|
||||
|
||||
.addBuildscriptPropertyDefinition("ext.kotlin_version = '$kotlinVersion'")
|
||||
|
||||
for (dependency in getDependencies(sdk)) {
|
||||
buildScriptData.addDependencyNotation(KotlinWithGradleConfigurator.getGroovyDependencySnippet(dependency, "compile"))
|
||||
buildScriptData.addDependencyNotation(KotlinWithGradleConfigurator.getGroovyDependencySnippet(dependency, "compile", !useNewSyntax))
|
||||
}
|
||||
for (dependency in getTestDependencies()) {
|
||||
buildScriptData.addDependencyNotation(
|
||||
if (":" in dependency)
|
||||
"testCompile \"$dependency\""
|
||||
else
|
||||
KotlinWithGradleConfigurator.getGroovyDependencySnippet(dependency, "testCompile")
|
||||
KotlinWithGradleConfigurator.getGroovyDependencySnippet(dependency, "testCompile", !useNewSyntax)
|
||||
)
|
||||
}
|
||||
buildScriptData.addBuildscriptDependencyNotation(KotlinWithGradleConfigurator.CLASSPATH)
|
||||
|
||||
if (useNewSyntax) {
|
||||
updateSettingsScript(module) { updateSettingsScript(it, specifyPluginVersionIfNeeded) }
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun updateSettingsScript(settingsScript: PsiFile, specifyPluginVersionIfNeeded: Boolean) { }
|
||||
|
||||
protected abstract fun getDependencies(sdk: Sdk?): List<String>
|
||||
protected open fun getTestDependencies(): List<String> = listOf()
|
||||
|
||||
protected abstract fun getPluginId(): String
|
||||
protected abstract fun getPluginExpression(): String
|
||||
|
||||
protected abstract fun getDescription(): String
|
||||
}
|
||||
@@ -116,11 +142,12 @@ open class GradleKotlinJavaFrameworkSupportProvider(
|
||||
) : GradleKotlinFrameworkSupportProvider(frameworkTypeId, displayName, KotlinIcons.SMALL_LOGO) {
|
||||
|
||||
override fun getPluginId() = KotlinGradleModuleConfigurator.KOTLIN
|
||||
override fun getPluginExpression() = "id 'org.jetbrains.kotlin.jvm'"
|
||||
|
||||
override fun getDependencies(sdk: Sdk?) = listOf(getStdlibArtifactId(sdk, bundledRuntimeVersion()))
|
||||
|
||||
override fun addSupport(buildScriptData: BuildScriptDataBuilder, sdk: Sdk?) {
|
||||
super.addSupport(buildScriptData, sdk)
|
||||
override fun addSupport(buildScriptData: BuildScriptDataBuilder, module: Module, sdk: Sdk?, specifyPluginVersionIfNeeded: Boolean) {
|
||||
super.addSupport(buildScriptData, module, sdk, specifyPluginVersionIfNeeded)
|
||||
val jvmTarget = getDefaultJvmTarget(sdk, bundledRuntimeVersion())
|
||||
if (jvmTarget != null) {
|
||||
val description = jvmTarget.description
|
||||
@@ -138,21 +165,35 @@ open class GradleKotlinJSFrameworkSupportProvider(
|
||||
) : GradleKotlinFrameworkSupportProvider(frameworkTypeId, displayName, KotlinIcons.JS) {
|
||||
|
||||
override fun getPluginId() = KotlinJsGradleModuleConfigurator.KOTLIN_JS
|
||||
override fun getPluginExpression() = "id 'kotlin2js'"
|
||||
|
||||
override fun getDependencies(sdk: Sdk?) = listOf(MAVEN_JS_STDLIB_ID)
|
||||
|
||||
override fun getTestDependencies() = listOf(MAVEN_JS_TEST_ID)
|
||||
|
||||
override fun updateSettingsScript(settingsScript: PsiFile, specifyPluginVersionIfNeeded: Boolean) {
|
||||
if (specifyPluginVersionIfNeeded) {
|
||||
KotlinWithGradleConfigurator.getManipulator(settingsScript).addResolutionStrategy("kotlin2js")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDescription() = "A Kotlin library or application targeting JavaScript"
|
||||
}
|
||||
|
||||
open class GradleKotlinMPPCommonFrameworkSupportProvider :
|
||||
GradleKotlinFrameworkSupportProvider("KOTLIN_MPP_COMMON", "Kotlin (Multiplatform Common - Experimental)", KotlinIcons.MPP) {
|
||||
override fun getPluginId() = "kotlin-platform-common"
|
||||
override fun getPluginExpression() = "id 'kotlin-platform-common'"
|
||||
|
||||
override fun getDependencies(sdk: Sdk?) = listOf(MAVEN_COMMON_STDLIB_ID)
|
||||
override fun getTestDependencies() = listOf(MAVEN_COMMON_TEST_ID, MAVEN_COMMON_TEST_ANNOTATIONS_ID)
|
||||
|
||||
override fun updateSettingsScript(settingsScript: PsiFile, specifyPluginVersionIfNeeded: Boolean) {
|
||||
if (specifyPluginVersionIfNeeded) {
|
||||
KotlinWithGradleConfigurator.getManipulator(settingsScript).addResolutionStrategy("kotlin-platform-common")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDescription() = "Shared code for a Kotlin multiplatform project (targeting JVM and JS)"
|
||||
}
|
||||
|
||||
@@ -160,11 +201,13 @@ class GradleKotlinMPPJavaFrameworkSupportProvider
|
||||
: GradleKotlinJavaFrameworkSupportProvider("KOTLIN_MPP_JVM", "Kotlin (Multiplatform JVM - Experimental)") {
|
||||
|
||||
override fun getPluginId() = "kotlin-platform-jvm"
|
||||
override fun getPluginExpression() = "id 'kotlin-platform-jvm'"
|
||||
|
||||
override fun getDescription() = "JVM-specific code for a Kotlin multiplatform project"
|
||||
override fun getTestDependencies() = listOf(MAVEN_TEST_ID, MAVEN_TEST_JUNIT_ID, "junit:junit:4.12")
|
||||
|
||||
override fun addSupport(buildScriptData: BuildScriptDataBuilder, sdk: Sdk?) {
|
||||
super.addSupport(buildScriptData, sdk)
|
||||
override fun addSupport(buildScriptData: BuildScriptDataBuilder, module: Module, sdk: Sdk?, specifyPluginVersionIfNeeded: Boolean) {
|
||||
super.addSupport(buildScriptData, module, sdk, specifyPluginVersionIfNeeded)
|
||||
val jvmTarget = getDefaultJvmTarget(sdk, bundledRuntimeVersion())
|
||||
if (jvmTarget != null) {
|
||||
val description = jvmTarget.description
|
||||
@@ -172,11 +215,24 @@ class GradleKotlinMPPJavaFrameworkSupportProvider
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateSettingsScript(settingsScript: PsiFile, specifyPluginVersionIfNeeded: Boolean) {
|
||||
if (specifyPluginVersionIfNeeded) {
|
||||
KotlinWithGradleConfigurator.getManipulator(settingsScript).addResolutionStrategy("kotlin-platform-jvm")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GradleKotlinMPPJSFrameworkSupportProvider
|
||||
: GradleKotlinJSFrameworkSupportProvider("KOTLIN_MPP_JS", "Kotlin (Multiplatform JS - Experimental)") {
|
||||
|
||||
override fun getPluginId() = "kotlin-platform-js"
|
||||
override fun getPluginExpression() = "id 'kotlin-platform-js'"
|
||||
|
||||
override fun updateSettingsScript(settingsScript: PsiFile, specifyPluginVersionIfNeeded: Boolean) {
|
||||
if (specifyPluginVersionIfNeeded) {
|
||||
KotlinWithGradleConfigurator.getManipulator(settingsScript).addResolutionStrategy("kotlin-platform-js")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDescription() = "JavaScript-specific code for a Kotlin multiplatform project"
|
||||
}
|
||||
|
||||
+174
-90
@@ -18,71 +18,109 @@ package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.module
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrAssignmentExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator.Companion.getBuildScriptSettingsPsiFile
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement
|
||||
|
||||
class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : GradleBuildScriptManipulator {
|
||||
override fun isConfigured(kotlinPluginName: String): Boolean {
|
||||
val fileText = runReadAction { groovyScript.text }
|
||||
class GroovyBuildScriptManipulator(
|
||||
override val scriptFile: GroovyFile,
|
||||
override val preferNewSyntax: Boolean
|
||||
) : GradleBuildScriptManipulator<GroovyFile> {
|
||||
override fun isConfiguredWithOldSyntax(kotlinPluginName: String): Boolean {
|
||||
val fileText = runReadAction { scriptFile.text }
|
||||
return containsDirective(fileText, getApplyPluginDirective(kotlinPluginName)) &&
|
||||
fileText.contains("org.jetbrains.kotlin") &&
|
||||
fileText.contains("kotlin-stdlib")
|
||||
}
|
||||
|
||||
override fun isConfigured(kotlinPluginExpression: String): Boolean {
|
||||
val fileText = runReadAction { scriptFile.text }
|
||||
val pluginsBlockText = runReadAction { scriptFile.getBlockByName("plugins")?.text ?: "" }
|
||||
return (containsDirective(pluginsBlockText, kotlinPluginExpression)) &&
|
||||
fileText.contains("org.jetbrains.kotlin") &&
|
||||
fileText.contains("kotlin-stdlib")
|
||||
}
|
||||
|
||||
override fun configureModuleBuildScript(
|
||||
kotlinPluginName: String,
|
||||
kotlinPluginExpression: String,
|
||||
stdlibArtifactName: String,
|
||||
version: String,
|
||||
jvmTarget: String?
|
||||
): Boolean {
|
||||
val oldText = groovyScript.text
|
||||
val applyPluginDirective = getGroovyApplyPluginDirective(kotlinPluginName)
|
||||
if (!containsDirective(groovyScript.text, applyPluginDirective)) {
|
||||
val apply = GroovyPsiElementFactory.getInstance(groovyScript.project).createExpressionFromText(applyPluginDirective)
|
||||
val applyStatement = getApplyStatement(groovyScript)
|
||||
if (applyStatement != null) {
|
||||
groovyScript.addAfter(apply, applyStatement)
|
||||
} else {
|
||||
val anchorBlock = groovyScript.getBlockByName("plugins") ?: groovyScript.getBlockByName("buildscript")
|
||||
if (anchorBlock != null) {
|
||||
groovyScript.addAfter(apply, anchorBlock.parent)
|
||||
} else {
|
||||
groovyScript.addAfter(apply, groovyScript.statements.lastOrNull() ?: groovyScript.firstChild)
|
||||
val oldText = scriptFile.text
|
||||
|
||||
val useNewSyntax = useNewSyntax(kotlinPluginName)
|
||||
if (useNewSyntax) {
|
||||
scriptFile
|
||||
.getPluginsBlock()
|
||||
.addLastExpressionInBlockIfNeeded("$kotlinPluginExpression version '$version'")
|
||||
scriptFile.getRepositoriesBlock().apply {
|
||||
val repository = getRepositoryForVersion(version)
|
||||
if (repository != null) {
|
||||
scriptFile.module?.getBuildScriptSettingsPsiFile()?.let {
|
||||
with(KotlinWithGradleConfigurator.getManipulator(it)) {
|
||||
addPluginRepository(repository)
|
||||
addMavenCentralPluginRepository()
|
||||
}
|
||||
}
|
||||
}
|
||||
addMavenCentralIfMissing()
|
||||
}
|
||||
}
|
||||
else {
|
||||
val applyPluginDirective = getGroovyApplyPluginDirective(kotlinPluginName)
|
||||
if (!containsDirective(scriptFile.text, applyPluginDirective)) {
|
||||
val apply = GroovyPsiElementFactory.getInstance(scriptFile.project).createExpressionFromText(applyPluginDirective)
|
||||
val applyStatement = getApplyStatement(scriptFile)
|
||||
if (applyStatement != null) {
|
||||
scriptFile.addAfter(apply, applyStatement)
|
||||
} else {
|
||||
val anchorBlock = scriptFile.getBlockByName("plugins") ?: scriptFile.getBlockByName("buildscript")
|
||||
if (anchorBlock != null) {
|
||||
scriptFile.addAfter(apply, anchorBlock.parent)
|
||||
} else {
|
||||
scriptFile.addAfter(apply, scriptFile.statements.lastOrNull() ?: scriptFile.firstChild)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scriptFile.getRepositoriesBlock().apply {
|
||||
addRepository(version)
|
||||
addMavenCentralIfMissing()
|
||||
}
|
||||
}
|
||||
|
||||
groovyScript.getRepositoriesBlock().apply {
|
||||
addRepository(version)
|
||||
addMavenCentralIfMissing()
|
||||
}
|
||||
|
||||
groovyScript.getDependenciesBlock().apply {
|
||||
addExpressionInBlockIfNeeded(getGroovyDependencySnippet(stdlibArtifactName), false)
|
||||
scriptFile.getDependenciesBlock().apply {
|
||||
addExpressionOrStatementInBlockIfNeeded(getGroovyDependencySnippet(stdlibArtifactName, !useNewSyntax), false, false)
|
||||
}
|
||||
|
||||
if (jvmTarget != null) {
|
||||
changeKotlinTaskParameter(groovyScript, "jvmTarget", jvmTarget, forTests = false)
|
||||
changeKotlinTaskParameter(groovyScript, "jvmTarget", jvmTarget, forTests = true)
|
||||
changeKotlinTaskParameter(scriptFile, "jvmTarget", jvmTarget, forTests = false)
|
||||
changeKotlinTaskParameter(scriptFile, "jvmTarget", jvmTarget, forTests = true)
|
||||
}
|
||||
|
||||
return groovyScript.text != oldText
|
||||
return scriptFile.text != oldText
|
||||
}
|
||||
|
||||
override fun configureProjectBuildScript(version: String): Boolean {
|
||||
val oldText = groovyScript.text
|
||||
groovyScript.apply {
|
||||
override fun configureProjectBuildScript(kotlinPluginName: String, version: String): Boolean {
|
||||
if (useNewSyntax(kotlinPluginName)) return false
|
||||
|
||||
val oldText = scriptFile.text
|
||||
scriptFile.apply {
|
||||
getBuildScriptBlock().apply {
|
||||
addFirstExpressionInBlockIfNeeded(VERSION.replace(VERSION_TEMPLATE, version))
|
||||
}
|
||||
@@ -97,12 +135,12 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
}
|
||||
}
|
||||
|
||||
return oldText != groovyScript.text
|
||||
return oldText != scriptFile.text
|
||||
}
|
||||
|
||||
override fun changeCoroutineConfiguration(coroutineOption: String): PsiElement? {
|
||||
val snippet = "coroutines \"$coroutineOption\""
|
||||
val kotlinBlock = groovyScript.getBlockOrCreate("kotlin")
|
||||
val kotlinBlock = scriptFile.getBlockOrCreate("kotlin")
|
||||
kotlinBlock.getBlockOrCreate("experimental").apply {
|
||||
addOrReplaceExpression(snippet) { stmt ->
|
||||
(stmt as? GrMethodCall)?.invokedExpression?.text == "coroutines"
|
||||
@@ -113,10 +151,10 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
}
|
||||
|
||||
override fun changeLanguageVersion(version: String, forTests: Boolean): PsiElement? =
|
||||
changeKotlinTaskParameter(groovyScript, "languageVersion", version, forTests)
|
||||
changeKotlinTaskParameter(scriptFile, "languageVersion", version, forTests)
|
||||
|
||||
override fun changeApiVersion(version: String, forTests: Boolean): PsiElement? =
|
||||
changeKotlinTaskParameter(groovyScript, "apiVersion", version, forTests)
|
||||
changeKotlinTaskParameter(scriptFile, "apiVersion", version, forTests)
|
||||
|
||||
override fun addKotlinLibraryToModuleBuildScript(
|
||||
scope: DependencyScope,
|
||||
@@ -131,20 +169,20 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
libraryDescriptor.maxVersion
|
||||
)
|
||||
|
||||
groovyScript.getDependenciesBlock().apply {
|
||||
scriptFile.getDependenciesBlock().apply {
|
||||
addLastExpressionInBlockIfNeeded(dependencyString)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getKotlinStdlibVersion(): String? {
|
||||
val versionProperty = "\$kotlin_version"
|
||||
groovyScript.getBlockByName("buildScript")?.let {
|
||||
scriptFile.getBlockByName("buildScript")?.let {
|
||||
if (it.text.contains("ext.kotlin_version = ")) {
|
||||
return versionProperty
|
||||
}
|
||||
}
|
||||
|
||||
val dependencies = groovyScript.getBlockByName("dependencies")?.statements
|
||||
val dependencies = scriptFile.getBlockByName("dependencies")?.statements
|
||||
val stdlibArtifactPrefix = "org.jetbrains.kotlin:kotlin-stdlib:"
|
||||
dependencies?.forEach { dependency ->
|
||||
val dependencyText = dependency.text
|
||||
@@ -158,6 +196,35 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
return null
|
||||
}
|
||||
|
||||
private fun addPluginRepositoryExpression(expression: String) {
|
||||
scriptFile
|
||||
.getBlockOrPrepend("pluginManagement")
|
||||
.getBlockOrCreate("repositories")
|
||||
.addLastExpressionInBlockIfNeeded(expression)
|
||||
}
|
||||
|
||||
override fun addMavenCentralPluginRepository() {
|
||||
addPluginRepositoryExpression("mavenCentral()")
|
||||
}
|
||||
|
||||
override fun addPluginRepository(repository: RepositoryDescription) {
|
||||
addPluginRepositoryExpression(repository.toGroovyRepositorySnippet())
|
||||
}
|
||||
|
||||
override fun addResolutionStrategy(pluginId: String) {
|
||||
scriptFile
|
||||
.getBlockOrPrepend("pluginManagement")
|
||||
.getBlockOrCreate("resolutionStrategy")
|
||||
.getBlockOrCreate("eachPlugin")
|
||||
.addLastStatementInBlockIfNeeded(
|
||||
"""
|
||||
if (requested.id.id == "$pluginId") {
|
||||
useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${'$'}{requested.version}")
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
private fun changeKotlinTaskParameter(
|
||||
gradleFile: GroovyFile,
|
||||
parameterName: String,
|
||||
@@ -182,7 +249,10 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
return kotlinBlock.parent
|
||||
}
|
||||
|
||||
private fun getGroovyDependencySnippet(artifactName: String) = "compile \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\""
|
||||
private fun getGroovyDependencySnippet(
|
||||
artifactName: String,
|
||||
withVersion: Boolean
|
||||
) = "compile \"org.jetbrains.kotlin:$artifactName${if (withVersion) ":\$kotlin_version" else ""}\""
|
||||
|
||||
private fun getApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'"
|
||||
|
||||
@@ -195,13 +265,6 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
private fun getApplyStatement(file: GroovyFile): GrApplicationStatement? =
|
||||
file.getChildrenOfType<GrApplicationStatement>().find { it.invokedExpression.text == "apply" }
|
||||
|
||||
private fun PsiElement.getBlockByName(name: String): GrClosableBlock? {
|
||||
return getChildrenOfType<GrMethodCallExpression>()
|
||||
.filter { it.closureArguments.isNotEmpty() }
|
||||
.find { it.invokedExpression.text == name }
|
||||
?.let { it.closureArguments[0] }
|
||||
}
|
||||
|
||||
private fun GrClosableBlock.addRepository(version: String): Boolean {
|
||||
val repository = getRepositoryForVersion(version)
|
||||
val snippet = when {
|
||||
@@ -212,13 +275,6 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
return addLastExpressionInBlockIfNeeded(snippet)
|
||||
}
|
||||
|
||||
private fun GrClosableBlock.addMavenCentralIfMissing(): Boolean =
|
||||
if (!isRepositoryConfigured(text)) addLastExpressionInBlockIfNeeded(MAVEN_CENTRAL) else false
|
||||
|
||||
private fun GrStatementOwner.getRepositoriesBlock() = getBlockOrCreate("repositories")
|
||||
|
||||
private fun GrStatementOwner.getDependenciesBlock(): GrClosableBlock = getBlockOrCreate("dependencies")
|
||||
|
||||
private fun GrStatementOwner.getBuildScriptBlock() = getBlockOrCreate("buildscript") { newBlock ->
|
||||
val pluginsBlock = getBlockByName("plugins") ?: return@getBlockOrCreate false
|
||||
addBefore(newBlock, pluginsBlock.parent)
|
||||
@@ -231,21 +287,12 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
private fun GrStatementOwner.getBuildScriptDependenciesBlock(): GrClosableBlock =
|
||||
getBuildScriptBlock().getBlockOrCreate("dependencies")
|
||||
|
||||
private fun GrStatementOwner.getBlockOrCreate(
|
||||
name: String,
|
||||
customInsert: GrStatementOwner.(newBlock: PsiElement) -> Boolean = { false }
|
||||
): GrClosableBlock {
|
||||
var block = getBlockByName(name)
|
||||
if (block == null) {
|
||||
val factory = GroovyPsiElementFactory.getInstance(project)
|
||||
val newBlock = factory.createExpressionFromText("$name{\n}\n")
|
||||
if (!customInsert(newBlock)) {
|
||||
addAfter(newBlock, statements.lastOrNull() ?: firstChild)
|
||||
}
|
||||
block = getBlockByName(name)!!
|
||||
}
|
||||
return block
|
||||
}
|
||||
private fun GrClosableBlock.addMavenCentralIfMissing(): Boolean =
|
||||
if (!isRepositoryConfigured(text)) addLastExpressionInBlockIfNeeded(MAVEN_CENTRAL) else false
|
||||
|
||||
private fun GrStatementOwner.getRepositoriesBlock() = getBlockOrCreate("repositories")
|
||||
|
||||
private fun GrStatementOwner.getDependenciesBlock(): GrClosableBlock = getBlockOrCreate("dependencies")
|
||||
|
||||
private fun GrClosableBlock.addOrReplaceExpression(snippet: String, predicate: (GrStatement) -> Boolean) {
|
||||
statements.firstOrNull(predicate)?.let { stmt ->
|
||||
@@ -255,29 +302,6 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
addLastExpressionInBlockIfNeeded(snippet)
|
||||
}
|
||||
|
||||
private fun GrClosableBlock.addLastExpressionInBlockIfNeeded(expressionText: String): Boolean =
|
||||
addExpressionInBlockIfNeeded(expressionText, false)
|
||||
|
||||
private fun GrClosableBlock.addFirstExpressionInBlockIfNeeded(expressionText: String): Boolean =
|
||||
addExpressionInBlockIfNeeded(expressionText, true)
|
||||
|
||||
private fun GrClosableBlock.addExpressionInBlockIfNeeded(expressionText: String, isFirst: Boolean): Boolean {
|
||||
if (text.contains(expressionText)) return false
|
||||
val newStatement = GroovyPsiElementFactory.getInstance(project).createExpressionFromText(expressionText)
|
||||
CodeStyleManager.getInstance(project).reformat(newStatement)
|
||||
if (!isFirst && statements.isNotEmpty()) {
|
||||
val lastStatement = statements[statements.size - 1]
|
||||
if (lastStatement != null) {
|
||||
addAfter(newStatement, lastStatement)
|
||||
}
|
||||
} else {
|
||||
if (firstChild != null) {
|
||||
addAfter(newStatement, firstChild)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'"
|
||||
|
||||
private fun GrStatement.replaceWithStatementFromText(snippet: String): GrStatement {
|
||||
@@ -291,5 +315,65 @@ class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : Gradl
|
||||
private val VERSION = String.format("ext.kotlin_version = '%s'", VERSION_TEMPLATE)
|
||||
private val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin"
|
||||
private val CLASSPATH = "classpath \"$KOTLIN_GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\""
|
||||
|
||||
private fun PsiElement.getBlockByName(name: String): GrClosableBlock? {
|
||||
return getChildrenOfType<GrMethodCallExpression>()
|
||||
.filter { it.closureArguments.isNotEmpty() }
|
||||
.find { it.invokedExpression.text == name }
|
||||
?.let { it.closureArguments[0] }
|
||||
}
|
||||
|
||||
fun GrStatementOwner.getBlockOrCreate(
|
||||
name: String,
|
||||
customInsert: GrStatementOwner.(newBlock: PsiElement) -> Boolean = { false }
|
||||
): GrClosableBlock {
|
||||
var block = getBlockByName(name)
|
||||
if (block == null) {
|
||||
val factory = GroovyPsiElementFactory.getInstance(project)
|
||||
val newBlock = factory.createExpressionFromText("$name{\n}\n")
|
||||
if (!customInsert(newBlock)) {
|
||||
addAfter(newBlock, statements.lastOrNull() ?: firstChild)
|
||||
}
|
||||
block = getBlockByName(name)!!
|
||||
}
|
||||
return block
|
||||
}
|
||||
|
||||
fun GrStatementOwner.getBlockOrPrepend(name: String) = getBlockOrCreate(name) { newBlock ->
|
||||
addAfter(newBlock, null)
|
||||
true
|
||||
}
|
||||
|
||||
fun GrStatementOwner.getPluginsBlock() = getBlockOrCreate("plugins") { newBlock ->
|
||||
addAfter(newBlock, getBlockByName("buildscript"))
|
||||
true
|
||||
}
|
||||
|
||||
fun GrClosableBlock.addLastExpressionInBlockIfNeeded(expressionText: String): Boolean =
|
||||
addExpressionOrStatementInBlockIfNeeded(expressionText, false, false)
|
||||
|
||||
fun GrClosableBlock.addLastStatementInBlockIfNeeded(expressionText: String): Boolean =
|
||||
addExpressionOrStatementInBlockIfNeeded(expressionText, true, false)
|
||||
|
||||
private fun GrClosableBlock.addFirstExpressionInBlockIfNeeded(expressionText: String): Boolean =
|
||||
addExpressionOrStatementInBlockIfNeeded(expressionText, false, true)
|
||||
|
||||
private fun GrClosableBlock.addExpressionOrStatementInBlockIfNeeded(text: String, isStatement: Boolean, isFirst: Boolean): Boolean {
|
||||
if (statements.any { StringUtil.equalsIgnoreWhitespaces(it.text, text) }) return false
|
||||
val psiFactory = GroovyPsiElementFactory.getInstance(project)
|
||||
val newStatement = if (isStatement) psiFactory.createStatementFromText(text) else psiFactory.createExpressionFromText(text)
|
||||
CodeStyleManager.getInstance(project).reformat(newStatement)
|
||||
if (!isFirst && statements.isNotEmpty()) {
|
||||
val lastStatement = statements[statements.size - 1]
|
||||
if (lastStatement != null) {
|
||||
addAfter(newStatement, lastStatement)
|
||||
}
|
||||
} else {
|
||||
if (firstChild != null) {
|
||||
addAfter(newStatement, firstChild)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
+173
-47
@@ -18,24 +18,35 @@ package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator.Companion.getBuildScriptSettingsPsiFile
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.GradleHeuristicHelper.PRODUCTION_DEPENDENCY_STATEMENTS
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.util.module
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBuildScriptManipulator {
|
||||
override fun isConfigured(kotlinPluginName: String): Boolean =
|
||||
runReadAction {
|
||||
kotlinScript.containsApplyKotlinPlugin(kotlinPluginName) && kotlinScript.containsCompileStdLib()
|
||||
}
|
||||
class KotlinBuildScriptManipulator(
|
||||
override val scriptFile: KtFile,
|
||||
override val preferNewSyntax: Boolean
|
||||
) : GradleBuildScriptManipulator<KtFile> {
|
||||
override fun isConfiguredWithOldSyntax(kotlinPluginName: String) = runReadAction {
|
||||
scriptFile.containsApplyKotlinPlugin(kotlinPluginName) && scriptFile.containsCompileStdLib()
|
||||
}
|
||||
|
||||
override fun configureProjectBuildScript(version: String): Boolean {
|
||||
val originalText = kotlinScript.text
|
||||
kotlinScript.getBuildScriptBlock()?.apply {
|
||||
override fun isConfigured(kotlinPluginExpression: String): Boolean = runReadAction {
|
||||
scriptFile.containsKotlinPluginInPluginsGroup(kotlinPluginExpression) && scriptFile.containsCompileStdLib()
|
||||
}
|
||||
|
||||
override fun configureProjectBuildScript(kotlinPluginName: String, version: String): Boolean {
|
||||
if (useNewSyntax(kotlinPluginName)) return false
|
||||
|
||||
val originalText = scriptFile.text
|
||||
scriptFile.getBuildScriptBlock()?.apply {
|
||||
addDeclarationIfMissing("var $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra", true).also {
|
||||
addExpressionAfterIfMissing("$GSK_KOTLIN_VERSION_PROPERTY_NAME = \"$version\"", it)
|
||||
}
|
||||
@@ -48,50 +59,70 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
getDependenciesBlock()?.addPluginToClassPathIfMissing()
|
||||
}
|
||||
|
||||
return originalText != kotlinScript.text
|
||||
return originalText != scriptFile.text
|
||||
}
|
||||
|
||||
override fun configureModuleBuildScript(
|
||||
kotlinPluginName: String,
|
||||
kotlinPluginExpression: String,
|
||||
stdlibArtifactName: String,
|
||||
version: String,
|
||||
jvmTarget: String?
|
||||
): Boolean {
|
||||
val originalText = kotlinScript.text
|
||||
kotlinScript.apply {
|
||||
script?.blockExpression?.addDeclarationIfMissing("val $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra", true)
|
||||
getApplyBlock()?.createPluginIfMissing(kotlinPluginName)
|
||||
getDependenciesBlock()?.addCompileStdlibIfMissing(stdlibArtifactName)
|
||||
getRepositoriesBlock()?.apply {
|
||||
addRepositoryIfMissing(version)
|
||||
addMavenCentralIfMissing()
|
||||
val originalText = scriptFile.text
|
||||
val useNewSyntax = useNewSyntax(kotlinPluginName)
|
||||
scriptFile.apply {
|
||||
if (useNewSyntax) {
|
||||
createPluginInPluginsGroupIfMissing(kotlinPluginExpression, version)
|
||||
getDependenciesBlock()?.addNoVersionCompileStdlibIfMissing(stdlibArtifactName)
|
||||
getRepositoriesBlock()?.apply {
|
||||
val repository = getRepositoryForVersion(version)
|
||||
if (repository != null) {
|
||||
scriptFile.module?.getBuildScriptSettingsPsiFile()?.let {
|
||||
with(KotlinWithGradleConfigurator.getManipulator(it)) {
|
||||
addPluginRepository(repository)
|
||||
addMavenCentralPluginRepository()
|
||||
}
|
||||
}
|
||||
}
|
||||
addMavenCentralIfMissing()
|
||||
}
|
||||
} else {
|
||||
script?.blockExpression?.addDeclarationIfMissing("val $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra", true)
|
||||
getApplyBlock()?.createPluginIfMissing(kotlinPluginName)
|
||||
getDependenciesBlock()?.addCompileStdlibIfMissing(stdlibArtifactName)
|
||||
getRepositoriesBlock()?.apply {
|
||||
addRepositoryIfMissing(version)
|
||||
addMavenCentralIfMissing()
|
||||
}
|
||||
}
|
||||
|
||||
jvmTarget?.let {
|
||||
changeKotlinTaskParameter("jvmTarget", it, forTests = false)
|
||||
changeKotlinTaskParameter("jvmTarget", it, forTests = true)
|
||||
}
|
||||
}
|
||||
|
||||
return originalText != kotlinScript.text
|
||||
return originalText != scriptFile.text
|
||||
}
|
||||
|
||||
override fun changeCoroutineConfiguration(coroutineOption: String): PsiElement? =
|
||||
kotlinScript.changeCoroutineConfiguration(coroutineOption)
|
||||
scriptFile.changeCoroutineConfiguration(coroutineOption)
|
||||
|
||||
override fun changeLanguageVersion(version: String, forTests: Boolean): PsiElement? =
|
||||
kotlinScript.changeKotlinTaskParameter("languageVersion", version, forTests)
|
||||
scriptFile.changeKotlinTaskParameter("languageVersion", version, forTests)
|
||||
|
||||
override fun changeApiVersion(version: String, forTests: Boolean): PsiElement? =
|
||||
kotlinScript.changeKotlinTaskParameter("apiVersion", version, forTests)
|
||||
scriptFile.changeKotlinTaskParameter("apiVersion", version, forTests)
|
||||
|
||||
override fun addKotlinLibraryToModuleBuildScript(
|
||||
scope: DependencyScope,
|
||||
libraryDescriptor: ExternalLibraryDescriptor,
|
||||
isAndroidModule: Boolean
|
||||
) {
|
||||
val kotlinLibraryVersion = libraryDescriptor.maxVersion.takeIf { it != GSK_KOTLIN_VERSION_PROPERTY_NAME }
|
||||
kotlinScript.getDependenciesBlock()?.apply {
|
||||
val kotlinLibraryVersion = libraryDescriptor.maxVersion.let {
|
||||
if (it == GSK_KOTLIN_VERSION_PROPERTY_NAME) "\$$it" else it
|
||||
}
|
||||
scriptFile.getDependenciesBlock()?.apply {
|
||||
addExpressionIfMissing(
|
||||
getCompileDependencySnippet(
|
||||
libraryDescriptor.libraryGroupId,
|
||||
@@ -103,10 +134,46 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
}
|
||||
}
|
||||
|
||||
override fun getKotlinStdlibVersion(): String? = kotlinScript.getKotlinStdlibVersion()
|
||||
override fun getKotlinStdlibVersion(): String? = scriptFile.getKotlinStdlibVersion()
|
||||
|
||||
private fun KtBlockExpression.addCompileStdlibIfMissing(stdlibArtifactName: String): KtCallExpression? =
|
||||
findStdLibDependency() ?: addExpressionIfMissing(getCompileDependencySnippet(KOTLIN_GROUP_ID, stdlibArtifactName)) as? KtCallExpression
|
||||
findStdLibDependency()
|
||||
?: addExpressionIfMissing(
|
||||
getCompileDependencySnippet(
|
||||
KOTLIN_GROUP_ID,
|
||||
stdlibArtifactName,
|
||||
version = "\$$GSK_KOTLIN_VERSION_PROPERTY_NAME"
|
||||
)
|
||||
) as? KtCallExpression
|
||||
|
||||
private fun addPluginRepositoryExpression(expression: String) {
|
||||
scriptFile.getPluginManagementBlock()?.findOrCreateBlock("repositories")?.addExpressionIfMissing(expression)
|
||||
}
|
||||
|
||||
override fun addMavenCentralPluginRepository() {
|
||||
addPluginRepositoryExpression("mavenCentral()")
|
||||
}
|
||||
|
||||
override fun addPluginRepository(repository: RepositoryDescription) {
|
||||
addPluginRepositoryExpression(repository.toKotlinRepositorySnippet())
|
||||
}
|
||||
|
||||
override fun addResolutionStrategy(pluginId: String) {
|
||||
scriptFile
|
||||
.getPluginManagementBlock()
|
||||
?.findOrCreateBlock("resolutionStrategy")
|
||||
?.findOrCreateBlock("eachPlugin")
|
||||
?.addExpressionIfMissing(
|
||||
"""
|
||||
if (requested.id.id == "$pluginId") {
|
||||
useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:${'$'}{requested.version}")
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
private fun KtBlockExpression.addNoVersionCompileStdlibIfMissing(stdlibArtifactName: String): KtCallExpression? =
|
||||
findStdLibDependency() ?: addExpressionIfMissing("compile(${getKotlinModuleDependencySnippet(stdlibArtifactName, null)})") as? KtCallExpression
|
||||
|
||||
private fun KtFile.containsCompileStdLib(): Boolean =
|
||||
findScriptInitializer("dependencies")?.getBlock()?.findStdLibDependency() != null
|
||||
@@ -114,12 +181,39 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
private fun KtFile.containsApplyKotlinPlugin(pluginName: String): Boolean =
|
||||
findScriptInitializer("apply")?.getBlock()?.findPlugin(pluginName) != null
|
||||
|
||||
private fun KtFile.containsKotlinPluginInPluginsGroup(pluginName: String): Boolean =
|
||||
findScriptInitializer("plugins")?.getBlock()?.findPluginInPluginsGroup(pluginName) != null
|
||||
|
||||
private fun KtBlockExpression.findPlugin(pluginName: String): KtCallExpression? {
|
||||
return PsiTreeUtil.getChildrenOfType(this, KtCallExpression::class.java)?.find {
|
||||
it.calleeExpression?.text == "plugin" && it.valueArguments.firstOrNull()?.text == "\"$pluginName\""
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtBlockExpression.findPluginInPluginsGroup(pluginName: String): KtCallExpression? {
|
||||
return PsiTreeUtil.getChildrenOfAnyType(
|
||||
this,
|
||||
KtCallExpression::class.java,
|
||||
KtBinaryExpression::class.java,
|
||||
KtDotQualifiedExpression::class.java
|
||||
).mapNotNull {
|
||||
when (it) {
|
||||
is KtCallExpression -> it
|
||||
is KtBinaryExpression -> {
|
||||
if (it.operationReference.text == "version") it.left as? KtCallExpression else null
|
||||
}
|
||||
is KtDotQualifiedExpression -> {
|
||||
if ((it.selectorExpression as? KtCallExpression)?.calleeExpression?.text == "version") {
|
||||
it.receiverExpression as? KtCallExpression
|
||||
} else null
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}.find {
|
||||
"${it.calleeExpression?.text?.trim() ?: ""}(${it.valueArguments.firstOrNull()?.text ?: ""})" == pluginName
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtFile.findScriptInitializer(startsWith: String): KtScriptInitializer? =
|
||||
PsiTreeUtil.findChildrenOfType(this, KtScriptInitializer::class.java).find { it.text.startsWith(startsWith) }
|
||||
|
||||
@@ -140,7 +234,7 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
return findScriptInitializer("dependencies")?.getBlock()?.let {
|
||||
val expression = it.findStdLibDependency()?.valueArguments?.firstOrNull()?.getArgumentExpression()
|
||||
when (expression) {
|
||||
is KtCallExpression -> expression.valueArguments[1].text.trim('\"')
|
||||
is KtCallExpression -> expression.valueArguments.getOrNull(1)?.text?.trim('\"')
|
||||
is KtStringTemplateExpression -> expression.text?.trim('\"')?.substringAfterLast(":")?.removePrefix("$")
|
||||
else -> null
|
||||
}
|
||||
@@ -150,23 +244,39 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
private fun KtBlockExpression.findStdLibDependency(): KtCallExpression? {
|
||||
return PsiTreeUtil.getChildrenOfType(this, KtCallExpression::class.java)?.find {
|
||||
val calleeText = it.calleeExpression?.text
|
||||
calleeText in PRODUCTION_DEPENDENCY_STATEMENTS && (it.valueArguments.firstOrNull()?.getArgumentExpression()?.isKotlinStdLib() ?: false)
|
||||
calleeText in PRODUCTION_DEPENDENCY_STATEMENTS && (it.valueArguments.firstOrNull()?.getArgumentExpression()?.isKotlinStdLib()
|
||||
?: false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtExpression.isKotlinStdLib(): Boolean = when (this) {
|
||||
is KtCallExpression -> calleeExpression?.text == "kotlinModule" &&
|
||||
valueArguments.firstOrNull()?.getArgumentExpression()?.text?.startsWith("\"stdlib") ?: false
|
||||
is KtCallExpression -> {
|
||||
val calleeText = calleeExpression?.text
|
||||
(calleeText == "kotlinModule" || calleeText == "kotlin") &&
|
||||
valueArguments.firstOrNull()?.getArgumentExpression()?.text?.startsWith("\"stdlib") ?: false
|
||||
}
|
||||
is KtStringTemplateExpression -> text.startsWith("\"$STDLIB_ARTIFACT_PREFIX")
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun KtFile.getPluginManagementBlock(): KtBlockExpression? =
|
||||
findScriptInitializer("pluginManagement")?.getBlock() ?: addTopLevelBlock("pluginManagement", true)
|
||||
|
||||
private fun KtFile.getRepositoriesBlock(): KtBlockExpression? =
|
||||
findScriptInitializer("repositories")?.getBlock() ?: addTopLevelBlock("repositories")
|
||||
|
||||
private fun KtFile.getDependenciesBlock(): KtBlockExpression? =
|
||||
findScriptInitializer("dependencies")?.getBlock() ?: addTopLevelBlock("dependencies")
|
||||
|
||||
private fun KtFile.getPluginsBlock(): KtBlockExpression? =
|
||||
findScriptInitializer("plugins")?.getBlock() ?: addTopLevelBlock("plugins", true)
|
||||
|
||||
private fun KtFile.createPluginInPluginsGroupIfMissing(pluginName: String, version: String): KtCallExpression? =
|
||||
getPluginsBlock()?.let {
|
||||
it.findPluginInPluginsGroup(pluginName)
|
||||
?: it.addExpressionIfMissing("$pluginName version \"$version\"") as? KtCallExpression
|
||||
}
|
||||
|
||||
private fun KtFile.createApplyBlock(): KtBlockExpression? {
|
||||
val apply = psiFactory.createScriptInitializer("apply {\n}")
|
||||
val plugins = findScriptInitializer("plugins")
|
||||
@@ -212,6 +322,15 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtBlockExpression.getRepositorySnippet(version: String): String? {
|
||||
val repository = getRepositoryForVersion(version)
|
||||
return when {
|
||||
repository != null -> repository.toKotlinRepositorySnippet()
|
||||
!isRepositoryConfigured(text) -> MAVEN_CENTRAL
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtFile.getBuildScriptBlock(): KtBlockExpression? =
|
||||
findScriptInitializer("buildscript")?.getBlock() ?: addTopLevelBlock("buildscript", true)
|
||||
|
||||
@@ -222,24 +341,24 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
findBlock("dependencies") ?: addBlock("dependencies")
|
||||
|
||||
private fun KtBlockExpression.addRepositoryIfMissing(version: String): KtCallExpression? {
|
||||
val repository = getRepositoryForVersion(version)
|
||||
val snippet = when {
|
||||
repository != null -> repository.toKotlinRepositorySnippet()
|
||||
!isRepositoryConfigured(text) -> MAVEN_CENTRAL
|
||||
else -> return null
|
||||
}
|
||||
|
||||
val snippet = getRepositorySnippet(version) ?: return null
|
||||
return addExpressionIfMissing(snippet) as? KtCallExpression
|
||||
}
|
||||
|
||||
private fun KtBlockExpression.addMavenCentralIfMissing(): KtCallExpression? =
|
||||
if (!isRepositoryConfigured(text)) addExpressionIfMissing(MAVEN_CENTRAL) as? KtCallExpression else null
|
||||
|
||||
private fun KtBlockExpression.findOrCreateBlock(name: String, first: Boolean = false) = findBlock(name) ?: addBlock(name, first)
|
||||
|
||||
private fun KtBlockExpression.addPluginToClassPathIfMissing(): KtCallExpression? =
|
||||
addExpressionIfMissing(getKotlinGradlePluginClassPathSnippet()) as? KtCallExpression
|
||||
|
||||
private fun KtBlockExpression.addBlock(name: String): KtBlockExpression? {
|
||||
return add(psiFactory.createExpression("$name {\n}"))
|
||||
fun getKotlinGradlePluginClassPathSnippet(): String =
|
||||
"classpath(${getKotlinModuleDependencySnippet("gradle-plugin", "\$$GSK_KOTLIN_VERSION_PROPERTY_NAME")})"
|
||||
|
||||
private fun KtBlockExpression.addBlock(name: String, first: Boolean = false): KtBlockExpression? {
|
||||
return psiFactory.createExpression("$name {\n}")
|
||||
.let { if (first) addAfter(it, null) else add(it) }
|
||||
?.apply { addNewLinesIfNeeded() }
|
||||
?.cast<KtCallExpression>()
|
||||
?.getBlock()
|
||||
@@ -277,11 +396,11 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
|
||||
private fun KtFile.addImportIfMissing(path: String): KtImportDirective =
|
||||
importDirectives.find { it.importPath?.pathStr == path } ?: importList?.add(
|
||||
psiFactory.createImportDirective(
|
||||
ImportPath.fromString(
|
||||
path
|
||||
psiFactory.createImportDirective(
|
||||
ImportPath.fromString(
|
||||
path
|
||||
)
|
||||
)
|
||||
)
|
||||
) as KtImportDirective
|
||||
|
||||
private fun KtBlockExpression.addExpressionAfterIfMissing(text: String, after: PsiElement): KtExpression = addStatementIfMissing(text) {
|
||||
@@ -307,7 +426,7 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
text: String,
|
||||
crossinline factory: (String) -> PsiElement
|
||||
): T {
|
||||
statements.find { it.text == text }?.let {
|
||||
statements.find { StringUtil.equalsIgnoreWhitespaces(it.text, text) }?.let {
|
||||
return it as T
|
||||
}
|
||||
|
||||
@@ -324,10 +443,17 @@ class KotlinBuildScriptManipulator(private val kotlinScript: KtFile) : GradleBui
|
||||
private val STDLIB_ARTIFACT_PREFIX = "org.jetbrains.kotlin:kotlin-stdlib"
|
||||
val GSK_KOTLIN_VERSION_PROPERTY_NAME = "kotlin_version"
|
||||
|
||||
fun getKotlinGradlePluginClassPathSnippet(): String = "classpath(${getKotlinModuleDependencySnippet("gradle-plugin")})"
|
||||
fun getKotlinGradlePluginClassPathSnippet(): String =
|
||||
"classpath(${getKotlinModuleDependencySnippet("gradle-plugin", "\$$GSK_KOTLIN_VERSION_PROPERTY_NAME")})"
|
||||
|
||||
fun getKotlinModuleDependencySnippet(artifactId: String, version: String? = null): String =
|
||||
"kotlinModule(\"${artifactId.removePrefix("kotlin-")}\", ${version?.let { "\"$it\"" } ?: GSK_KOTLIN_VERSION_PROPERTY_NAME})"
|
||||
fun getKotlinModuleDependencySnippet(artifactId: String, version: String? = null): String {
|
||||
val moduleName = artifactId.removePrefix("kotlin-")
|
||||
return when (version) {
|
||||
null -> "kotlin(\"$moduleName\")"
|
||||
"\$$GSK_KOTLIN_VERSION_PROPERTY_NAME" -> "kotlinModule(\"$moduleName\", $GSK_KOTLIN_VERSION_PROPERTY_NAME)"
|
||||
else -> "kotlinModule(\"$moduleName\", ${"\"$version\""})"
|
||||
}
|
||||
}
|
||||
|
||||
fun getCompileDependencySnippet(
|
||||
groupId: String,
|
||||
|
||||
+61
-23
@@ -18,14 +18,15 @@ package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.framework.FrameworkTypeEx
|
||||
import com.intellij.framework.addSupport.FrameworkSupportInModuleProvider
|
||||
import com.intellij.ide.util.frameworkSupport.FrameworkSupportModel
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectId
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.roots.ModifiableModelsProvider
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinBuildScriptManipulator.Companion.GSK_KOTLIN_VERSION_PROPERTY_NAME
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinBuildScriptManipulator.Companion.getCompileDependencySnippet
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinBuildScriptManipulator.Companion.getKotlinGradlePluginClassPathSnippet
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinBuildScriptManipulator.Companion.getKotlinModuleDependencySnippet
|
||||
import org.jetbrains.kotlin.idea.versions.*
|
||||
import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder
|
||||
import org.jetbrains.plugins.gradle.frameworkSupport.KotlinDslGradleFrameworkSupportProvider
|
||||
@@ -42,6 +43,8 @@ abstract class KotlinDslGradleKotlinFrameworkSupportProvider(
|
||||
override fun createProvider(): FrameworkSupportInModuleProvider = this@KotlinDslGradleKotlinFrameworkSupportProvider
|
||||
}
|
||||
|
||||
override fun createConfigurable(model: FrameworkSupportModel) = KotlinGradleFrameworkSupportInModuleConfigurable(model, this)
|
||||
|
||||
override fun addSupport(
|
||||
projectId: ProjectId,
|
||||
module: Module,
|
||||
@@ -55,38 +58,59 @@ abstract class KotlinDslGradleKotlinFrameworkSupportProvider(
|
||||
kotlinVersion = LAST_SNAPSHOT_VERSION
|
||||
}
|
||||
|
||||
if (additionalRepository != null) {
|
||||
val repository = additionalRepository.toKotlinRepositorySnippet()
|
||||
buildScriptData.addBuildscriptRepositoriesDefinition(repository)
|
||||
buildScriptData.addRepositoriesDefinition("mavenCentral()")
|
||||
buildScriptData.addRepositoriesDefinition(repository)
|
||||
}
|
||||
val useNewSyntax = buildScriptData.gradleVersion >= MIN_GRADLE_VERSION_FOR_NEW_PLUGIN_SYNTAX
|
||||
if (useNewSyntax) {
|
||||
if (additionalRepository != null) {
|
||||
val repository = additionalRepository.toKotlinRepositorySnippet()
|
||||
updateSettingsScript(module) {
|
||||
with(KotlinWithGradleConfigurator.getManipulator(it)) {
|
||||
addPluginRepository(additionalRepository)
|
||||
addMavenCentralPluginRepository()
|
||||
}
|
||||
}
|
||||
buildScriptData.addRepositoriesDefinition("mavenCentral()")
|
||||
buildScriptData.addRepositoriesDefinition(repository)
|
||||
}
|
||||
|
||||
buildScriptData
|
||||
.addPropertyDefinition("val $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra")
|
||||
.addPluginDefinition(getPluginDefinition())
|
||||
.addBuildscriptRepositoriesDefinition("mavenCentral()")
|
||||
.addRepositoriesDefinition("mavenCentral()")
|
||||
// TODO: in gradle > 4.1 this could be single declaration e.g. 'val kotlin_version: String by extra { "1.1.11" }'
|
||||
.addBuildscriptPropertyDefinition("var $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra\n $GSK_KOTLIN_VERSION_PROPERTY_NAME = \"$kotlinVersion\"")
|
||||
.addDependencyNotation(getRuntimeLibrary(rootModel))
|
||||
.addBuildscriptDependencyNotation(getKotlinGradlePluginClassPathSnippet())
|
||||
buildScriptData
|
||||
.addPluginDefinitionInPluginsGroup(getPluginDefinition() + " version \"$kotlinVersion\"")
|
||||
.addDependencyNotation(getRuntimeLibrary(rootModel, null))
|
||||
} else {
|
||||
if (additionalRepository != null) {
|
||||
val repository = additionalRepository.toKotlinRepositorySnippet()
|
||||
buildScriptData.addBuildscriptRepositoriesDefinition(repository)
|
||||
buildScriptData.addRepositoriesDefinition("mavenCentral()")
|
||||
buildScriptData.addRepositoriesDefinition(repository)
|
||||
}
|
||||
|
||||
buildScriptData
|
||||
.addPropertyDefinition("val $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra")
|
||||
.addPluginDefinition(getOldSyntaxPluginDefinition())
|
||||
.addBuildscriptRepositoriesDefinition("mavenCentral()")
|
||||
.addRepositoriesDefinition("mavenCentral()")
|
||||
// TODO: in gradle > 4.1 this could be single declaration e.g. 'val kotlin_version: String by extra { "1.1.11" }'
|
||||
.addBuildscriptPropertyDefinition("var $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra\n $GSK_KOTLIN_VERSION_PROPERTY_NAME = \"$kotlinVersion\"")
|
||||
.addDependencyNotation(getRuntimeLibrary(rootModel, "\$$GSK_KOTLIN_VERSION_PROPERTY_NAME"))
|
||||
.addBuildscriptDependencyNotation(getKotlinGradlePluginClassPathSnippet())
|
||||
}
|
||||
}
|
||||
|
||||
private fun RepositoryDescription.toKotlinRepositorySnippet() = "maven { setUrl(\"$url\") }"
|
||||
|
||||
protected abstract fun getRuntimeLibrary(rootModel: ModifiableRootModel): String
|
||||
protected abstract fun getRuntimeLibrary(rootModel: ModifiableRootModel, version: String?): String
|
||||
|
||||
protected abstract fun getOldSyntaxPluginDefinition(): String
|
||||
protected abstract fun getPluginDefinition(): String
|
||||
}
|
||||
|
||||
class KotlinDslGradleKotlinJavaFrameworkSupportProvider :
|
||||
KotlinDslGradleKotlinFrameworkSupportProvider("KOTLIN", "Kotlin (Java)", KotlinIcons.SMALL_LOGO) {
|
||||
|
||||
override fun getPluginDefinition() = "plugin(\"${KotlinGradleModuleConfigurator.KOTLIN}\")"
|
||||
override fun getOldSyntaxPluginDefinition() = "plugin(\"${KotlinGradleModuleConfigurator.KOTLIN}\")"
|
||||
override fun getPluginDefinition() = "kotlin(\"jvm\")"
|
||||
|
||||
override fun getRuntimeLibrary(rootModel: ModifiableRootModel) =
|
||||
getCompileDependencySnippet(KOTLIN_GROUP_ID, getStdlibArtifactId(rootModel.sdk, bundledRuntimeVersion()))
|
||||
override fun getRuntimeLibrary(rootModel: ModifiableRootModel, version: String?) =
|
||||
"compile(${getKotlinModuleDependencySnippet(getStdlibArtifactId(rootModel.sdk, bundledRuntimeVersion()), version)})"
|
||||
|
||||
override fun addSupport(
|
||||
projectId: ProjectId,
|
||||
@@ -108,8 +132,22 @@ class KotlinDslGradleKotlinJavaFrameworkSupportProvider :
|
||||
class KotlinDslGradleKotlinJSFrameworkSupportProvider :
|
||||
KotlinDslGradleKotlinFrameworkSupportProvider("KOTLIN_JS", "Kotlin (JavaScript)", KotlinIcons.JS) {
|
||||
|
||||
override fun getPluginDefinition(): String = "plugin(\"${KotlinJsGradleModuleConfigurator.KOTLIN_JS}\")"
|
||||
override fun getOldSyntaxPluginDefinition(): String = "plugin(\"${KotlinJsGradleModuleConfigurator.KOTLIN_JS}\")"
|
||||
override fun getPluginDefinition(): String = "id(\"kotlin2js\")"
|
||||
|
||||
override fun getRuntimeLibrary(rootModel: ModifiableRootModel) =
|
||||
getCompileDependencySnippet(KOTLIN_GROUP_ID, MAVEN_JS_STDLIB_ID.removePrefix("kotlin-"))
|
||||
override fun getRuntimeLibrary(rootModel: ModifiableRootModel, version: String?) =
|
||||
"compile(${getKotlinModuleDependencySnippet(MAVEN_JS_STDLIB_ID.removePrefix("kotlin-"), version)})"
|
||||
|
||||
override fun addSupport(
|
||||
projectId: ProjectId,
|
||||
module: Module,
|
||||
rootModel: ModifiableRootModel,
|
||||
modifiableModelsProvider: ModifiableModelsProvider,
|
||||
buildScriptData: BuildScriptDataBuilder
|
||||
) {
|
||||
super.addSupport(projectId, module, rootModel, modifiableModelsProvider, buildScriptData)
|
||||
updateSettingsScript(module) {
|
||||
KotlinWithGradleConfigurator.getManipulator(it).addResolutionStrategy("kotlin2js")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -37,6 +37,9 @@ class KotlinGradleModuleConfigurator : KotlinWithGradleConfigurator() {
|
||||
override val kotlinPluginName: String
|
||||
get() = KOTLIN
|
||||
|
||||
override fun getKotlinPluginExpression(forKotlinDsl: Boolean): String =
|
||||
if (forKotlinDsl) "kotlin(\"jvm\")" else "id 'org.jetbrains.kotlin.jvm'"
|
||||
|
||||
override fun getJvmTarget(sdk: Sdk?, version: String) = getDefaultJvmTarget(sdk, version)?.description
|
||||
|
||||
override fun configureModule(
|
||||
|
||||
+18
-16
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.configuration
|
||||
import com.intellij.ide.util.projectWizard.ModuleWizardStep
|
||||
import com.intellij.ide.util.projectWizard.WizardContext
|
||||
import com.intellij.openapi.externalSystem.service.project.wizard.ExternalModuleSettingsStep
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.ModifiableRootModel
|
||||
@@ -27,11 +26,11 @@ import com.intellij.openapi.roots.ui.configuration.ModulesProvider
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.idea.util.rootManager
|
||||
import org.jetbrains.plugins.gradle.frameworkSupport.BuildScriptDataBuilder
|
||||
import org.jetbrains.plugins.gradle.service.project.wizard.GradleModuleBuilder
|
||||
import org.jetbrains.plugins.gradle.service.settings.GradleProjectSettingsControl
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory
|
||||
import javax.swing.Icon
|
||||
|
||||
class KotlinGradleMultiplatformModuleBuilder : GradleModuleBuilder() {
|
||||
@@ -65,28 +64,31 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupModule(module: Module) {
|
||||
super.setupModule(module)
|
||||
try {
|
||||
module.gradleModuleBuilder = this
|
||||
|
||||
val contentRoot = module.rootManager.contentRoots.firstOrNull() ?: return
|
||||
setupCommonModule(module, contentRoot)
|
||||
setupPlatformModule(module, contentRoot, jvmModuleName, GradleKotlinMPPJavaFrameworkSupportProvider(), jdk)
|
||||
setupPlatformModule(module, contentRoot, jsModuleName, GradleKotlinMPPJSFrameworkSupportProvider())
|
||||
super.setupModule(module)
|
||||
|
||||
val settingsGradle = contentRoot.findChild("settings.gradle")
|
||||
settingsGradle?.let {
|
||||
module.project.executeCommand("Update settings.gradle") {
|
||||
val doc = FileDocumentManager.getInstance().getDocument(it) ?: return@executeCommand
|
||||
val contentRoot = module.rootManager.contentRoots.firstOrNull() ?: return
|
||||
setupCommonModule(module, contentRoot)
|
||||
setupPlatformModule(module, contentRoot, jvmModuleName, GradleKotlinMPPJavaFrameworkSupportProvider(), jdk)
|
||||
setupPlatformModule(module, contentRoot, jsModuleName, GradleKotlinMPPJSFrameworkSupportProvider())
|
||||
|
||||
updateSettingsScript(module) {
|
||||
val includedModules = listOfNotNull(commonModuleName, jvmModuleName, jsModuleName).filter { it.isNotEmpty() }
|
||||
if (includedModules.isNotEmpty()) {
|
||||
doc.insertString(doc.textLength, includedModules.joinToString(prefix = "include ") { "'$it'" })
|
||||
val includeCall = GroovyPsiElementFactory.getInstance(module.project)
|
||||
.createExpressionFromText(includedModules.joinToString(prefix = "include ") { "'$it'" })
|
||||
it.add(includeCall)
|
||||
}
|
||||
FileDocumentManager.getInstance().saveDocument(doc)
|
||||
}
|
||||
} finally {
|
||||
flushSettingsGradleCopy(module)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +112,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 +122,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, !commonModuleName.isNullOrEmpty())
|
||||
val dependency = commonModuleName ?: ""
|
||||
builder.addDependencyNotation("expectedBy project(\":$dependency\")")
|
||||
}
|
||||
|
||||
+19
@@ -17,6 +17,8 @@
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.util.module
|
||||
import org.jetbrains.kotlin.idea.versions.MAVEN_JS_STDLIB_ID
|
||||
import org.jetbrains.kotlin.js.resolve.JsPlatform
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
@@ -26,9 +28,26 @@ class KotlinJsGradleModuleConfigurator : KotlinWithGradleConfigurator() {
|
||||
override val presentableText: String = "JavaScript with Gradle"
|
||||
override val targetPlatform: TargetPlatform = JsPlatform
|
||||
override val kotlinPluginName: String = KOTLIN_JS
|
||||
override fun getKotlinPluginExpression(forKotlinDsl: Boolean): String =
|
||||
if (forKotlinDsl) "id(\"kotlin2js\")" else "id 'kotlin2js'"
|
||||
override fun getMinimumSupportedVersion() = "1.1.0"
|
||||
override fun getStdlibArtifactName(sdk: Sdk?, version: String): String = MAVEN_JS_STDLIB_ID
|
||||
|
||||
override fun addElementsToFile(file: PsiFile, isTopLevelProjectFile: Boolean, version: String): Boolean {
|
||||
if (getManipulator(file).useNewSyntax(kotlinPluginName)) {
|
||||
val settingsPsiFile = if (isTopLevelProjectFile) {
|
||||
file.module?.getTopLevelBuildScriptSettingsPsiFile()
|
||||
} else {
|
||||
file.module?.getBuildScriptSettingsPsiFile()
|
||||
}
|
||||
if (settingsPsiFile != null) {
|
||||
getManipulator(settingsPsiFile).addResolutionStrategy("kotlin2js")
|
||||
}
|
||||
}
|
||||
|
||||
return super.addElementsToFile(file, isTopLevelProjectFile, version)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val KOTLIN_JS = "kotlin2js"
|
||||
}
|
||||
|
||||
+50
-24
@@ -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<Module>) {
|
||||
@@ -146,10 +151,11 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
|
||||
val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk }
|
||||
val jvmTarget = getJvmTarget(sdk, version)
|
||||
return getManipulator(file).configureModuleBuildScript(
|
||||
kotlinPluginName,
|
||||
getStdlibArtifactName(sdk, version),
|
||||
version,
|
||||
jvmTarget
|
||||
kotlinPluginName,
|
||||
getKotlinPluginExpression(file.isKtDsl()),
|
||||
getStdlibArtifactName(sdk, version),
|
||||
version,
|
||||
jvmTarget
|
||||
)
|
||||
}
|
||||
|
||||
@@ -158,6 +164,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,
|
||||
@@ -165,7 +172,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
|
||||
}
|
||||
@@ -251,21 +258,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'"
|
||||
|
||||
@@ -320,28 +326,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
|
||||
}
|
||||
}
|
||||
@@ -349,9 +364,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)
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.externalSystem.model.project.ProjectId
|
||||
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() = supportProvider.createComponent()
|
||||
|
||||
override fun addSupport(
|
||||
module: Module,
|
||||
rootModel: ModifiableRootModel,
|
||||
modifiableModelsProvider: ModifiableModelsProvider
|
||||
) {
|
||||
val buildScriptData = GradleModuleBuilder.getBuildScriptData(module)
|
||||
if (buildScriptData != null) {
|
||||
val builder = model.moduleBuilder
|
||||
val projectId = (builder as? GradleModuleBuilder)?.projectId ?: ProjectId(null, module.name, null)
|
||||
try {
|
||||
module.gradleModuleBuilder = builder as? GradleModuleBuilder
|
||||
supportProvider.addSupport(projectId, module, rootModel, modifiableModelsProvider, buildScriptData)
|
||||
} finally {
|
||||
flushSettingsGradleCopy(module)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+688
-82
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user