From 47c80a1ad16f0ff9a780ca53fff257b592375bd4 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 10 Nov 2016 20:19:15 +0100 Subject: [PATCH] KotlinWithGradleConfigurator: J2K --- ...KotlinAndroidGradleModuleConfigurator.java | 6 +- ...radleKotlinJavaFrameworkSupportProvider.kt | 4 +- .../KotlinGradleModuleConfigurator.java | 6 +- .../KotlinWithGradleConfigurator.kt | 769 ++++++++---------- 4 files changed, 368 insertions(+), 417 deletions(-) diff --git a/idea/idea-android/src/org/jetbrains/kotlin/android/configure/KotlinAndroidGradleModuleConfigurator.java b/idea/idea-android/src/org/jetbrains/kotlin/android/configure/KotlinAndroidGradleModuleConfigurator.java index 043e50929e0..7e9a2f906cb 100644 --- a/idea/idea-android/src/org/jetbrains/kotlin/android/configure/KotlinAndroidGradleModuleConfigurator.java +++ b/idea/idea-android/src/org/jetbrains/kotlin/android/configure/KotlinAndroidGradleModuleConfigurator.java @@ -61,13 +61,13 @@ public class KotlinAndroidGradleModuleConfigurator extends KotlinWithGradleConfi @Override protected boolean addSourceSetsBlock(@NotNull GroovyFile file) { GrClosableBlock androidBlock = getAndroidBlock(file); - return addLastExpressionInBlockIfNeeded(SOURCE_SET, getSourceSetsBlock(androidBlock)); + return Companion.addLastExpressionInBlockIfNeeded(Companion.getSOURCE_SET(), Companion.getSourceSetsBlock(androidBlock)); } @Override protected boolean addElementsToFile(@NotNull GroovyFile groovyFile, boolean isTopLevelProjectFile, @NotNull String version) { if (isTopLevelProjectFile) { - return addElementsToProjectFile(groovyFile, version); + return Companion.addElementsToProjectFile(groovyFile, version); } else { return addElementsToModuleFile(groovyFile, version); @@ -76,7 +76,7 @@ public class KotlinAndroidGradleModuleConfigurator extends KotlinWithGradleConfi @NotNull private static GrClosableBlock getAndroidBlock(@NotNull GroovyFile file) { - return getBlockOrCreate(file, "android"); + return Companion.getBlockOrCreate(file, "android"); } KotlinAndroidGradleModuleConfigurator() { diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/GradleKotlinJavaFrameworkSupportProvider.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/GradleKotlinJavaFrameworkSupportProvider.kt index f161bc57262..eea1305373c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/configuration/GradleKotlinJavaFrameworkSupportProvider.kt +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/GradleKotlinJavaFrameworkSupportProvider.kt @@ -45,10 +45,10 @@ class GradleKotlinJavaFrameworkSupportProvider() : GradleFrameworkSupportProvide val additionalRepository: String? = when { kotlinVersion == "@snapshot@" -> { kotlinVersion = "1.1-SNAPSHOT" - KotlinWithGradleConfigurator.SNAPSHOT_REPOSITORY + KotlinWithGradleConfigurator.SNAPSHOT_REPOSITORY_SNIPPET } isEap(kotlinVersion) -> { - KotlinWithGradleConfigurator.EAP_REPOSITORY + KotlinWithGradleConfigurator.EAP_REPOSITORY_SNIPPET } else -> { null diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleModuleConfigurator.java b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleModuleConfigurator.java index 1a18c4f86ee..512e0a11750 100644 --- a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleModuleConfigurator.java +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleModuleConfigurator.java @@ -60,14 +60,14 @@ public class KotlinGradleModuleConfigurator extends KotlinWithGradleConfigurator @Override protected boolean addSourceSetsBlock(@NotNull GroovyFile file) { - GrClosableBlock sourceSetBlock = getSourceSetsBlock(file); - return addLastExpressionInBlockIfNeeded(SOURCE_SET, sourceSetBlock); + GrClosableBlock sourceSetBlock = Companion.getSourceSetsBlock(file); + return Companion.addLastExpressionInBlockIfNeeded(Companion.getSOURCE_SET(), sourceSetBlock); } @Override protected boolean addElementsToFile(@NotNull GroovyFile groovyFile, boolean isTopLevelProjectFile, @NotNull String version) { if (!isTopLevelProjectFile) { - boolean wasModified = addElementsToProjectFile(groovyFile, version); + boolean wasModified = Companion.addElementsToProjectFile(groovyFile, version); wasModified |= addElementsToModuleFile(groovyFile, version); return wasModified; } diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt index 4415b41ec45..df29ec93424 100644 --- a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt @@ -14,483 +14,434 @@ * limitations under the License. */ -package org.jetbrains.kotlin.idea.configuration; +package org.jetbrains.kotlin.idea.configuration -import com.intellij.codeInsight.CodeInsightUtilCore; -import com.intellij.ide.actions.OpenFileAction; -import com.intellij.openapi.application.Result; -import com.intellij.openapi.command.CommandProcessor; -import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.DependencyScope; -import com.intellij.openapi.roots.ExternalLibraryDescriptor; -import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.vfs.VfsUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.openapi.vfs.WritingAccessProvider; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiManager; -import com.intellij.psi.codeStyle.CodeStyleManager; -import com.intellij.psi.util.PsiTreeUtil; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.idea.KotlinPluginUtil; -import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion; -import org.jetbrains.plugins.gradle.util.GradleConstants; -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.GrExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; -import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner; +import com.intellij.codeInsight.CodeInsightUtilCore +import com.intellij.ide.actions.OpenFileAction +import com.intellij.openapi.command.CommandProcessor +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.DependencyScope +import com.intellij.openapi.roots.ExternalLibraryDescriptor +import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.openapi.vfs.WritingAccessProvider +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiManager +import com.intellij.psi.codeStyle.CodeStyleManager +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.idea.KotlinPluginUtil +import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion +import org.jetbrains.kotlin.idea.util.application.executeWriteCommand +import org.jetbrains.plugins.gradle.util.GradleConstants +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.blocks.GrClosableBlock +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement +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.util.* -import java.io.File; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; +abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { -public abstract class KotlinWithGradleConfigurator implements KotlinProjectConfigurator { - private static final String VERSION_TEMPLATE = "$VERSION$"; - - public static final String GROUP_ID = "org.jetbrains.kotlin"; - public static final String GRADLE_PLUGIN_ID = "kotlin-gradle-plugin"; - - protected static final String CLASSPATH = "classpath \"" + GROUP_ID + ":" + GRADLE_PLUGIN_ID + ":$kotlin_version\""; - - protected static final String SNAPSHOT_REPOSITORY = "maven {\nurl '" + ConfigureKotlinInProjectUtilsKt.SNAPSHOT_REPOSITORY.getUrl() + "'\n}"; - protected static final String EAP_REPOSITORY = "maven {\nurl '" + ConfigureKotlinInProjectUtilsKt.EAP_REPOSITORY.getUrl() + "'\n}"; - - private static final String MAVEN_CENTRAL = "mavenCentral()\n"; - private static final String JCENTER = "jcenter()\n"; - public static final String LIBRARY = "compile \"org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version\""; - protected static final String SOURCE_SET = "main.java.srcDirs += 'src/main/kotlin'\n"; - private static final String VERSION = String.format("ext.kotlin_version = '%s'", VERSION_TEMPLATE); - - @NotNull - @Override - public ConfigureKotlinStatus getStatus(@NotNull Module module) { + override fun getStatus(module: Module): ConfigureKotlinStatus { if (!isApplicable(module)) { - return ConfigureKotlinStatus.NON_APPLICABLE; + return ConfigureKotlinStatus.NON_APPLICABLE } - if (ConfigureKotlinInProjectUtilsKt.hasKotlinJvmRuntimeInScope(module)) { - return ConfigureKotlinStatus.CONFIGURED; + if (hasKotlinJvmRuntimeInScope(module)) { + return ConfigureKotlinStatus.CONFIGURED } - GroovyFile moduleGradleFile = getBuildGradleFile(module.getProject(), getModuleFilePath(module)); + val moduleGradleFile = getBuildGradleFile(module.project, getModuleFilePath(module)) if (moduleGradleFile != null && !isFileConfigured(moduleGradleFile)) { - return ConfigureKotlinStatus.CAN_BE_CONFIGURED; + return ConfigureKotlinStatus.CAN_BE_CONFIGURED } - GroovyFile projectGradleFile = getBuildGradleFile(module.getProject(), getTopLevelProjectFilePath(module.getProject())); + val projectGradleFile = getBuildGradleFile(module.project, getTopLevelProjectFilePath(module.project)) if (projectGradleFile != null && !isFileConfigured(projectGradleFile)) { - return ConfigureKotlinStatus.CAN_BE_CONFIGURED; + return ConfigureKotlinStatus.CAN_BE_CONFIGURED } - return ConfigureKotlinStatus.BROKEN; + return ConfigureKotlinStatus.BROKEN } - protected abstract boolean isApplicable(@NotNull Module module); + protected abstract fun isApplicable(module: Module): Boolean - private boolean isFileConfigured(GroovyFile projectGradleFile) { - String fileText = projectGradleFile.getText(); - return containsDirective(fileText, getApplyPluginDirective()) && fileText.contains(LIBRARY); + private fun isFileConfigured(projectGradleFile: GroovyFile): Boolean { + val fileText = projectGradleFile.text + return containsDirective(fileText, applyPluginDirective) && fileText.contains(LIBRARY) } - private static boolean containsDirective(@NotNull String fileText, @NotNull String directive) { - return fileText.contains(directive) - || fileText.contains(directive.replace("\"", "'")) - || fileText.contains(directive.replace("'", "\"")); - } + @JvmSuppressWildcards + override fun configure(project: Project, excludeModules: Collection) { + val dialog = ConfigureDialogWithModulesAndVersion(project, this, excludeModules) - @Override - public void configure(@NotNull final Project project, Collection excludeModules) { - final ConfigureDialogWithModulesAndVersion dialog = - new ConfigureDialogWithModulesAndVersion(project, this, excludeModules); + dialog.show() + if (!dialog.isOK) return - dialog.show(); - if (!dialog.isOK()) return; + CommandProcessor.getInstance().executeCommand(project, { + val collector = createConfigureKotlinNotificationCollector(project) + val changedFiles = HashSet() + val projectGradleFile = getBuildGradleFile(project, getTopLevelProjectFilePath(project)) + if (projectGradleFile != null && canConfigureFile(projectGradleFile)) { + val isModified = changeGradleFile(projectGradleFile, true, dialog.kotlinVersion, collector) + if (isModified) { + changedFiles.add(projectGradleFile) + } + } - CommandProcessor.getInstance().executeCommand(project, new Runnable() { - @Override - public void run() { - NotificationMessageCollector collector = NotificationMessageCollectorKt.createConfigureKotlinNotificationCollector(project); - Set changedFiles = new HashSet(); - GroovyFile projectGradleFile = getBuildGradleFile(project, getTopLevelProjectFilePath(project)); - if (projectGradleFile != null && canConfigureFile(projectGradleFile)) { - boolean isModified = changeGradleFile(projectGradleFile, true, dialog.getKotlinVersion(), collector); + for (module in dialog.modulesToConfigure) { + val file = getBuildGradleFile(project, getModuleFilePath(module)) + if (file != null && canConfigureFile(file)) { + val isModified = changeGradleFile(file, false, dialog.kotlinVersion, collector) if (isModified) { - changedFiles.add(projectGradleFile); + changedFiles.add(file) } } - - for (Module module : dialog.getModulesToConfigure()) { - GroovyFile file = getBuildGradleFile(project, getModuleFilePath(module)); - if (file != null && canConfigureFile(file)) { - boolean isModified = changeGradleFile(file, false, dialog.getKotlinVersion(), collector); - if (isModified) { - changedFiles.add(file); - } - } - else { - showErrorMessage(project, "Cannot find build.gradle file for module " + module.getName()); - } - } - - for (GroovyFile file : changedFiles) { - OpenFileAction.openFile(file.getVirtualFile(), project); - } - collector.showNotification(); - } - }, "Configure Kotlin", null); - } - - public static void addKotlinLibraryToModule(final Module module, final DependencyScope scope, final ExternalLibraryDescriptor libraryDescriptor) { - String gradleFilePath = getModuleFilePath(module); - final GroovyFile gradleFile = getBuildGradleFile(module.getProject(), gradleFilePath); - - if (gradleFile != null && canConfigureFile(gradleFile)) { - new WriteCommandAction(gradleFile.getProject()) { - @Override - protected void run(@NotNull Result result) { - String groovyScope; - switch (scope) { - case COMPILE: - groovyScope = "compile"; - break; - case TEST: - if (KotlinPluginUtil.isAndroidGradleModule(module)) { - // TODO we should add testCompile or androidTestCompile - groovyScope = "compile"; - } - else { - groovyScope = "testCompile"; - } - break; - case RUNTIME: - groovyScope = "runtime"; - break; - case PROVIDED: - groovyScope = "compile"; - break; - default: - groovyScope = "compile"; - } - - String dependencyString = String.format( - "%s \"%s:%s:%s\"", - groovyScope, libraryDescriptor.getLibraryGroupId(), libraryDescriptor.getLibraryArtifactId(), - libraryDescriptor.getMaxVersion()); - - GrClosableBlock dependenciesBlock = getDependenciesBlock(gradleFile); - addLastExpressionInBlockIfNeeded(dependencyString, dependenciesBlock); - - CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(gradleFile); - } - }.execute(); - - VirtualFile virtualFile = gradleFile.getVirtualFile(); - if (virtualFile != null) { - NotificationMessageCollectorKt.createConfigureKotlinNotificationCollector(gradleFile.getProject()) - .addMessage(virtualFile.getPath() + " was modified") - .showNotification(); - } - } - } - - @Nullable - public static String getKotlinStdlibVersion(@NotNull Module module) { - String gradleFilePath = getModuleFilePath(module); - GroovyFile gradleFile = getBuildGradleFile(module.getProject(), gradleFilePath); - - if (gradleFile == null) return null; - - String versionProperty = "$kotlin_version"; - GrClosableBlock block = getBuildScriptBlock(gradleFile); - if (block.getText().contains("ext.kotlin_version = ")) { - return versionProperty; - } - - GrStatement[] dependencies = getDependenciesBlock(gradleFile).getStatements(); - String stdlibArtifactPrefix = "org.jetbrains.kotlin:kotlin-stdlib:"; - for (GrStatement dependency : dependencies) { - String dependencyText = dependency.getText(); - int startIndex = dependencyText.indexOf(stdlibArtifactPrefix) + stdlibArtifactPrefix.length(); - int endIndex = dependencyText.length() - 1; - if (startIndex != -1 && endIndex != -1) { - return dependencyText.substring(startIndex, endIndex); - } - } - - return null; - } - - protected static boolean addElementsToProjectFile(@NotNull GroovyFile file, @NotNull String version) { - boolean wasModified; - - GrClosableBlock buildScriptBlock = getBuildScriptBlock(file); - wasModified = addFirstExpressionInBlockIfNeeded(VERSION.replace(VERSION_TEMPLATE, version), buildScriptBlock); - - GrClosableBlock buildScriptRepositoriesBlock = getBuildScriptRepositoriesBlock(file); - if (ConfigureKotlinInProjectUtilsKt.isSnapshot(version)) { - wasModified |= addLastExpressionInBlockIfNeeded(SNAPSHOT_REPOSITORY, buildScriptRepositoriesBlock); - } - else if (ConfigureKotlinInProjectUtilsKt.isEap(version)) { - wasModified |= addLastExpressionInBlockIfNeeded(EAP_REPOSITORY, buildScriptRepositoriesBlock); - } - else if (!isRepositoryConfigured(buildScriptRepositoriesBlock)) { - wasModified |= addLastExpressionInBlockIfNeeded(MAVEN_CENTRAL, buildScriptRepositoriesBlock); - } - - GrClosableBlock buildScriptDependenciesBlock = getBuildScriptDependenciesBlock(file); - wasModified |= addLastExpressionInBlockIfNeeded(CLASSPATH, buildScriptDependenciesBlock); - - return wasModified; - } - - protected boolean addElementsToModuleFile(@NotNull GroovyFile file, @NotNull String version) { - boolean wasModified = false; - - if (!containsDirective(file.getText(), getApplyPluginDirective())) { - GrExpression apply = GroovyPsiElementFactory.getInstance(file.getProject()).createExpressionFromText(getApplyPluginDirective()); - GrApplicationStatement applyStatement = getApplyStatement(file); - if (applyStatement != null) { - file.addAfter(apply, applyStatement); - wasModified = true; - } - else { - GrClosableBlock buildScript = getBlockByName(file, "buildscript"); - if (buildScript != null) { - file.addAfter(apply, buildScript.getParent()); - wasModified = true; - } else { - GrStatement[] statements = file.getStatements(); - if (statements.length > 0) { - file.addAfter(apply, statements[statements.length - 1]); + showErrorMessage(project, "Cannot find build.gradle file for module " + module.name) + } + } + + for (file in changedFiles) { + OpenFileAction.openFile(file.virtualFile, project) + } + collector.showNotification() + }, "Configure Kotlin", null) + } + + protected fun addElementsToModuleFile(file: GroovyFile, version: String): Boolean { + var wasModified = false + + if (!containsDirective(file.text, applyPluginDirective)) { + val apply = GroovyPsiElementFactory.getInstance(file.project).createExpressionFromText(applyPluginDirective) + val applyStatement = getApplyStatement(file) + if (applyStatement != null) { + file.addAfter(apply, applyStatement) + wasModified = true + } + else { + val buildScript = getBlockByName(file, "buildscript") + if (buildScript != null) { + file.addAfter(apply, buildScript.parent) + wasModified = true + } + else { + val statements = file.statements + if (statements.size > 0) { + file.addAfter(apply, statements[statements.size - 1]) } else { - file.addAfter(apply, file.getFirstChild()); + file.addAfter(apply, file.firstChild) } - wasModified = true; + wasModified = true } } } - GrClosableBlock repositoriesBlock = getRepositoriesBlock(file); - if (ConfigureKotlinInProjectUtilsKt.isSnapshot(version)) { - wasModified |= addLastExpressionInBlockIfNeeded(SNAPSHOT_REPOSITORY, repositoriesBlock); + val repositoriesBlock = getRepositoriesBlock(file) + if (isSnapshot(version)) { + wasModified = wasModified or addLastExpressionInBlockIfNeeded(SNAPSHOT_REPOSITORY_SNIPPET, repositoriesBlock) } - else if (ConfigureKotlinInProjectUtilsKt.isEap(version)) { - wasModified |= addLastExpressionInBlockIfNeeded(EAP_REPOSITORY, repositoriesBlock); + else if (isEap(version)) { + wasModified = wasModified or addLastExpressionInBlockIfNeeded(EAP_REPOSITORY_SNIPPET, repositoriesBlock) } else if (!isRepositoryConfigured(repositoriesBlock)) { - wasModified |= addLastExpressionInBlockIfNeeded(MAVEN_CENTRAL, repositoriesBlock); + wasModified = wasModified or addLastExpressionInBlockIfNeeded(MAVEN_CENTRAL, repositoriesBlock) } - GrClosableBlock dependenciesBlock = getDependenciesBlock(file); - wasModified |= addExpressionInBlockIfNeeded(LIBRARY, dependenciesBlock, false); + val dependenciesBlock = getDependenciesBlock(file) + wasModified = wasModified or addExpressionInBlockIfNeeded(LIBRARY, dependenciesBlock, false) - wasModified |= addSourceSetsBlock(file); + wasModified = wasModified or addSourceSetsBlock(file) - return wasModified; + return wasModified } - private static boolean isRepositoryConfigured(GrClosableBlock repositoriesBlock) { - return repositoriesBlock.getText().contains(MAVEN_CENTRAL) || repositoriesBlock.getText().contains(JCENTER); - } + protected abstract val applyPluginDirective: String - protected abstract String getApplyPluginDirective(); + protected abstract fun addSourceSetsBlock(file: GroovyFile): Boolean - protected abstract boolean addSourceSetsBlock(@NotNull GroovyFile file); + protected abstract fun addElementsToFile( + groovyFile: GroovyFile, + isTopLevelProjectFile: Boolean, + version: String + ): Boolean - protected abstract boolean addElementsToFile( - @NotNull GroovyFile groovyFile, - boolean isTopLevelProjectFile, - @NotNull String version - ); + fun changeGradleFile( + groovyFile: GroovyFile, + isTopLevelProjectFile: Boolean, + version: String, + collector: NotificationMessageCollector + ): Boolean { + val isModified = groovyFile.project.executeWriteCommand("Configure build.gradle", null) { + val isModified = addElementsToFile(groovyFile, isTopLevelProjectFile, version) - private static boolean canConfigureFile(@NotNull GroovyFile file) { - return WritingAccessProvider.isPotentiallyWritable(file.getVirtualFile(), null); - } - - @Nullable - private static GroovyFile getBuildGradleFile(Project project, @Nullable String path) { - if (path == null) { - return null; - } - VirtualFile file = VfsUtil.findFileByIoFile(new File(path), true); - if (file == null) { - return null; - } - PsiFile psiFile = PsiManager.getInstance(project).findFile(file); - if (!(psiFile instanceof GroovyFile)) return null; - return (GroovyFile) psiFile; - } - - @NotNull - private static String getTopLevelProjectFilePath(@NotNull Project project) { - return project.getBasePath() + "/" + GradleConstants.DEFAULT_SCRIPT_NAME; - } - - @Nullable - private static String getModuleFilePath(@NotNull Module module) { - String moduleDir = new File(module.getModuleFilePath()).getParent(); - File buildGradleFile = new File(moduleDir + "/" + GradleConstants.DEFAULT_SCRIPT_NAME); - if (buildGradleFile.exists()) { - return buildGradleFile.getPath(); + CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(groovyFile) + isModified } - // since IDEA 145 module file is located in .idea directory - for (VirtualFile file : ModuleRootManager.getInstance(module).getContentRoots()) { - buildGradleFile = new File(file.getPath() + "/" + GradleConstants.DEFAULT_SCRIPT_NAME); + val virtualFile = groovyFile.virtualFile + if (virtualFile != null && isModified) { + collector.addMessage(virtualFile.path + " was modified") + } + return isModified + } + + companion object { + private val VERSION_TEMPLATE = "\$VERSION$" + + val GROUP_ID = "org.jetbrains.kotlin" + val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin" + + val CLASSPATH = "classpath \"$GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\"" + + val SNAPSHOT_REPOSITORY_SNIPPET = "maven {\nurl '" + SNAPSHOT_REPOSITORY.url + "'\n}" + val EAP_REPOSITORY_SNIPPET = "maven {\nurl '" + EAP_REPOSITORY.url + "'\n}" + + private val MAVEN_CENTRAL = "mavenCentral()\n" + private val JCENTER = "jcenter()\n" + val LIBRARY = "compile \"org.jetbrains.kotlin:kotlin-stdlib:\$kotlin_version\"" + val SOURCE_SET = "main.java.srcDirs += 'src/main/kotlin'\n" + private val VERSION = String.format("ext.kotlin_version = '%s'", VERSION_TEMPLATE) + + private fun containsDirective(fileText: String, directive: String): Boolean { + return fileText.contains(directive) + || fileText.contains(directive.replace("\"", "'")) + || fileText.contains(directive.replace("'", "\"")) + } + + fun addKotlinLibraryToModule(module: Module, scope: DependencyScope, libraryDescriptor: ExternalLibraryDescriptor) { + val gradleFilePath = getModuleFilePath(module) + val gradleFile = getBuildGradleFile(module.project, gradleFilePath) + + if (gradleFile != null && canConfigureFile(gradleFile)) { + gradleFile.project.executeWriteCommand("Add Kotlin library") { + val groovyScope: String + when (scope) { + DependencyScope.COMPILE -> groovyScope = "compile" + DependencyScope.TEST -> if (KotlinPluginUtil.isAndroidGradleModule(module)) { + // TODO we should add testCompile or androidTestCompile + groovyScope = "compile" + } + else { + groovyScope = "testCompile" + } + DependencyScope.RUNTIME -> groovyScope = "runtime" + DependencyScope.PROVIDED -> groovyScope = "compile" + else -> groovyScope = "compile" + } + + val dependencyString = String.format( + "%s \"%s:%s:%s\"", + groovyScope, libraryDescriptor.libraryGroupId, libraryDescriptor.libraryArtifactId, + libraryDescriptor.maxVersion) + + val dependenciesBlock = getDependenciesBlock(gradleFile) + addLastExpressionInBlockIfNeeded(dependencyString, dependenciesBlock) + + CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(gradleFile) + } + + val virtualFile = gradleFile.virtualFile + if (virtualFile != null) { + createConfigureKotlinNotificationCollector(gradleFile.project) + .addMessage(virtualFile.path + " was modified") + .showNotification() + } + } + } + + fun getKotlinStdlibVersion(module: Module): String? { + val gradleFilePath = getModuleFilePath(module) + val gradleFile = getBuildGradleFile(module.project, gradleFilePath) ?: return null + + val versionProperty = "\$kotlin_version" + val block = getBuildScriptBlock(gradleFile) + if (block.text.contains("ext.kotlin_version = ")) { + return versionProperty + } + + val dependencies = getDependenciesBlock(gradleFile).statements + 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: GroovyFile, version: String): Boolean { + var wasModified: Boolean + + val buildScriptBlock = getBuildScriptBlock(file) + wasModified = addFirstExpressionInBlockIfNeeded(VERSION.replace(VERSION_TEMPLATE, version), buildScriptBlock) + + val buildScriptRepositoriesBlock = getBuildScriptRepositoriesBlock(file) + if (isSnapshot(version)) { + wasModified = wasModified or addLastExpressionInBlockIfNeeded(SNAPSHOT_REPOSITORY_SNIPPET, buildScriptRepositoriesBlock) + } + else if (isEap(version)) { + wasModified = wasModified or addLastExpressionInBlockIfNeeded(EAP_REPOSITORY_SNIPPET, buildScriptRepositoriesBlock) + } + else if (!isRepositoryConfigured(buildScriptRepositoriesBlock)) { + wasModified = wasModified or addLastExpressionInBlockIfNeeded(MAVEN_CENTRAL, buildScriptRepositoriesBlock) + } + + val buildScriptDependenciesBlock = getBuildScriptDependenciesBlock(file) + wasModified = wasModified or addLastExpressionInBlockIfNeeded(CLASSPATH, buildScriptDependenciesBlock) + + return wasModified + } + + private fun isRepositoryConfigured(repositoriesBlock: GrClosableBlock): Boolean { + return repositoriesBlock.text.contains(MAVEN_CENTRAL) || repositoriesBlock.text.contains(JCENTER) + } + + private fun canConfigureFile(file: GroovyFile): Boolean { + return WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null) + } + + private fun getBuildGradleFile(project: Project, path: String?): GroovyFile? { + if (path == null) { + return null + } + val file = VfsUtil.findFileByIoFile(File(path), true) ?: return null + val psiFile = PsiManager.getInstance(project).findFile(file) as? GroovyFile ?: return null + return psiFile + } + + private fun getTopLevelProjectFilePath(project: Project): String { + return project.basePath + "/" + GradleConstants.DEFAULT_SCRIPT_NAME + } + + private fun getModuleFilePath(module: Module): String? { + val moduleDir = File(module.moduleFilePath).parent + var buildGradleFile = File(moduleDir + "/" + GradleConstants.DEFAULT_SCRIPT_NAME) if (buildGradleFile.exists()) { - return buildGradleFile.getPath(); + return buildGradleFile.path } - } - return null; - } - protected boolean changeGradleFile( - @NotNull final GroovyFile groovyFile, - final boolean isTopLevelProjectFile, - @NotNull final String version, - @NotNull NotificationMessageCollector collector - ) { - final boolean[] isModified = {false}; - new WriteCommandAction(groovyFile.getProject()) { - @Override - protected void run(@NotNull Result result) { - isModified[0] = addElementsToFile(groovyFile, isTopLevelProjectFile, version); - - CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(groovyFile); + // since IDEA 145 module file is located in .idea directory + for (file in ModuleRootManager.getInstance(module).contentRoots) { + buildGradleFile = File(file.path + "/" + GradleConstants.DEFAULT_SCRIPT_NAME) + if (buildGradleFile.exists()) { + return buildGradleFile.path + } } - }.execute(); - - VirtualFile virtualFile = groovyFile.getVirtualFile(); - if (virtualFile != null && isModified[0]) { - collector.addMessage(virtualFile.getPath() + " was modified"); + return null } - return isModified[0]; - } - @NotNull - private static GrClosableBlock getDependenciesBlock(@NotNull GrStatementOwner file) { - return getBlockOrCreate(file, "dependencies"); - } + private fun getDependenciesBlock(file: GrStatementOwner): GrClosableBlock { + return getBlockOrCreate(file, "dependencies") + } - @NotNull - protected static GrClosableBlock getSourceSetsBlock(@NotNull GrStatementOwner parent) { - return getBlockOrCreate(parent, "sourceSets"); - } + fun getSourceSetsBlock(parent: GrStatementOwner): GrClosableBlock { + return getBlockOrCreate(parent, "sourceSets") + } - @NotNull - private static GrClosableBlock getBuildScriptBlock(@NotNull GrStatementOwner file) { - return getBlockOrCreate(file, "buildscript"); - } + private fun getBuildScriptBlock(file: GrStatementOwner): GrClosableBlock { + return getBlockOrCreate(file, "buildscript") + } - @NotNull - private static GrClosableBlock getBuildScriptDependenciesBlock(@NotNull GrStatementOwner file) { - GrClosableBlock buildScript = getBuildScriptBlock(file); - return getBlockOrCreate(buildScript, "dependencies"); - } + private fun getBuildScriptDependenciesBlock(file: GrStatementOwner): GrClosableBlock { + val buildScript = getBuildScriptBlock(file) + return getBlockOrCreate(buildScript, "dependencies") + } - @NotNull - private static GrClosableBlock getBuildScriptRepositoriesBlock(@NotNull GrStatementOwner file) { - GrClosableBlock buildScript = getBuildScriptBlock(file); - return getBlockOrCreate(buildScript, "repositories"); - } + private fun getBuildScriptRepositoriesBlock(file: GrStatementOwner): GrClosableBlock { + val buildScript = getBuildScriptBlock(file) + return getBlockOrCreate(buildScript, "repositories") + } - @NotNull - private static GrClosableBlock getRepositoriesBlock(@NotNull GrStatementOwner file) { - return getBlockOrCreate(file, "repositories"); - } + private fun getRepositoriesBlock(file: GrStatementOwner): GrClosableBlock { + return getBlockOrCreate(file, "repositories") + } - @NotNull - protected static GrClosableBlock getBlockOrCreate(@NotNull GrStatementOwner parent, @NotNull String name) { - GrClosableBlock block = getBlockByName(parent, name); - if (block == null) { - GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(parent.getProject()); - GrExpression newBlock = factory.createExpressionFromText(name + "{\n}\n"); - GrStatement[] statements = parent.getStatements(); - if (statements.length > 0) { - parent.addAfter(newBlock, statements[statements.length - 1]); + 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") + val statements = parent.statements + if (statements.size > 0) { + parent.addAfter(newBlock, statements[statements.size - 1]) + } + else { + parent.addAfter(newBlock, parent.firstChild) + } + block = getBlockByName(parent, name)!! + } + return block + } + + 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? { + val allExpressions = PsiTreeUtil.getChildrenOfType(parent, GrMethodCallExpression::class.java) + if (allExpressions != null) { + for (expression in allExpressions) { + val invokedExpression = expression.invokedExpression + if (expression.closureArguments.size == 0) continue + + val expressionText = invokedExpression.text + if (expressionText == name) return expression.closureArguments[0] + } + } + return null + } + + 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.size > 0) { + val lastStatement = statements[statements.size - 1] + if (lastStatement != null) { + block.addAfter(newStatement, lastStatement) + } } else { - parent.addAfter(newBlock, parent.getFirstChild()); + val firstChild = block.firstChild + if (firstChild != null) { + block.addAfter(newStatement, firstChild) + } } - block = getBlockByName(parent, name); - assert block != null : "Block should be non-null because it is created"; + return true } - return block; - } - protected static boolean addLastExpressionInBlockIfNeeded(@NotNull String text, @NotNull GrClosableBlock block) { - return addExpressionInBlockIfNeeded(text, block, false); - } - - private static boolean addFirstExpressionInBlockIfNeeded(@NotNull String text, @NotNull GrClosableBlock block) { - return addExpressionInBlockIfNeeded(text, block, true); - } - - @Nullable - private static GrClosableBlock getBlockByName(@NotNull PsiElement parent, @NotNull String name) { - GrMethodCallExpression[] allExpressions = PsiTreeUtil.getChildrenOfType(parent, GrMethodCallExpression.class); - if (allExpressions != null) { - for (GrMethodCallExpression expression : allExpressions) { - GrExpression invokedExpression = expression.getInvokedExpression(); - if (expression.getClosureArguments().length == 0) continue; - - String expressionText = invokedExpression.getText(); - if (expressionText.equals(name)) return expression.getClosureArguments()[0]; + private fun getApplyStatement(file: GroovyFile): GrApplicationStatement? { + val applyStatement = PsiTreeUtil.getChildrenOfType(file, GrApplicationStatement::class.java) ?: return null + for (callExpression in applyStatement) { + val invokedExpression = callExpression.invokedExpression + if (invokedExpression.text == "apply") { + return callExpression + } } + return null } - return null; - } - private static boolean addExpressionInBlockIfNeeded(@NotNull String text, @NotNull GrClosableBlock block, boolean isFirst) { - if (block.getText().contains(text)) return false; - GrExpression newStatement = GroovyPsiElementFactory.getInstance(block.getProject()).createExpressionFromText(text); - CodeStyleManager.getInstance(block.getProject()).reformat(newStatement); - GrStatement[] statements = block.getStatements(); - if (!isFirst && statements.length > 0) { - GrStatement lastStatement = statements[statements.length - 1]; - if (lastStatement != null) { - block.addAfter(newStatement, lastStatement); - } + private fun showErrorMessage(project: Project, message: String?) { + Messages.showErrorDialog(project, + "Couldn't configure kotlin-gradle plugin automatically.
" + + (if (message != null) message + "
" else "") + + "
See manual installation instructions here.", + "Configure Kotlin-Gradle Plugin") } - else { - PsiElement firstChild = block.getFirstChild(); - if (firstChild != null) { - block.addAfter(newStatement, firstChild); - } - } - return true; - } - - @Nullable - private static GrApplicationStatement getApplyStatement(@NotNull GroovyFile file) { - GrApplicationStatement[] applyStatement = PsiTreeUtil.getChildrenOfType(file, GrApplicationStatement.class); - if (applyStatement == null) return null; - for (GrApplicationStatement callExpression : applyStatement) { - GrExpression invokedExpression = callExpression.getInvokedExpression(); - if (invokedExpression.getText().equals("apply")) { - return callExpression; - } - } - return null; - } - - private static void showErrorMessage(@NotNull Project project, @Nullable String message) { - Messages.showErrorDialog(project, - "Couldn't configure kotlin-gradle plugin automatically.
" + - (message != null ? (message + "
") : "") + - "
See manual installation instructions here.", - "Configure Kotlin-Gradle Plugin"); } }