Refactor Kotlin Gradle configurator

This commit is contained in:
Vyacheslav Gerasimov
2017-06-14 17:19:24 +03:00
parent 9810c10f8b
commit 7c6ffff198
10 changed files with 1260 additions and 970 deletions
@@ -17,17 +17,18 @@
package org.jetbrains.kotlin.android.configure package org.jetbrains.kotlin.android.configure
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtil
import com.intellij.openapi.projectRoots.JavaSdk import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.JavaSdkVersion import com.intellij.openapi.projectRoots.JavaSdkVersion
import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.idea.KotlinPluginUtil import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator
import org.jetbrains.kotlin.idea.versions.* import org.jetbrains.kotlin.idea.versions.MAVEN_STDLIB_ID_JRE7
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.idea.versions.hasJreSpecificRuntime
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
class KotlinAndroidGradleModuleConfigurator internal constructor() : KotlinWithGradleConfigurator() { class KotlinAndroidGradleModuleConfigurator internal constructor() : KotlinWithGradleConfigurator() {
@@ -42,25 +43,21 @@ class KotlinAndroidGradleModuleConfigurator internal constructor() : KotlinWithG
override val kotlinPluginName: String = KOTLIN_ANDROID override val kotlinPluginName: String = KOTLIN_ANDROID
override fun addElementsToFile(file: PsiFile, isTopLevelProjectFile: Boolean, version: String): Boolean { override fun addElementsToFile(file: PsiFile, isTopLevelProjectFile: Boolean, version: String): Boolean {
if (file is GroovyFile) { val manipulator = getManipulator(file)
if (isTopLevelProjectFile) { val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk }
return addElementsToProjectGroovyFile(file, version) val jvmTarget = getJvmTarget(sdk, version)
}
else {
return addElementsToModuleGroovyFile(file, version)
}
}
if (file is KtFile) { return if (isTopLevelProjectFile) {
if (isTopLevelProjectFile) { manipulator.configureProjectBuildScript(version)
return addElementsToProjectGSKFile(file, version) }
} else {
else { manipulator.configureModuleBuildScript(
return addElementsToModuleGSKFile(file, version) kotlinPluginName,
} getStdlibArtifactName(sdk, version),
version,
jvmTarget
)
} }
return false
} }
override fun getStdlibArtifactName(sdk: Sdk?, version: String): String { override fun getStdlibArtifactName(sdk: Sdk?, version: String): String {
@@ -23,6 +23,7 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.util.Computable import com.intellij.openapi.util.Computable
import com.intellij.psi.search.FileTypeIndex import com.intellij.psi.search.FileTypeIndex
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
@@ -65,6 +66,24 @@ val EAP_12_REPOSITORY = RepositoryDescription(
"https://bintray.com/kotlin/kotlin-eap-1.2/kotlin/", "https://bintray.com/kotlin/kotlin-eap-1.2/kotlin/",
isSnapshot = false) isSnapshot = false)
val MAVEN_CENTRAL = "mavenCentral()"
val JCENTER = "jcenter()"
val KOTLIN_GROUP_ID = "org.jetbrains.kotlin"
fun isRepositoryConfigured(repositoriesBlockText: String): Boolean =
repositoriesBlockText.contains(MAVEN_CENTRAL) || repositoriesBlockText.contains(JCENTER)
fun DependencyScope.toGradleCompileScope(isAndroidModule: Boolean) = when (this) {
DependencyScope.COMPILE -> "compile"
// TODO: We should add testCompile or androidTestCompile
DependencyScope.TEST -> if (isAndroidModule) "compile" else "testCompile"
DependencyScope.RUNTIME -> "runtime"
DependencyScope.PROVIDED -> "compile"
else -> "compile"
}
fun RepositoryDescription.toGroovyRepositorySnippet() = "maven {\nurl '$url'\n}" fun RepositoryDescription.toGroovyRepositorySnippet() = "maven {\nurl '$url'\n}"
fun RepositoryDescription.toKotlinRepositorySnippet() = "maven {\nsetUrl(\"$url\")\n}" fun RepositoryDescription.toKotlinRepositorySnippet() = "maven {\nsetUrl(\"$url\")\n}"
@@ -240,4 +259,4 @@ fun isEap(version: String): Boolean {
fun useEapRepository(minorKotlinVersion: Int, version: String): Boolean { fun useEapRepository(minorKotlinVersion: Int, version: String): Boolean {
return Regex("1\\.$minorKotlinVersion(\\.\\d)?-[A-Za-z][A-Za-z0-9-]*").matches(version) && return Regex("1\\.$minorKotlinVersion(\\.\\d)?-[A-Za-z][A-Za-z0-9-]*").matches(version) &&
!version.startsWith("1.$minorKotlinVersion.0-dev") !version.startsWith("1.$minorKotlinVersion.0-dev")
} }
@@ -1,251 +0,0 @@
/*
* 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.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
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
fun getGSKCompileDependencySnippet(groupId: String, artifactId: String, compileScope: String = "compile", version: String? = null): String =
if (groupId == KOTLIN_GROUP_ID)
"$compileScope(${getKotlinModuleDependencySnippet(artifactId, version)})"
else
"$compileScope(\"$groupId:$artifactId:$version\")"
fun getKotlinModuleDependencySnippet(artifactId: String, version: String? = null): String =
"kotlinModule(\"${artifactId.removePrefix("kotlin-")}\", ${version?.let { "\"$it\"" } ?: GSK_KOTLIN_VERSION_PROPERTY_NAME})"
fun KtFile.containsCompileStdLib(): Boolean =
findScriptInitializer("dependencies")?.getBlock()?.findCompileStdLib() != null
fun KtFile.containsApplyKotlinPlugin(pluginName: String): Boolean =
findScriptInitializer("apply")?.getBlock()?.findPlugin(pluginName) != null
fun KtFile.getKotlinStdlibVersion(): String? {
return findScriptInitializer("dependencies")?.getBlock()?.let {
val expression = it.findCompileStdLib()?.valueArguments?.firstOrNull()?.getArgumentExpression()
when (expression) {
is KtCallExpression -> expression.valueArguments[1].text.trim('\"')
is KtStringTemplateExpression -> expression.text?.trim('\"')?.substringAfterLast(":")?.removePrefix("$")
else -> null
}
}
}
fun KtBlockExpression.findCompileStdLib(): KtCallExpression? {
return PsiTreeUtil.getChildrenOfType(this, KtCallExpression::class.java)?.find {
it.calleeExpression?.text == "compile" && (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 KtStringTemplateExpression -> text.startsWith("\"$STDLIB_ARTIFACT_PREFIX")
else -> false
}
fun KtFile.getRepositoriesBlock(): KtBlockExpression? =
findScriptInitializer("repositories")?.getBlock() ?: addTopLevelBlock("repositories")
fun KtFile.getDependenciesBlock(): KtBlockExpression? =
findScriptInitializer("dependencies")?.getBlock() ?: addTopLevelBlock("dependencies")
fun KtFile.createApplyBlock(): KtBlockExpression? {
val apply = psiFactory.createScriptInitializer("apply {\n}")
val plugins = findScriptInitializer("plugins")
val addedElement = plugins?.addSibling(apply) ?: addToScriptBlock(apply)
addedElement?.addNewLinesIfNeeded()
return (addedElement as? KtScriptInitializer)?.getBlock()
}
fun KtFile.getApplyBlock(): KtBlockExpression? = findScriptInitializer("apply")?.getBlock() ?: createApplyBlock()
private fun KtBlockExpression.findPlugin(pluginName: String): KtCallExpression? {
return PsiTreeUtil.getChildrenOfType(this, KtCallExpression::class.java)?.find {
it.calleeExpression?.text == "plugin" && it.valueArguments.firstOrNull()?.text == "\"$pluginName\""
}
}
fun KtBlockExpression.createPluginIfMissing(pluginName: String): KtCallExpression? =
findPlugin(pluginName) ?: addExpressionIfMissing("plugin(\"$pluginName\")") as? KtCallExpression
fun changeCoroutineConfiguration(buildScriptFile: KtFile, coroutineOption: String): PsiElement? {
val snippet = "experimental.coroutines = Coroutines.${coroutineOption.toUpperCase()}"
val kotlinBlock = buildScriptFile.findScriptInitializer("kotlin")?.getBlock() ?:
buildScriptFile.addTopLevelBlock("kotlin") ?: return null
buildScriptFile.addImportIfMissing("org.jetbrains.kotlin.gradle.dsl.Coroutines")
val statement = kotlinBlock.statements.find { it.text.startsWith("experimental.coroutines") }
return if (statement != null) {
statement.replace(buildScriptFile.psiFactory.createExpression(snippet))
}
else {
kotlinBlock.add(buildScriptFile.psiFactory.createExpression(snippet)).apply { addNewLinesIfNeeded() }
}
}
fun KtFile.changeKotlinTaskParameter(parameterName: String, parameterValue: String, forTests: Boolean): PsiElement? {
val snippet = "$parameterName = \"$parameterValue\""
val taskName = if (forTests) "compileTestKotlin" else "compileKotlin"
val optionsBlock = findScriptInitializer("$taskName.kotlinOptions")?.getBlock()
return if (optionsBlock != null) {
val assignment = optionsBlock.statements.find {
(it as? KtBinaryExpression)?.left?.text == parameterName
}
if (assignment != null) {
assignment.replace(psiFactory.createExpression(snippet))
}
else {
optionsBlock.addExpressionIfMissing(snippet)
}
}
else {
addImportIfMissing("org.jetbrains.kotlin.gradle.tasks.KotlinCompile")
script?.blockExpression?.addDeclarationIfMissing("val $taskName: KotlinCompile by tasks")
addTopLevelBlock("$taskName.kotlinOptions")?.addExpressionIfMissing(snippet)
}
}
fun KtFile.getBuildScriptBlock(): KtBlockExpression? =
findScriptInitializer("buildscript")?.getBlock() ?: addTopLevelBlock("buildscript", true)
fun KtBlockExpression.getRepositoriesBlock(): KtBlockExpression? =
findBlock("repositories") ?: addBlock("repositories")
fun KtBlockExpression.getDependenciesBlock(): KtBlockExpression? =
findBlock("dependencies") ?: addBlock("dependencies")
fun KtBlockExpression.addRepositoryIfMissing(version: String): KtCallExpression? {
val repository = getRepositoryForVersion(version)
val snippet = when {
repository != null -> repository.toKotlinRepositorySnippet()
!isRepositoryConfigured() -> MAVEN_CENTRAL
else -> return null
}
return addExpressionIfMissing(snippet) as? KtCallExpression
}
private fun KtBlockExpression.isRepositoryConfigured(): Boolean {
return text.contains(MAVEN_CENTRAL) || text.contains(JCENTER)
}
fun KtBlockExpression.addPluginToClassPathIfMissing(): KtCallExpression? =
addExpressionIfMissing("classpath(${getKotlinModuleDependencySnippet("gradle-plugin")})") as? KtCallExpression
private fun KtFile.findScriptInitializer(startsWith: String): KtScriptInitializer? =
PsiTreeUtil.findChildrenOfType(this, KtScriptInitializer::class.java).find { it.text.startsWith(startsWith) }
private fun KtBlockExpression.findBlock(name: String): KtBlockExpression? {
return getChildrenOfType<KtCallExpression>().find {
it.calleeExpression?.text == name &&
it.valueArguments.singleOrNull()?.getArgumentExpression() is KtLambdaExpression
}?.getBlock()
}
private fun KtScriptInitializer.getBlock(): KtBlockExpression? =
PsiTreeUtil.findChildOfType<KtCallExpression>(this, KtCallExpression::class.java)?.getBlock()
private fun KtCallExpression.getBlock(): KtBlockExpression? =
(valueArguments.singleOrNull()?.getArgumentExpression() as? KtLambdaExpression)?.bodyExpression
private fun KtBlockExpression.addBlock(name: String): KtBlockExpression? {
return add(psiFactory.createExpression("$name {\n}"))
?.apply { addNewLinesIfNeeded() }
?.cast<KtCallExpression>()
?.getBlock()
}
private fun KtFile.addTopLevelBlock(name: String, first: Boolean = false): KtBlockExpression? {
val scriptInitializer = psiFactory.createScriptInitializer("$name {\n}")
val addedElement = addToScriptBlock(scriptInitializer, first) as? KtScriptInitializer
addedElement?.addNewLinesIfNeeded()
return addedElement?.getBlock()
}
private fun PsiElement.addSibling(element: PsiElement): PsiElement = parent.addAfter(element, this)
private fun PsiElement.addNewLineBefore(lineBreaks: Int = 1) {
parent.addBefore(psiFactory.createNewLine(lineBreaks), this)
}
private fun PsiElement.addNewLineAfter(lineBreaks: Int = 1) {
parent.addAfter(psiFactory.createNewLine(lineBreaks), this)
}
private fun PsiElement.addNewLinesIfNeeded(lineBreaks: Int = 1) {
if (prevSibling != null && prevSibling.text.isNotBlank()) {
addNewLineBefore(lineBreaks)
}
if (nextSibling != null && nextSibling.text.isNotBlank()) {
addNewLineAfter(lineBreaks)
}
}
private fun KtFile.addToScriptBlock(element: PsiElement, first: Boolean = false): PsiElement? =
if (first) script?.blockExpression?.addAfter(element, null) else script?.blockExpression?.add(element)
private fun KtFile.addImportIfMissing(path: String): KtImportDirective =
importDirectives.find { it.importPath?.pathStr == path } ?:
importList?.add(psiFactory.createImportDirective(ImportPath.fromString(path))) as KtImportDirective
fun KtBlockExpression.addExpressionAfterIfMissing(text: String, after: PsiElement): KtExpression = addStatementIfMissing(text) {
psiFactory.createExpression(it).let { created ->
addAfter(created, after)
}
}
fun KtBlockExpression.addExpressionIfMissing(text: String, first: Boolean = false): KtExpression = addStatementIfMissing(text) {
psiFactory.createExpression(it).let { created ->
if(first) addAfter(created, null) else add(created)
}
}
fun KtBlockExpression.addDeclarationIfMissing(text: String, first: Boolean = false): KtDeclaration = addStatementIfMissing(text) {
psiFactory.createDeclaration<KtDeclaration>(it).let { created ->
if(first) addAfter(created, null) else add(created)
}
}
private inline fun <reified T: PsiElement> KtBlockExpression.addStatementIfMissing(
text: String,
crossinline factory: (String) -> PsiElement): T {
statements.find { it.text == text }?.let {
return it as T
}
return factory(text).apply { addNewLinesIfNeeded() } as T
}
private fun KtPsiFactory.createScriptInitializer(text: String): KtScriptInitializer =
createFile("dummy.kts", text).script?.blockExpression?.firstChild as KtScriptInitializer
private val PsiElement.psiFactory: KtPsiFactory
get() = KtPsiFactory(this)
private val MAVEN_CENTRAL = "mavenCentral()"
private val JCENTER = "jcenter()"
private val STDLIB_ARTIFACT_PREFIX = "org.jetbrains.kotlin:kotlin-stdlib"
val KOTLIN_GROUP_ID = "org.jetbrains.kotlin"
val GSK_KOTLIN_VERSION_PROPERTY_NAME = "kotlin_version"
@@ -0,0 +1,45 @@
/*
* 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
interface GradleBuildScriptManipulator {
fun isConfigured(kotlinPluginName: String): Boolean
fun configureModuleBuildScript(kotlinPluginName: String,
stdlibArtifactName: String,
version: String,
jvmTarget: String?): Boolean
fun configureProjectBuildScript(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?
}
@@ -0,0 +1,282 @@
/*
* 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.codeStyle.CodeStyleManager
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
class GroovyBuildScriptManipulator(private val groovyScript: GroovyFile) : GradleBuildScriptManipulator {
override fun isConfigured(kotlinPluginName: String): Boolean {
val fileText = groovyScript.text
return containsDirective(fileText, getApplyPluginDirective(kotlinPluginName)) &&
fileText.contains("org.jetbrains.kotlin") &&
fileText.contains("kotlin-stdlib")
}
override fun configureModuleBuildScript(
kotlinPluginName: 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 buildScriptBlock = groovyScript.getBlockByName("buildscript")
if (buildScriptBlock != null) {
groovyScript.addAfter(apply, buildScriptBlock.parent)
}
else {
groovyScript.addAfter(apply, groovyScript.statements.lastOrNull() ?: groovyScript.firstChild)
}
}
}
groovyScript.getRepositoriesBlock().apply {
addRepository(version)
}
groovyScript.getDependenciesBlock().apply {
addExpressionInBlockIfNeeded(getGroovyDependencySnippet(stdlibArtifactName), false)
}
if (jvmTarget != null) {
changeKotlinTaskParameter(groovyScript, "jvmTarget", jvmTarget, forTests = false)
changeKotlinTaskParameter(groovyScript, "jvmTarget", jvmTarget, forTests = true)
}
return groovyScript.text != oldText
}
override fun configureProjectBuildScript(version: String): Boolean {
val oldText = groovyScript.text
groovyScript.apply {
getBuildScriptBlock().apply {
addFirstExpressionInBlockIfNeeded(VERSION.replace(VERSION_TEMPLATE, version))
}
getBuildScriptRepositoriesBlock().apply {
addRepository(version)
}
getBuildScriptDependenciesBlock().apply {
addLastExpressionInBlockIfNeeded(CLASSPATH)
}
}
return oldText != groovyScript.text
}
override fun changeCoroutineConfiguration(coroutineOption: String): PsiElement? {
val snippet = "coroutines \"$coroutineOption\""
val kotlinBlock = groovyScript.getBlockOrCreate("kotlin")
kotlinBlock.getBlockOrCreate("experimental").apply {
addOrReplaceExpression(snippet) { stmt ->
(stmt as? GrMethodCall)?.invokedExpression?.text == "coroutines"
}
}
return kotlinBlock.parent
}
override fun changeLanguageVersion(version: String, forTests: Boolean): PsiElement? =
changeKotlinTaskParameter(groovyScript, "languageVersion", version, forTests)
override fun changeApiVersion(version: String, forTests: Boolean): PsiElement? =
changeKotlinTaskParameter(groovyScript, "apiVersion", version, forTests)
override fun addKotlinLibraryToModuleBuildScript(
scope: DependencyScope,
libraryDescriptor: ExternalLibraryDescriptor,
isAndroidModule: Boolean
) {
val dependencyString = String.format(
"%s \"%s:%s:%s\"",
scope.toGradleCompileScope(isAndroidModule),
libraryDescriptor.libraryGroupId,
libraryDescriptor.libraryArtifactId,
libraryDescriptor.maxVersion)
groovyScript.getDependenciesBlock().apply {
addLastExpressionInBlockIfNeeded(dependencyString)
}
}
override fun getKotlinStdlibVersion(): String? {
val versionProperty = "\$kotlin_version"
groovyScript.getBlockByName("buildScript")?.let {
if (it.text.contains("ext.kotlin_version = ")) {
return versionProperty
}
}
val dependencies = groovyScript.getBlockByName("dependencies")?.statements
val stdlibArtifactPrefix = "org.jetbrains.kotlin:kotlin-stdlib:"
dependencies?.forEach { dependency ->
val dependencyText = dependency.text
val startIndex = dependencyText.indexOf(stdlibArtifactPrefix) + stdlibArtifactPrefix.length
val endIndex = dependencyText.length - 1
if (startIndex != -1 && endIndex != -1) {
return dependencyText.substring(startIndex, endIndex)
}
}
return null
}
private fun changeKotlinTaskParameter(
gradleFile: GroovyFile,
parameterName: String,
parameterValue: String,
forTests: Boolean
): PsiElement? {
val snippet = "$parameterName = \"$parameterValue\""
val kotlinBlock = gradleFile.getBlockOrCreate(if (forTests) "compileTestKotlin" else "compileKotlin")
for (stmt in kotlinBlock.statements) {
if ((stmt as? GrAssignmentExpression)?.lValue?.text == "kotlinOptions." + parameterName) {
return stmt.replaceWithStatementFromText("kotlinOptions." + snippet)
}
}
kotlinBlock.getBlockOrCreate("kotlinOptions").apply {
addOrReplaceExpression(snippet) { stmt ->
(stmt as? GrAssignmentExpression)?.lValue?.text == parameterName
}
}
return kotlinBlock.parent
}
private fun getGroovyDependencySnippet(artifactName: String) = "compile \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\""
private fun getApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'"
private fun containsDirective(fileText: String, directive: String): Boolean {
return fileText.contains(directive)
|| fileText.contains(directive.replace("\"", "'"))
|| fileText.contains(directive.replace("'", "\""))
}
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 {
repository != null -> repository.toGroovyRepositorySnippet()
!isRepositoryConfigured(text) -> "$MAVEN_CENTRAL\n"
else -> return false
}
return addLastExpressionInBlockIfNeeded(snippet)
}
private fun GrStatementOwner.getRepositoriesBlock() = getBlockOrCreate("repositories")
private fun GrStatementOwner.getDependenciesBlock(): GrClosableBlock = getBlockOrCreate("dependencies")
private fun GrStatementOwner.getBuildScriptBlock() = getBlockOrCreate("buildscript")
private fun GrStatementOwner.getBuildScriptRepositoriesBlock(): GrClosableBlock =
getBuildScriptBlock().getBlockOrCreate("repositories")
private fun GrStatementOwner.getBuildScriptDependenciesBlock(): GrClosableBlock =
getBuildScriptBlock().getBlockOrCreate("dependencies")
private fun GrStatementOwner.getBlockOrCreate(name: String): GrClosableBlock {
var block = getBlockByName(name)
if (block == null) {
val factory = GroovyPsiElementFactory.getInstance(project)
val newBlock = factory.createExpressionFromText("$name{\n}\n")
addAfter(newBlock, statements.lastOrNull() ?: firstChild)
block = getBlockByName(name)!!
}
return block
}
private fun GrClosableBlock.addOrReplaceExpression(snippet: String, predicate: (GrStatement) -> Boolean) {
statements.firstOrNull(predicate)?.let { stmt ->
stmt.replaceWithStatementFromText(snippet)
return
}
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 {
val newStatement = GroovyPsiElementFactory.getInstance(project).createExpressionFromText(snippet)
CodeStyleManager.getInstance(project).reformat(newStatement)
return replaceWithStatement(newStatement)
}
companion object {
private val VERSION_TEMPLATE = "\$VERSION$"
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\""
}
}
@@ -0,0 +1,315 @@
/*
* 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.util.PsiTreeUtil
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 =
kotlinScript.containsApplyKotlinPlugin(kotlinPluginName) && kotlinScript.containsCompileStdLib()
override fun configureProjectBuildScript(version: String): Boolean {
val originalText = kotlinScript.text
kotlinScript.getBuildScriptBlock()?.apply {
addDeclarationIfMissing("var $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra", true).also {
addExpressionAfterIfMissing("$GSK_KOTLIN_VERSION_PROPERTY_NAME = \"$version\"", it)
}
getRepositoriesBlock()?.addRepositoryIfMissing(version)
getDependenciesBlock()?.addPluginToClassPathIfMissing()
}
return originalText != kotlinScript.text
}
override fun configureModuleBuildScript(
kotlinPluginName: 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()?.addRepositoryIfMissing(version)
jvmTarget?.let {
changeKotlinTaskParameter("jvmTarget", it, forTests = false)
changeKotlinTaskParameter("jvmTarget", it, forTests = true)
}
}
return originalText != kotlinScript.text
}
override fun changeCoroutineConfiguration(coroutineOption: String): PsiElement? =
kotlinScript.changeCoroutineConfiguration(coroutineOption)
override fun changeLanguageVersion(version: String, forTests: Boolean): PsiElement? =
kotlinScript.changeKotlinTaskParameter("languageVersion", version, forTests)
override fun changeApiVersion(version: String, forTests: Boolean): PsiElement? =
kotlinScript.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 {
addExpressionIfMissing(
getCompileDependencySnippet(
libraryDescriptor.libraryGroupId,
libraryDescriptor.libraryArtifactId,
scope.toGradleCompileScope(isAndroidModule),
kotlinLibraryVersion))
}
}
override fun getKotlinStdlibVersion(): String? = kotlinScript.getKotlinStdlibVersion()
private fun KtBlockExpression.addCompileStdlibIfMissing(stdlibArtifactName: String): KtCallExpression? =
findCompileStdLib() ?: addExpressionIfMissing(getCompileDependencySnippet(KOTLIN_GROUP_ID, stdlibArtifactName)) as? KtCallExpression
private fun KtFile.containsCompileStdLib(): Boolean =
findScriptInitializer("dependencies")?.getBlock()?.findCompileStdLib() != null
private fun KtFile.containsApplyKotlinPlugin(pluginName: String): Boolean =
findScriptInitializer("apply")?.getBlock()?.findPlugin(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 KtFile.findScriptInitializer(startsWith: String): KtScriptInitializer? =
PsiTreeUtil.findChildrenOfType(this, KtScriptInitializer::class.java).find { it.text.startsWith(startsWith) }
private fun KtBlockExpression.findBlock(name: String): KtBlockExpression? {
return getChildrenOfType<KtCallExpression>().find {
it.calleeExpression?.text == name &&
it.valueArguments.singleOrNull()?.getArgumentExpression() is KtLambdaExpression
}?.getBlock()
}
private fun KtScriptInitializer.getBlock(): KtBlockExpression? =
PsiTreeUtil.findChildOfType<KtCallExpression>(this, KtCallExpression::class.java)?.getBlock()
private fun KtCallExpression.getBlock(): KtBlockExpression? =
(valueArguments.singleOrNull()?.getArgumentExpression() as? KtLambdaExpression)?.bodyExpression
private fun getCompileDependencySnippet(groupId: String, artifactId: String, compileScope: String = "compile", version: String? = null): String =
if (groupId == KOTLIN_GROUP_ID)
"$compileScope(${getKotlinModuleDependencySnippet(artifactId, version)})"
else
"$compileScope(\"$groupId:$artifactId:$version\")"
private fun getKotlinModuleDependencySnippet(artifactId: String, version: String? = null): String =
"kotlinModule(\"${artifactId.removePrefix("kotlin-")}\", ${version?.let { "\"$it\"" } ?: GSK_KOTLIN_VERSION_PROPERTY_NAME})"
private fun KtFile.getKotlinStdlibVersion(): String? {
return findScriptInitializer("dependencies")?.getBlock()?.let {
val expression = it.findCompileStdLib()?.valueArguments?.firstOrNull()?.getArgumentExpression()
when (expression) {
is KtCallExpression -> expression.valueArguments[1].text.trim('\"')
is KtStringTemplateExpression -> expression.text?.trim('\"')?.substringAfterLast(":")?.removePrefix("$")
else -> null
}
}
}
private fun KtBlockExpression.findCompileStdLib(): KtCallExpression? {
return PsiTreeUtil.getChildrenOfType(this, KtCallExpression::class.java)?.find {
it.calleeExpression?.text == "compile" && (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 KtStringTemplateExpression -> text.startsWith("\"$STDLIB_ARTIFACT_PREFIX")
else -> false
}
private fun KtFile.getRepositoriesBlock(): KtBlockExpression? =
findScriptInitializer("repositories")?.getBlock() ?: addTopLevelBlock("repositories")
private fun KtFile.getDependenciesBlock(): KtBlockExpression? =
findScriptInitializer("dependencies")?.getBlock() ?: addTopLevelBlock("dependencies")
private fun KtFile.createApplyBlock(): KtBlockExpression? {
val apply = psiFactory.createScriptInitializer("apply {\n}")
val plugins = findScriptInitializer("plugins")
val addedElement = plugins?.addSibling(apply) ?: addToScriptBlock(apply)
addedElement?.addNewLinesIfNeeded()
return (addedElement as? KtScriptInitializer)?.getBlock()
}
private fun KtFile.getApplyBlock(): KtBlockExpression? = findScriptInitializer("apply")?.getBlock() ?: createApplyBlock()
private fun KtBlockExpression.createPluginIfMissing(pluginName: String): KtCallExpression? =
findPlugin(pluginName) ?: addExpressionIfMissing("plugin(\"$pluginName\")") as? KtCallExpression
private fun KtFile.changeCoroutineConfiguration(coroutineOption: String): PsiElement? {
val snippet = "experimental.coroutines = Coroutines.${coroutineOption.toUpperCase()}"
val kotlinBlock = findScriptInitializer("kotlin")?.getBlock() ?: addTopLevelBlock("kotlin") ?: return null
addImportIfMissing("org.jetbrains.kotlin.gradle.dsl.Coroutines")
val statement = kotlinBlock.statements.find { it.text.startsWith("experimental.coroutines") }
return if (statement != null) {
statement.replace(psiFactory.createExpression(snippet))
}
else {
kotlinBlock.add(psiFactory.createExpression(snippet)).apply { addNewLinesIfNeeded() }
}
}
private fun KtFile.changeKotlinTaskParameter(parameterName: String, parameterValue: String, forTests: Boolean): PsiElement? {
val snippet = "$parameterName = \"$parameterValue\""
val taskName = if (forTests) "compileTestKotlin" else "compileKotlin"
val optionsBlock = findScriptInitializer("$taskName.kotlinOptions")?.getBlock()
return if (optionsBlock != null) {
val assignment = optionsBlock.statements.find {
(it as? KtBinaryExpression)?.left?.text == parameterName
}
if (assignment != null) {
assignment.replace(psiFactory.createExpression(snippet))
}
else {
optionsBlock.addExpressionIfMissing(snippet)
}
}
else {
addImportIfMissing("org.jetbrains.kotlin.gradle.tasks.KotlinCompile")
script?.blockExpression?.addDeclarationIfMissing("val $taskName: KotlinCompile by tasks")
addTopLevelBlock("$taskName.kotlinOptions")?.addExpressionIfMissing(snippet)
}
}
private fun KtFile.getBuildScriptBlock(): KtBlockExpression? =
findScriptInitializer("buildscript")?.getBlock() ?: addTopLevelBlock("buildscript", true)
private fun KtBlockExpression.getRepositoriesBlock(): KtBlockExpression? =
findBlock("repositories") ?: addBlock("repositories")
private fun KtBlockExpression.getDependenciesBlock(): KtBlockExpression? =
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
}
return addExpressionIfMissing(snippet) as? KtCallExpression
}
private fun KtBlockExpression.addPluginToClassPathIfMissing(): KtCallExpression? =
addExpressionIfMissing("classpath(${getKotlinModuleDependencySnippet("gradle-plugin")})") as? KtCallExpression
private fun KtBlockExpression.addBlock(name: String): KtBlockExpression? {
return add(psiFactory.createExpression("$name {\n}"))
?.apply { addNewLinesIfNeeded() }
?.cast<KtCallExpression>()
?.getBlock()
}
private fun KtFile.addTopLevelBlock(name: String, first: Boolean = false): KtBlockExpression? {
val scriptInitializer = psiFactory.createScriptInitializer("$name {\n}")
val addedElement = addToScriptBlock(scriptInitializer, first) as? KtScriptInitializer
addedElement?.addNewLinesIfNeeded()
return addedElement?.getBlock()
}
private fun PsiElement.addSibling(element: PsiElement): PsiElement = parent.addAfter(element, this)
private fun PsiElement.addNewLineBefore(lineBreaks: Int = 1) {
parent.addBefore(psiFactory.createNewLine(lineBreaks), this)
}
private fun PsiElement.addNewLineAfter(lineBreaks: Int = 1) {
parent.addAfter(psiFactory.createNewLine(lineBreaks), this)
}
private fun PsiElement.addNewLinesIfNeeded(lineBreaks: Int = 1) {
if (prevSibling != null && prevSibling.text.isNotBlank()) {
addNewLineBefore(lineBreaks)
}
if (nextSibling != null && nextSibling.text.isNotBlank()) {
addNewLineAfter(lineBreaks)
}
}
private fun KtFile.addToScriptBlock(element: PsiElement, first: Boolean = false): PsiElement? =
if (first) script?.blockExpression?.addAfter(element, null) else script?.blockExpression?.add(element)
private fun KtFile.addImportIfMissing(path: String): KtImportDirective =
importDirectives.find { it.importPath?.pathStr == path } ?:
importList?.add(psiFactory.createImportDirective(ImportPath.fromString(path))) as KtImportDirective
private fun KtBlockExpression.addExpressionAfterIfMissing(text: String, after: PsiElement): KtExpression = addStatementIfMissing(text) {
psiFactory.createExpression(it).let { created ->
addAfter(created, after)
}
}
private fun KtBlockExpression.addExpressionIfMissing(text: String, first: Boolean = false): KtExpression = addStatementIfMissing(text) {
psiFactory.createExpression(it).let { created ->
if(first) addAfter(created, null) else add(created)
}
}
private fun KtBlockExpression.addDeclarationIfMissing(text: String, first: Boolean = false): KtDeclaration = addStatementIfMissing(text) {
psiFactory.createDeclaration<KtDeclaration>(it).let { created ->
if(first) addAfter(created, null) else add(created)
}
}
private inline fun <reified T: PsiElement> KtBlockExpression.addStatementIfMissing(
text: String,
crossinline factory: (String) -> PsiElement): T {
statements.find { it.text == text }?.let {
return it as T
}
return factory(text).apply { addNewLinesIfNeeded() } as T
}
private fun KtPsiFactory.createScriptInitializer(text: String): KtScriptInitializer =
createFile("dummy.kts", text).script?.blockExpression?.firstChild as KtScriptInitializer
private val PsiElement.psiFactory: KtPsiFactory
get() = KtPsiFactory(this)
companion object {
private val STDLIB_ARTIFACT_PREFIX = "org.jetbrains.kotlin:kotlin-stdlib"
private val GSK_KOTLIN_VERSION_PROPERTY_NAME = "kotlin_version"
}
}
@@ -33,26 +33,14 @@ import com.intellij.openapi.vfs.WritingAccessProvider
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager import com.intellij.psi.PsiManager
import com.intellij.psi.codeStyle.CodeStyleManager
import org.jetbrains.kotlin.idea.KotlinPluginUtil import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion
import org.jetbrains.kotlin.idea.util.application.executeCommand import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.versions.getStdlibArtifactId import org.jetbrains.kotlin.idea.versions.getStdlibArtifactId
import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
import org.jetbrains.plugins.gradle.util.GradleConstants import org.jetbrains.plugins.gradle.util.GradleConstants
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile 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 java.io.File import java.io.File
import java.util.* import java.util.*
@@ -80,32 +68,18 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
return ConfigureKotlinStatus.BROKEN return ConfigureKotlinStatus.BROKEN
} }
private fun PsiFile.isConfiguredByAnyGradleConfigurator() = private fun PsiFile.isConfiguredByAnyGradleConfigurator(): Boolean {
Extensions.getExtensions(KotlinProjectConfigurator.EP_NAME) return Extensions.getExtensions(KotlinProjectConfigurator.EP_NAME)
.filterIsInstance<KotlinWithGradleConfigurator>() .filterIsInstance<KotlinWithGradleConfigurator>()
.any { it.isFileConfigured(this) } .any { it.isFileConfigured(this) }
protected open fun isApplicable(module: Module): Boolean {
return KotlinPluginUtil.isGradleModule(module) && !KotlinPluginUtil.isAndroidGradleModule(module)
} }
protected open fun isApplicable(module: Module): Boolean =
KotlinPluginUtil.isGradleModule(module) && !KotlinPluginUtil.isAndroidGradleModule(module)
protected open fun getMinimumSupportedVersion() = "1.0.0" protected open fun getMinimumSupportedVersion() = "1.0.0"
private fun isFileConfigured(projectGradleFile: PsiFile): Boolean = when(projectGradleFile) { private fun isFileConfigured(buildScript: PsiFile): Boolean = getManipulator(buildScript).isConfigured(kotlinPluginName)
is GroovyFile -> isGradleFileConfigured(projectGradleFile)
is KtFile -> isKotlinFileConfigured(projectGradleFile)
else -> error("Unknown build script file type")
}
fun isKotlinFileConfigured(file: KtFile): Boolean =
file.containsApplyKotlinPlugin(kotlinPluginName) && file.containsCompileStdLib()
private fun isGradleFileConfigured(file: GroovyFile): Boolean {
val fileText = file.text
return containsDirective(fileText, getGroovyApplyPluginDirective(kotlinPluginName)) &&
fileText.contains("org.jetbrains.kotlin") &&
fileText.contains("kotlin-stdlib")
}
@JvmSuppressWildcards @JvmSuppressWildcards
override fun configure(project: Project, excludeModules: Collection<Module>) { override fun configure(project: Project, excludeModules: Collection<Module>) {
@@ -132,7 +106,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
val changedFiles = HashSet<PsiFile>() val changedFiles = HashSet<PsiFile>()
val buildScript = project.getTopLevelBuildScriptPsiFile() val buildScript = project.getTopLevelBuildScriptPsiFile()
if (buildScript != null && canConfigureFile(buildScript)) { if (buildScript != null && canConfigureFile(buildScript)) {
val isModified = changeBuildScript(buildScript, true, kotlinVersion, collector) val isModified = configureBuildScript(buildScript, true, kotlinVersion, collector)
if (isModified) { if (isModified) {
changedFiles.add(buildScript) changedFiles.add(buildScript)
} }
@@ -141,7 +115,7 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
for (module in modulesToConfigure) { for (module in modulesToConfigure) {
val file = module.getBuildScriptPsiFile() val file = module.getBuildScriptPsiFile()
if (file != null && canConfigureFile(file)) { if (file != null && canConfigureFile(file)) {
val isModified = changeBuildScript(file, false, kotlinVersion, collector) val isModified = configureBuildScript(file, false, kotlinVersion, collector)
if (isModified) { if (isModified) {
changedFiles.add(file) changedFiles.add(file)
} }
@@ -153,71 +127,18 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
return changedFiles return changedFiles
} }
protected fun addElementsToModuleFile(file: PsiFile, version: String): Boolean = when (file) { protected fun configureModuleBuildScript(file: PsiFile, version: String): Boolean {
is GroovyFile -> addElementsToModuleGroovyFile(file, version)
is KtFile -> addElementsToModuleGSKFile(file, version)
else -> error("Unknown build script file type")
}
protected fun addElementsToModuleGSKFile(file: KtFile, version: String): Boolean {
val originalText = file.text
val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk } val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk }
file.script?.blockExpression?.addDeclarationIfMissing("val $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra", true)
file.getApplyBlock()?.createPluginIfMissing(kotlinPluginName)
file.getDependenciesBlock()?.addCompileStdlibIfMissing(sdk, version)
file.getRepositoriesBlock()?.addRepositoryIfMissing(version)
getJvmTarget(sdk, version)?.let {
file.changeKotlinTaskParameter("jvmTarget", it, forTests = false)
file.changeKotlinTaskParameter("jvmTarget", it, forTests = true)
}
return originalText != file.text
}
private fun KtBlockExpression.addCompileStdlibIfMissing(sdk: Sdk?, version: String): KtCallExpression? =
findCompileStdLib() ?:
addExpressionIfMissing(getGSKCompileDependencySnippet(KOTLIN_GROUP_ID, getStdlibArtifactName(sdk, version))) as? KtCallExpression
protected fun addElementsToModuleGroovyFile(file: GroovyFile, version: String): Boolean {
val oldText = file.text
val applyPluginDirective = getGroovyApplyPluginDirective(kotlinPluginName)
if (!containsDirective(file.text, applyPluginDirective)) {
val apply = GroovyPsiElementFactory.getInstance(file.project).createExpressionFromText(applyPluginDirective)
val applyStatement = getApplyStatement(file)
if (applyStatement != null) {
file.addAfter(apply, applyStatement)
}
else {
val buildScript = getBlockByName(file, "buildscript")
if (buildScript != null) {
file.addAfter(apply, buildScript.parent)
}
else {
file.addAfter(apply, file.statements.lastOrNull() ?: file.firstChild)
}
}
}
val repositoriesBlock = getRepositoriesBlock(file)
addRepository(repositoriesBlock, version)
val dependenciesBlock = getDependenciesBlock(file)
val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk }
addExpressionInBlockIfNeeded(getStdlibDependencyDirectiveForGroovy(sdk, version), dependenciesBlock, false)
val jvmTarget = getJvmTarget(sdk, version) val jvmTarget = getJvmTarget(sdk, version)
if (jvmTarget != null) { return getManipulator(file).configureModuleBuildScript(
changeKotlinTaskParameter(file, "jvmTarget", jvmTarget, forTests = false) kotlinPluginName,
changeKotlinTaskParameter(file, "jvmTarget", jvmTarget, forTests = true) getStdlibArtifactName(sdk, version),
} version,
jvmTarget)
return file.text != oldText
} }
protected open fun getStdlibArtifactName(sdk: Sdk?, version: String) = getStdlibArtifactId(sdk, version) protected open fun getStdlibArtifactName(sdk: Sdk?, version: String) = getStdlibArtifactId(sdk, version)
private fun getStdlibDependencyDirectiveForGroovy(sdk: Sdk?, version: String) =
getGroovyDependencySnippet(getStdlibArtifactName(sdk, version))
protected open fun getJvmTarget(sdk: Sdk?, version: String): String? = null protected open fun getJvmTarget(sdk: Sdk?, version: String): String? = null
protected abstract val kotlinPluginName: String protected abstract val kotlinPluginName: String
@@ -228,14 +149,14 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
version: String version: String
): Boolean { ): Boolean {
if (!isTopLevelProjectFile) { if (!isTopLevelProjectFile) {
var wasModified = addElementsToProjectFile(file, version) var wasModified = configureProjectFile(file, version)
wasModified = wasModified or addElementsToModuleFile(file, version) wasModified = wasModified or configureModuleBuildScript(file, version)
return wasModified return wasModified
} }
return false return false
} }
fun changeBuildScript( fun configureBuildScript(
file: PsiFile, file: PsiFile,
isTopLevelProjectFile: Boolean, isTopLevelProjectFile: Boolean,
version: String, version: String,
@@ -256,26 +177,19 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
} }
companion object { companion object {
private val VERSION_TEMPLATE = "\$VERSION$" fun getManipulator(file: PsiFile): GradleBuildScriptManipulator = when (file) {
is KtFile -> KotlinBuildScriptManipulator(file)
is GroovyFile -> GroovyBuildScriptManipulator(file)
else -> error("Unknown build script file type!")
}
val GROUP_ID = "org.jetbrains.kotlin" val GROUP_ID = "org.jetbrains.kotlin"
val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin" val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin"
val CLASSPATH = "classpath \"$GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\"" val CLASSPATH = "classpath \"$GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\""
private val MAVEN_CENTRAL = "mavenCentral()"
private val JCENTER = "jcenter()"
private val VERSION = String.format("ext.kotlin_version = '%s'", VERSION_TEMPLATE)
private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts" private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts"
private fun containsDirective(fileText: String, directive: String): Boolean {
return fileText.contains(directive)
|| fileText.contains(directive.replace("\"", "'"))
|| fileText.contains(directive.replace("'", "\""))
}
fun getGroovyDependencySnippet(artifactName: String) = "compile \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\"" fun getGroovyDependencySnippet(artifactName: String) = "compile \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\""
fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'" fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'"
@@ -286,11 +200,8 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
return return
} }
val isAndroidModule = KotlinPluginUtil.isAndroidGradleModule(module) getManipulator(buildScript)
when (buildScript) { .addKotlinLibraryToModuleBuildScript(scope, libraryDescriptor, KotlinPluginUtil.isAndroidGradleModule(module))
is GroovyFile -> addKotlinLibraryToModuleGroovyFile(buildScript, scope, libraryDescriptor, isAndroidModule)
is KtFile -> addKotlinLibraryToModuleGSKFile(buildScript, scope, libraryDescriptor, isAndroidModule)
}
buildScript.virtualFile?.let { buildScript.virtualFile?.let {
createConfigureKotlinNotificationCollector(buildScript.project) createConfigureKotlinNotificationCollector(buildScript.project)
@@ -299,131 +210,26 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
} }
} }
fun addKotlinLibraryToModuleGroovyFile( fun changeCoroutineConfiguration(module: Module, coroutineOption: String): PsiElement? = changeBuildGradle(module) {
gradleFile: GroovyFile, getManipulator(it).changeCoroutineConfiguration(coroutineOption)
scope: DependencyScope,
libraryDescriptor: ExternalLibraryDescriptor,
isAndroidModule: Boolean) {
gradleFile.project.executeWriteCommand("Add Kotlin library") {
val dependencyString = String.format(
"%s \"%s:%s:%s\"",
scope.toGradleCompileScope(isAndroidModule),
libraryDescriptor.libraryGroupId,
libraryDescriptor.libraryArtifactId,
libraryDescriptor.maxVersion)
val dependenciesBlock = getDependenciesBlock(gradleFile)
addLastExpressionInBlockIfNeeded(dependencyString, dependenciesBlock)
CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(gradleFile)
}
}
fun addKotlinLibraryToModuleGSKFile(
gradleFile: KtFile,
scope: DependencyScope,
libraryDescriptor: ExternalLibraryDescriptor,
isAndroidModule: Boolean) {
gradleFile.project.executeWriteCommand("Add Kotlin library") {
val kotlinLibraryVersion = libraryDescriptor.maxVersion.takeIf { it != GSK_KOTLIN_VERSION_PROPERTY_NAME }
gradleFile.getDependenciesBlock()?.apply {
addExpressionIfMissing(
getGSKCompileDependencySnippet(
libraryDescriptor.libraryGroupId,
libraryDescriptor.libraryArtifactId,
scope.toGradleCompileScope(isAndroidModule),
kotlinLibraryVersion))
}
CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(gradleFile)
}
}
private fun DependencyScope.toGradleCompileScope(isAndroidModule: Boolean) = when (this) {
DependencyScope.COMPILE -> "compile"
// TODO we should add testCompile or androidTestCompile
DependencyScope.TEST -> if (isAndroidModule) "compile" else "testCompile"
DependencyScope.RUNTIME -> "runtime"
DependencyScope.PROVIDED -> "compile"
else -> "compile"
}
fun changeCoroutineConfiguration(module: Module, coroutineOption: String): PsiElement? {
return changeBuildGradle(module) { buildScriptFile ->
when (buildScriptFile) {
is GroovyFile -> changeCoroutineConfiguration(buildScriptFile, coroutineOption)
is KtFile -> changeCoroutineConfiguration(buildScriptFile, coroutineOption)
else -> error("Unknown build script file type")
}
}
}
fun changeCoroutineConfiguration(gradleFile: GroovyFile, coroutineOption: String): PsiElement? {
val snippet = "coroutines \"$coroutineOption\""
val kotlinBlock = getBlockOrCreate(gradleFile, "kotlin")
val experimentalBlock = getBlockOrCreate(kotlinBlock, "experimental")
addOrReplaceExpression(experimentalBlock, snippet) { stmt ->
(stmt as? GrMethodCall)?.invokedExpression?.text == "coroutines"
}
return kotlinBlock.parent
} }
fun changeLanguageVersion(module: Module, languageVersion: String?, apiVersion: String? = null, forTests: Boolean): PsiElement? { fun changeLanguageVersion(module: Module, languageVersion: String?, apiVersion: String? = null, forTests: Boolean): PsiElement? {
return changeBuildGradle(module) { buildScriptFile -> return changeBuildGradle(module) { buildScriptFile ->
val manipulator = getManipulator(buildScriptFile)
var result: PsiElement? = null var result: PsiElement? = null
if (languageVersion != null) { if (languageVersion != null) {
result = when (buildScriptFile) { result = manipulator.changeLanguageVersion(languageVersion, forTests)
is GroovyFile -> changeLanguageVersion(buildScriptFile, languageVersion, forTests)
is KtFile -> changeLanguageVersion(buildScriptFile, languageVersion, forTests)
else -> error("Unknown build script file type")
}
} }
if (apiVersion != null) { if (apiVersion != null) {
result = when (buildScriptFile) { result = manipulator.changeApiVersion(apiVersion, forTests)
is GroovyFile -> changeApiVersion(buildScriptFile, apiVersion, forTests)
is KtFile -> changeApiVersion(buildScriptFile, apiVersion, forTests)
else -> error("Unknown build script file type")
}
} }
result result
} }
} }
fun changeLanguageVersion(gradleFile: KtFile, languageVersion: String, forTests: Boolean): PsiElement? {
return gradleFile.changeKotlinTaskParameter("languageVersion", languageVersion, forTests)
}
fun changeApiVersion(gradleFile: KtFile, apiVersion: String, forTests: Boolean): PsiElement? {
return gradleFile.changeKotlinTaskParameter("apiVersion", apiVersion, forTests)
}
fun changeLanguageVersion(gradleFile: GroovyFile, languageVersion: String, forTests: Boolean): PsiElement? {
return changeKotlinTaskParameter(gradleFile, "languageVersion", languageVersion, forTests)
}
fun changeApiVersion(gradleFile: GroovyFile, apiVersion: String, forTests: Boolean): PsiElement? {
return changeKotlinTaskParameter(gradleFile, "apiVersion", apiVersion, forTests)
}
private fun changeKotlinTaskParameter(gradleFile: GroovyFile, parameterName: String, parameterValue: String, forTests: Boolean): PsiElement? {
val snippet = "$parameterName = \"$parameterValue\""
val kotlinBlock = getBlockOrCreate(gradleFile, if (forTests) "compileTestKotlin" else "compileKotlin")
for (stmt in kotlinBlock.statements) {
if ((stmt as? GrAssignmentExpression)?.lValue?.text == "kotlinOptions." + parameterName) {
return stmt.replaceWithStatementFromText("kotlinOptions." + snippet)
}
}
val kotlinOptionsBlock = getBlockOrCreate(kotlinBlock, "kotlinOptions")
addOrReplaceExpression(kotlinOptionsBlock, snippet) { stmt ->
(stmt as? GrAssignmentExpression)?.lValue?.text == parameterName
}
return kotlinBlock.parent
}
private fun changeBuildGradle(module: Module, body: (PsiFile) -> PsiElement?): PsiElement? { private fun changeBuildGradle(module: Module, body: (PsiFile) -> PsiElement?): PsiElement? {
val buildScriptFile = module.getBuildScriptPsiFile() val buildScriptFile = module.getBuildScriptPsiFile()
if (buildScriptFile != null && canConfigureFile(buildScriptFile)) { if (buildScriptFile != null && canConfigureFile(buildScriptFile)) {
@@ -434,93 +240,15 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
return null return null
} }
private fun addOrReplaceExpression(block: GrClosableBlock, snippet: String, predicate: (GrStatement) -> Boolean) {
block.statements.firstOrNull(predicate)?.let { stmt ->
stmt.replaceWithStatementFromText(snippet)
return
}
addLastExpressionInBlockIfNeeded(snippet, block)
}
private fun GrStatement.replaceWithStatementFromText(snippet: String): GrStatement {
val newStatement = GroovyPsiElementFactory.getInstance(project).createExpressionFromText(snippet)
CodeStyleManager.getInstance(project).reformat(newStatement)
return replaceWithStatement(newStatement)
}
fun getKotlinStdlibVersion(module: Module): String? { fun getKotlinStdlibVersion(module: Module): String? {
val gradleFile = module.getBuildScriptPsiFile() ?: return null return module.getBuildScriptPsiFile()?.let {
return when (gradleFile) { getManipulator(it).getKotlinStdlibVersion()
is GroovyFile -> getKotlinStdlibVersion(gradleFile)
is KtFile -> gradleFile.getKotlinStdlibVersion()
else -> null
} }
} }
private fun getKotlinStdlibVersion(gradleFile: GroovyFile): String? { fun configureProjectFile(file: PsiFile, version: String): Boolean = getManipulator(file).configureProjectBuildScript(version)
val versionProperty = "\$kotlin_version"
val block = getBuildScriptBlock(gradleFile)
if (block.text.contains("ext.kotlin_version = ")) {
return versionProperty
}
val dependencies = getDependenciesBlock(gradleFile).statements private fun canConfigureFile(file: PsiFile): Boolean = WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null)
val stdlibArtifactPrefix = "org.jetbrains.kotlin:kotlin-stdlib:"
for (dependency in dependencies) {
val dependencyText = dependency.text
val startIndex = dependencyText.indexOf(stdlibArtifactPrefix) + stdlibArtifactPrefix.length
val endIndex = dependencyText.length - 1
if (startIndex != -1 && endIndex != -1) {
return dependencyText.substring(startIndex, endIndex)
}
}
return null
}
fun addElementsToProjectFile(file: PsiFile, version: String): Boolean = when (file) {
is GroovyFile -> addElementsToProjectGroovyFile(file, version)
is KtFile -> addElementsToProjectGSKFile(file, version)
else -> error("Unknown build script file type")
}
fun addElementsToProjectGSKFile(file: KtFile, version: String): Boolean {
val originalText = file.text
file.getBuildScriptBlock()?.apply {
addDeclarationIfMissing("var $GSK_KOTLIN_VERSION_PROPERTY_NAME: String by extra", true).also {
addExpressionAfterIfMissing("$GSK_KOTLIN_VERSION_PROPERTY_NAME = \"$version\"", it)
}
getRepositoriesBlock()?.addRepositoryIfMissing(version)
getDependenciesBlock()?.addPluginToClassPathIfMissing()
}
return originalText != file.text
}
fun addElementsToProjectGroovyFile(file: GroovyFile, version: String): Boolean {
var wasModified: Boolean
val buildScriptBlock = getBuildScriptBlock(file)
wasModified = addFirstExpressionInBlockIfNeeded(VERSION.replace(VERSION_TEMPLATE, version), buildScriptBlock)
val buildScriptRepositoriesBlock = getBuildScriptRepositoriesBlock(file)
wasModified = wasModified or addRepository(buildScriptRepositoriesBlock, version)
val buildScriptDependenciesBlock = getBuildScriptDependenciesBlock(file)
wasModified = wasModified or addLastExpressionInBlockIfNeeded(CLASSPATH, buildScriptDependenciesBlock)
return wasModified
}
private fun isRepositoryConfigured(repositoriesBlockText: String): Boolean {
return repositoriesBlockText.contains(MAVEN_CENTRAL) || repositoriesBlockText.contains(JCENTER)
}
private fun canConfigureFile(file: PsiFile): Boolean {
return WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null)
}
private fun Module.getBuildScriptPsiFile() = getBuildScriptFile()?.getPsiFile(project) private fun Module.getBuildScriptPsiFile() = getBuildScriptFile()?.getPsiFile(project)
@@ -555,74 +283,6 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
PsiManager.getInstance(project).findFile(it) PsiManager.getInstance(project).findFile(it)
} }
private fun getDependenciesBlock(file: GrStatementOwner): GrClosableBlock {
return getBlockOrCreate(file, "dependencies")
}
private fun getBuildScriptBlock(file: GrStatementOwner) = getBlockOrCreate(file, "buildscript")
private fun getBuildScriptDependenciesBlock(file: GrStatementOwner): GrClosableBlock {
val buildScript = getBuildScriptBlock(file)
return getBlockOrCreate(buildScript, "dependencies")
}
private fun getBuildScriptRepositoriesBlock(file: GrStatementOwner): GrClosableBlock {
val buildScript = getBuildScriptBlock(file)
return getBlockOrCreate(buildScript, "repositories")
}
private fun getRepositoriesBlock(file: GrStatementOwner) = getBlockOrCreate(file, "repositories")
private fun getBlockOrCreate(parent: GrStatementOwner, name: String): GrClosableBlock {
var block = getBlockByName(parent, name)
if (block == null) {
val factory = GroovyPsiElementFactory.getInstance(parent.project)
val newBlock = factory.createExpressionFromText("$name{\n}\n")
parent.addAfter(newBlock, parent.statements.lastOrNull() ?: parent.firstChild)
block = getBlockByName(parent, name)!!
}
return block
}
private fun addLastExpressionInBlockIfNeeded(text: String, block: GrClosableBlock): Boolean {
return addExpressionInBlockIfNeeded(text, block, false)
}
private fun addFirstExpressionInBlockIfNeeded(text: String, block: GrClosableBlock): Boolean {
return addExpressionInBlockIfNeeded(text, block, true)
}
private fun getBlockByName(parent: PsiElement, name: String): GrClosableBlock? {
return parent.getChildrenOfType<GrMethodCallExpression>()
.filter { it.closureArguments.isNotEmpty() }
.find { it.invokedExpression.text == name }
?.let { it.closureArguments[0] }
}
private fun addExpressionInBlockIfNeeded(text: String, block: GrClosableBlock, isFirst: Boolean): Boolean {
if (block.text.contains(text)) return false
val newStatement = GroovyPsiElementFactory.getInstance(block.project).createExpressionFromText(text)
CodeStyleManager.getInstance(block.project).reformat(newStatement)
val statements = block.statements
if (!isFirst && statements.isNotEmpty()) {
val lastStatement = statements[statements.size - 1]
if (lastStatement != null) {
block.addAfter(newStatement, lastStatement)
}
}
else {
val firstChild = block.firstChild
if (firstChild != null) {
block.addAfter(newStatement, firstChild)
}
}
return true
}
private fun getApplyStatement(file: GroovyFile): GrApplicationStatement? =
file.getChildrenOfType<GrApplicationStatement>()
.find { it.invokedExpression.text == "apply" }
private fun showErrorMessage(project: Project, message: String?) { private fun showErrorMessage(project: Project, message: String?) {
Messages.showErrorDialog(project, Messages.showErrorDialog(project,
"<html>Couldn't configure kotlin-gradle plugin automatically.<br/>" + "<html>Couldn't configure kotlin-gradle plugin automatically.<br/>" +
@@ -630,15 +290,5 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
"<br/>See manual installation instructions <a href=\"https://kotlinlang.org/docs/reference/using-gradle.html\">here</a>.</html>", "<br/>See manual installation instructions <a href=\"https://kotlinlang.org/docs/reference/using-gradle.html\">here</a>.</html>",
"Configure Kotlin-Gradle Plugin") "Configure Kotlin-Gradle Plugin")
} }
private fun addRepository(repositoriesBlock: GrClosableBlock, version: String): Boolean {
val repository = getRepositoryForVersion(version)
val snippet = when {
repository != null -> repository.toGroovyRepositorySnippet()
!isRepositoryConfigured(repositoriesBlock.text) -> "$MAVEN_CENTRAL\n"
else -> return false
}
return addLastExpressionInBlockIfNeeded(snippet, repositoriesBlock)
}
} }
} }
@@ -1,311 +0,0 @@
/*
* 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.gradle
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ExternalLibraryDescriptor
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator
import org.jetbrains.kotlin.idea.configuration.changeCoroutineConfiguration
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
class KotlinWithGradleConfiguratorTest : LightCodeInsightFixtureTestCase() {
fun testAddCoroutinesSupport() {
val buildGradle = myFixture.configureByText("build.gradle", "apply plugin: 'kotlin'\n") as GroovyFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeCoroutineConfiguration(buildGradle, "enable")
}
myFixture.checkResult(
"""apply plugin: 'kotlin'
|kotlin {
| experimental {
| coroutines "enable"
| }
|}
|""".trimMargin("|"))
}
fun testAddCoroutinesSupportGSK() {
val buildGradle = myFixture.configureByText("build.gradle.kts", "") as KtFile
myFixture.project.executeWriteCommand("") {
changeCoroutineConfiguration(buildGradle, "enable")
}
myFixture.checkResult(
"""import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
|kotlin {
| experimental.coroutines = Coroutines.ENABLE
|}""".trimMargin("|"))
}
fun testChangeCoroutinesSupport() {
val buildGradle = myFixture.configureByText("build.gradle",
"""apply plugin: 'kotlin'
|kotlin {
| experimental {
| coroutines "disable"
| }
|}
|""".trimMargin("|")) as GroovyFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeCoroutineConfiguration(buildGradle, "enable")
}
myFixture.checkResult(
"""apply plugin: 'kotlin'
|kotlin {
| experimental {
| coroutines "enable"
| }
|}
|""".trimMargin("|"))
}
fun testChangeCoroutinesSupportGSK() {
val buildGradle = myFixture.configureByText("build.gradle.kts",
"""import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
|kotlin {
| experimental.coroutines = Coroutines.DISABLE
|}
|""".trimMargin("|")) as KtFile
myFixture.project.executeWriteCommand("") {
changeCoroutineConfiguration(buildGradle, "enable")
}
myFixture.checkResult(
"""import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
|kotlin {
| experimental.coroutines = Coroutines.ENABLE
|}
|""".trimMargin("|"))
}
fun testAddLanguageVersion() {
val buildGradle = myFixture.configureByText("build.gradle", "apply plugin: 'kotlin'\n") as GroovyFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeLanguageVersion(buildGradle, "1.1", false)
}
myFixture.checkResult(
"""apply plugin: 'kotlin'
|compileKotlin {
| kotlinOptions {
| languageVersion = "1.1"
| }
|}
|""".trimMargin("|"))
}
fun testAddLanguageVersionGSK() {
val buildGradle = myFixture.configureByText("build.gradle.kts", "") as KtFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeLanguageVersion(buildGradle, "1.1", false)
}
myFixture.checkResult(
"""import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|val compileKotlin: KotlinCompile by tasks
|compileKotlin.kotlinOptions {
| languageVersion = "1.1"
|}""".trimMargin("|"))
}
fun testChangeLanguageVersion() {
val buildGradle = myFixture.configureByText("build.gradle",
"""apply plugin: 'kotlin'
|compileKotlin {
| kotlinOptions {
| languageVersion = "1.0"
| }
|}
|""".trimMargin("|")) as GroovyFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeLanguageVersion(buildGradle, "1.1", false)
}
myFixture.checkResult(
"""apply plugin: 'kotlin'
|compileKotlin {
| kotlinOptions {
| languageVersion = "1.1"
| }
|}
|""".trimMargin("|"))
}
fun testChangeLanguageVersionGSK() {
val buildGradle = myFixture.configureByText("build.gradle.kts",
"""val compileKotlin: KotlinCompile by tasks
|compileKotlin.kotlinOptions {
| languageVersion = "1.0"
|}
|""".trimMargin("|")) as KtFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeLanguageVersion(buildGradle, "1.1", false)
}
myFixture.checkResult(
"""val compileKotlin: KotlinCompile by tasks
|compileKotlin.kotlinOptions {
| languageVersion = "1.1"
|}
|""".trimMargin("|"))
}
fun testAddLibrary() {
val buildGradle = myFixture.configureByText("build.gradle",
"""
|dependencies {
| compile "org.jetbrains.kotlin:stdlib-jre8:1.0.0"
|}
|""".trimMargin("|")) as GroovyFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.addKotlinLibraryToModuleGroovyFile(
buildGradle,
DependencyScope.COMPILE,
object: ExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-reflect", "1.0.0", "1.0.0") {
override fun getLibraryClassesRoots() = emptyList<String>()
},
false)
}
myFixture.checkResult(
"""
|dependencies {
| compile "org.jetbrains.kotlin:stdlib-jre8:1.0.0"
| compile "org.jetbrains.kotlin:kotlin-reflect:1.0.0"
|}
|""".trimMargin("|"))
}
fun testAddLibraryGSK() {
val buildGradle = myFixture.configureByText("build.gradle.kts",
"""
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8"))
|}
|""".trimMargin("|")) as KtFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.addKotlinLibraryToModuleGSKFile(
buildGradle,
DependencyScope.COMPILE,
object: ExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-reflect", "1.0.0", "1.0.0") {
override fun getLibraryClassesRoots() = emptyList<String>()
},
false)
}
myFixture.checkResult(
"""
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8"))
| compile(kotlinModule("reflect", "1.0.0"))
|}
|""".trimMargin("|"))
}
fun testAddTestLibraryGSK() {
val buildGradle = myFixture.configureByText("build.gradle.kts",
"""
|dependencies {
| compile(kotlinModule("stdlib-jre8"))
|}
|""".trimMargin("|")) as KtFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.addKotlinLibraryToModuleGSKFile(
buildGradle,
DependencyScope.TEST,
object: ExternalLibraryDescriptor("junit", "junit", "4.12", "4.12") {
override fun getLibraryClassesRoots() = emptyList<String>()
},
false)
KotlinWithGradleConfigurator.addKotlinLibraryToModuleGSKFile(
buildGradle,
DependencyScope.TEST,
object: ExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-test", "1.1.2", "1.1.2") {
override fun getLibraryClassesRoots() = emptyList<String>()
},
false)
}
myFixture.checkResult(
"""
|dependencies {
| compile(kotlinModule("stdlib-jre8"))
| testCompile("junit:junit:4.12")
| testCompile(kotlinModule("test", "1.1.2"))
|}
|""".trimMargin("|"))
}
fun testAddLibraryGSK_WithKotlinVersion() {
val buildGradle = myFixture.configureByText("build.gradle.kts",
"""
|val kotlin_version: String by extra
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8", kotlin_version))
|}
|""".trimMargin("|")) as KtFile
myFixture.project.executeWriteCommand("") {
val stdLibVersion = KotlinWithGradleConfigurator.getKotlinStdlibVersion(myFixture.module)
KotlinWithGradleConfigurator.addKotlinLibraryToModuleGSKFile(
buildGradle,
DependencyScope.COMPILE,
object: ExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-reflect", stdLibVersion, stdLibVersion) {
override fun getLibraryClassesRoots() = emptyList<String>()
},
false)
}
myFixture.checkResult(
"""
|val kotlin_version: String by extra
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8", kotlin_version))
| compile(kotlinModule("reflect", kotlin_version))
|}
|""".trimMargin("|"))
}
fun testAddNonKotlinLibraryGSK() {
val buildGradle = myFixture.configureByText("build.gradle.kts",
"""
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8"))
|}
|""".trimMargin("|")) as KtFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.addKotlinLibraryToModuleGSKFile(
buildGradle,
DependencyScope.COMPILE,
object: ExternalLibraryDescriptor("org.a.b", "lib", "1.0.0", "1.0.0") {
override fun getLibraryClassesRoots() = emptyList<String>()
},
false)
}
myFixture.checkResult(
"""
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8"))
| compile("org.a.b:lib:1.0.0")
|}
|""".trimMargin("|"))
}
}
@@ -20,7 +20,10 @@ import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.impl.LoadTextUtil import com.intellij.openapi.fileEditor.impl.LoadTextUtil
import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ExternalLibraryDescriptor
import org.jetbrains.kotlin.idea.configuration.* import org.jetbrains.kotlin.idea.configuration.*
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.test.testFramework.runInEdtAndWait import org.jetbrains.kotlin.test.testFramework.runInEdtAndWait
import org.jetbrains.kotlin.test.testFramework.runWriteAction import org.jetbrains.kotlin.test.testFramework.runWriteAction
@@ -208,4 +211,545 @@ class GradleConfiguratorTest : GradleImportingTestCase() {
assertSameElements(moduleNamesWithKotlinFiles, "app") assertSameElements(moduleNamesWithKotlinFiles, "app")
} }
} }
@Test
fun testAddNonKotlinLibraryGSK() {
val buildScript = createProjectSubFile("build.gradle.kts",
"""
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8"))
|}
|""".trimMargin("|"))
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.addKotlinLibraryToModule(
myTestFixture.module,
DependencyScope.COMPILE,
object: ExternalLibraryDescriptor("org.a.b", "lib", "1.0.0", "1.0.0") {
override fun getLibraryClassesRoots() = emptyList<String>()
})
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals(
"""
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8"))
| compile("org.a.b:lib:1.0.0")
|}
|""".trimMargin("|"),
LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testAddLibraryGSK_WithKotlinVersion() {
val buildScript = createProjectSubFile("build.gradle.kts",
"""
|val kotlin_version: String by extra
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8", kotlin_version))
|}
|""".trimMargin("|"))
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
val stdLibVersion = KotlinWithGradleConfigurator.getKotlinStdlibVersion(myTestFixture.module)
KotlinWithGradleConfigurator.addKotlinLibraryToModule(
myTestFixture.module,
DependencyScope.COMPILE,
object : ExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-reflect", stdLibVersion, stdLibVersion) {
override fun getLibraryClassesRoots() = emptyList<String>()
})
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals(
"""
|val kotlin_version: String by extra
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8", kotlin_version))
| compile(kotlinModule("reflect", kotlin_version))
|}
|""".trimMargin("|"),
LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testAddTestLibraryGSK() {
val buildScript = createProjectSubFile("build.gradle.kts",
"""
|dependencies {
| compile(kotlinModule("stdlib-jre8"))
|}
|""".trimMargin("|"))
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.addKotlinLibraryToModule(
myTestFixture.module,
DependencyScope.TEST,
object : ExternalLibraryDescriptor("junit", "junit", "4.12", "4.12") {
override fun getLibraryClassesRoots() = emptyList<String>()
})
KotlinWithGradleConfigurator.addKotlinLibraryToModule(
myTestFixture.module,
DependencyScope.TEST,
object : ExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-test", "1.1.2", "1.1.2") {
override fun getLibraryClassesRoots() = emptyList<String>()
})
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals(
"""
|dependencies {
| compile(kotlinModule("stdlib-jre8"))
| testCompile("junit:junit:4.12")
| testCompile(kotlinModule("test", "1.1.2"))
|}
|""".trimMargin("|"),
LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testAddLibraryGSK() {
val buildScript = createProjectSubFile("build.gradle.kts",
"""
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8"))
|}
|""".trimMargin("|"))
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.addKotlinLibraryToModule(
myTestFixture.module,
DependencyScope.COMPILE,
object: ExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-reflect", "1.0.0", "1.0.0") {
override fun getLibraryClassesRoots() = emptyList<String>()
})
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals(
"""
|dependencies {
| testCompile("junit:junit:4.12")
| compile(kotlinModule("stdlib-jre8"))
| compile(kotlinModule("reflect", "1.0.0"))
|}
|""".trimMargin("|"),
LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testAddCoroutinesSupport() {
val buildScript = createProjectSubFile("build.gradle", """
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
}
""".trimIndent())
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeCoroutineConfiguration(myTestFixture.module, "enable")
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals("""
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
}
kotlin {
experimental {
coroutines "enable"
}
}
""".trimIndent(),
LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testAddCoroutinesSupportGSK() {
val buildScript = createProjectSubFile("build.gradle.kts", "")
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeCoroutineConfiguration(myTestFixture.module, "enable")
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals(
"""import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
|kotlin {
| experimental.coroutines = Coroutines.ENABLE
|}""".trimMargin("|"),
LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testChangeCoroutinesSupport() {
val buildScript = createProjectSubFile("build.gradle", """
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
}
kotlin {
experimental {
coroutines "error"
}
}
""".trimIndent())
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeCoroutineConfiguration(myTestFixture.module, "enable")
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals("""
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
}
kotlin {
experimental {
coroutines "enable"
}
}
""".trimIndent(), LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testChangeCoroutinesSupportGSK() {
val buildScript = createProjectSubFile("build.gradle.kts",
"""import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
|kotlin {
| experimental.coroutines = Coroutines.DISABLE
|}
|""".trimMargin("|"))
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeCoroutineConfiguration(myTestFixture.module, "enable")
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals(
"""import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
|kotlin {
| experimental.coroutines = Coroutines.ENABLE
|}
|""".trimMargin("|"),
LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testAddLanguageVersion() {
val buildScript = createProjectSubFile("build.gradle", """
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
}
""".trimIndent())
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeLanguageVersion(myTestFixture.module, "1.1", null, false)
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals("""
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
}
compileKotlin {
kotlinOptions {
languageVersion = "1.1"
}
}
""".trimIndent(), LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testAddLanguageVersionGSK() {
val buildScript = createProjectSubFile("build.gradle.kts", "")
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeLanguageVersion(myTestFixture.module, "1.1", null, false)
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals(
"""import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|val compileKotlin: KotlinCompile by tasks
|compileKotlin.kotlinOptions {
| languageVersion = "1.1"
|}""".trimMargin("|"),
LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testChangeLanguageVersion() {
val buildScript = createProjectSubFile("build.gradle", """
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
}
compileKotlin {
kotlinOptions {
languageVersion = "1.0"
}
}
""".trimIndent())
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeLanguageVersion(myTestFixture.module, "1.1", null, false)
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals("""
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
}
compileKotlin {
kotlinOptions {
languageVersion = "1.1"
}
}
""".trimIndent(), LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testChangeLanguageVersionGSK() {
val buildScript = createProjectSubFile("build.gradle.kts",
"""val compileKotlin: KotlinCompile by tasks
|compileKotlin.kotlinOptions {
| languageVersion = "1.0"
|}
|""".trimMargin("|"))
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeLanguageVersion(myTestFixture.module, "1.1", null, false)
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals(
"""val compileKotlin: KotlinCompile by tasks
|compileKotlin.kotlinOptions {
| languageVersion = "1.1"
|}
|""".trimMargin("|"),
LoadTextUtil.loadText(buildScript).toString())
}
@Test
fun testAddLibrary() {
val buildScript = createProjectSubFile("build.gradle", """
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
}
""".trimIndent())
importProject()
runInEdtAndWait {
myTestFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.addKotlinLibraryToModule(
myTestFixture.module,
DependencyScope.COMPILE,
object: ExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-reflect", "1.0.0", "1.0.0") {
override fun getLibraryClassesRoots() = emptyList<String>()
})
}
FileDocumentManager.getInstance().saveAllDocuments()
}
assertEquals("""
buildscript {
repositories {
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.1.0"
}
}
apply plugin: 'kotlin'
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-1.1.0"
compile "org.jetbrains.kotlin:kotlin-reflect:1.0.0"
}
""".trimIndent(), LoadTextUtil.loadText(buildScript).toString())
}
} }
@@ -34,7 +34,7 @@ abstract class AbstractGradleConfigureProjectByChangingFileTest : AbstractConfig
return return
} }
configurator.changeBuildScript(file, true, version, collector) configurator.configureBuildScript(file, true, version, collector)
configurator.changeBuildScript(file, false, version, collector) configurator.configureBuildScript(file, false, version, collector)
} }
} }