"Configure Kotlin in project" handles modules from Gradle source roots

THose modules are now always collapsed to their base modules.
 #KT-11828 Fixed
This commit is contained in:
Dmitry Jemerov
2017-03-10 18:44:46 +01:00
parent b1a65e4c74
commit 1f96ead801
3 changed files with 89 additions and 16 deletions
@@ -33,7 +33,7 @@ abstract class ConfigureKotlinInProjectAction : AnAction() {
override fun actionPerformed(e: AnActionEvent) {
val project = e.project ?: return
val modules = getModulesWithKotlinFiles(project).ifEmpty { project.allModules() }
val modules = getConfigurableModulesWithKotlinFiles(project).ifEmpty { project.allModules() }
if (modules.all(::isModuleConfigured)) {
Messages.showInfoMessage("All modules with Kotlin files are configured", e.presentation.text!!)
return
@@ -18,7 +18,9 @@ package org.jetbrains.kotlin.idea.configuration
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Computable
@@ -71,8 +73,20 @@ fun getModulesWithKotlinFiles(project: Project): Collection<Module> {
return emptyList()
}
return project.allModules().filter { module ->
FileTypeIndex.containsFileOfType(KotlinFileType.INSTANCE, module.getModuleScope(true))
return project.allModules()
.filter { module ->
FileTypeIndex.containsFileOfType(KotlinFileType.INSTANCE, module.getModuleScope(true))
}
}
fun getConfigurableModulesWithKotlinFiles(project: Project): Collection<Module> {
val modules = getModulesWithKotlinFiles(project)
if (modules.isEmpty()) return modules
val pathMap = ModuleManager.getInstance(project).modules.asList().buildExternalPathMap()
return modules.mapTo(HashSet()) { module ->
val externalPath = module.externalProjectPath
if (externalPath == null) module else (pathMap[externalPath] ?: module)
}
}
@@ -85,7 +99,7 @@ fun showConfigureKotlinNotificationIfNeeded(module: Module) {
fun showConfigureKotlinNotificationIfNeeded(project: Project, excludeModules: List<Module> = emptyList()) {
ApplicationManager.getApplication().executeOnPooledThread {
val notificationString = DumbService.getInstance(project).runReadActionInSmartMode(Computable {
val modules = getModulesWithKotlinFiles(project) - excludeModules
val modules = getConfigurableModulesWithKotlinFiles(project) - excludeModules
if (modules.all(::isModuleConfigured)) null else ConfigureKotlinNotification.getNotificationString(project, excludeModules)
})
if (notificationString != null) {
@@ -97,7 +111,7 @@ fun showConfigureKotlinNotificationIfNeeded(project: Project, excludeModules: Li
}
fun getAbleToRunConfigurators(project: Project): Collection<KotlinProjectConfigurator> {
val modules = getModulesWithKotlinFiles(project).ifEmpty { project.allModules() }
val modules = getConfigurableModulesWithKotlinFiles(project).ifEmpty { project.allModules() }
return Extensions.getExtensions(KotlinProjectConfigurator.EP_NAME).filter { configurator ->
modules.any { module -> configurator.getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED }
@@ -113,16 +127,48 @@ fun getConfiguratorByName(name: String): KotlinProjectConfigurator? {
}
fun getNonConfiguredModules(project: Project, configurator: KotlinProjectConfigurator): List<Module> {
return project.allModules().filter { module -> configurator.getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED }
return project.allModules()
.filter { module -> configurator.getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED }
.excludeSourceRootModules()
}
fun Collection<Module>.excludeSourceRootModules(): List<Module> {
val pathMap = buildExternalPathMap()
return filter { it.externalProjectId == null || it.externalProjectPath == null } + pathMap.values
}
fun Collection<Module>.buildExternalPathMap(): Map<String, Module> {
val pathMap = mutableMapOf<String, Module>()
for (module in this) {
val externalId = module.externalProjectId
val externalPath = module.externalProjectPath
if (externalId != null && externalPath != null) {
val previousModule = pathMap[externalPath]
// the module without the source root suffix will have the shortest name
if (previousModule == null || isSourceRootPrefix(externalId, previousModule.externalProjectId!!)) {
pathMap[externalPath] = module
}
}
}
return pathMap
}
private fun isSourceRootPrefix(externalId: String, previousModuleExternalId: String)
= externalId.length < previousModuleExternalId.length && previousModuleExternalId.startsWith(externalId)
val Module.externalProjectId: String?
get() = ExternalSystemApiUtil.getExternalProjectId(this)
val Module.externalProjectPath: String?
get() = ExternalSystemApiUtil.getExternalProjectPath(this)
fun getNonConfiguredModulesWithKotlinFiles(project: Project, configurator: KotlinProjectConfigurator): List<Module> {
val modules = getModulesWithKotlinFiles(project)
val modules = getConfigurableModulesWithKotlinFiles(project)
return modules.filter { module -> configurator.getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED }
}
fun getNonConfiguredModules(project: Project, excludeModules: Collection<Module> = emptyList()): Collection<Module> {
val modulesWithKotlinFiles = getModulesWithKotlinFiles(project) - excludeModules
val modulesWithKotlinFiles = getConfigurableModulesWithKotlinFiles(project) - excludeModules
val ableToRunConfigurators = getAbleToRunConfigurators(project)
return modulesWithKotlinFiles.filter { module ->
ableToRunConfigurators.any { it.getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED }
@@ -20,15 +20,14 @@ import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.fileEditor.impl.LoadTextUtil
import com.intellij.openapi.module.ModuleManager
import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinStatus
import org.jetbrains.kotlin.idea.configuration.KotlinGradleModuleConfigurator
import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator
import org.jetbrains.kotlin.idea.configuration.createConfigureKotlinNotificationCollector
import org.jetbrains.kotlin.idea.configuration.*
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.test.testFramework.runInEdtAndWait
import org.jetbrains.kotlin.test.testFramework.runWriteAction
import org.junit.Test
class GradleConfiguratorTest : GradleImportingTestCase() {
@Test
fun testProjectWithModule() {
createProjectSubFile("settings.gradle", "include ':app'")
@@ -58,8 +57,7 @@ class GradleConfiguratorTest : GradleImportingTestCase() {
myProject.baseDir.createChildData(null, "build.gradle")
val module = ModuleManager.getInstance(myProject).findModuleByName("app")!!
val configurator = Extensions.findExtension(KotlinProjectConfigurator.EP_NAME,
KotlinGradleModuleConfigurator::class.java)
val configurator = findGradleModuleConfigurator()
// We have a Kotlin runtime in build.gradle but not in the classpath, so it doesn't make sense
// to suggest configuring it
assertEquals(ConfigureKotlinStatus.BROKEN, configurator.getStatus(module))
@@ -84,8 +82,7 @@ class GradleConfiguratorTest : GradleImportingTestCase() {
runInEdtAndWait {
runWriteAction {
val module = ModuleManager.getInstance(myProject).findModuleByName("app")!!
val configurator = Extensions.findExtension(KotlinProjectConfigurator.EP_NAME,
KotlinGradleModuleConfigurator::class.java)
val configurator = findGradleModuleConfigurator()
val collector = createConfigureKotlinNotificationCollector(myProject)
configurator.configureWithVersion(myProject, listOf(module), "1.0.6", collector)
@@ -113,4 +110,34 @@ class GradleConfiguratorTest : GradleImportingTestCase() {
}
}
}
private fun findGradleModuleConfigurator() = Extensions.findExtension(KotlinProjectConfigurator.EP_NAME,
KotlinGradleModuleConfigurator::class.java)
@Test
fun testListNonConfiguredModules() {
createProjectSubFile("settings.gradle", "include ':app'")
createProjectSubFile("app/build.gradle", """
buildscript {
repositories {
jcenter()
mavenCentral()
}
}
apply plugin: 'java'
""".trimIndent())
createProjectSubFile("app/src/main/java/foo.kt", "")
importProject()
runReadAction {
val configurator = findGradleModuleConfigurator()
val moduleNames = getNonConfiguredModules(myProject, configurator).map { it.name }
assertSameElements(moduleNames, "app", "project")
val moduleNamesWithKotlinFiles = getNonConfiguredModulesWithKotlinFiles(myProject, configurator).map { it.name }
assertSameElements(moduleNamesWithKotlinFiles, "app")
}
}
}