Show popup about too old bundled compiler in Gradle and Maven (KT-25546)

This commit is contained in:
Nikolay Krasko
2018-07-18 13:41:08 +03:00
parent d27002827e
commit 4be5c395aa
10 changed files with 254 additions and 11 deletions
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.facet
import com.intellij.facet.Facet
import com.intellij.facet.FacetManager
import com.intellij.facet.FacetTypeRegistry
import com.intellij.openapi.module.Module
class KotlinFacet(
@@ -21,4 +20,4 @@ class KotlinFacet(
return FacetManager.getInstance(module).getFacetByType<KotlinFacet>(KotlinFacetType.TYPE_ID)
}
}
}
}
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
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.Assert
import org.junit.Ignore
import org.junit.Test
@@ -61,6 +62,17 @@ class GradleConfiguratorTest : GradleImportingTestCase() {
assertEquals(ConfigureKotlinStatus.BROKEN, findJsGradleModuleConfigurator().getStatus(moduleGroup))
}
}
Assert.assertEquals(
"""
<p>The compiler bundled to Kotlin plugin (1.0.0) is older than external compiler used for building modules:</p>
<ul>
<li>app (1.1.0)</li>
</ul>
<p>This may cause different set of errors and warnings reported in IDE.</p>
<p><a href="update">Update</a> <a href="ignore">Ignore</a></p>
""".trimIndent().lines().joinToString(separator = ""),
createOutdatedBundledCompilerMessage(myProject, "1.0.0"))
}
@Test
@@ -21,14 +21,13 @@ import com.intellij.notification.NotificationDisplayType
import com.intellij.notification.NotificationsConfiguration
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.AbstractProjectComponent
import com.intellij.openapi.externalSystem.service.project.manage.ProjectDataImportListener
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModuleRootEvent
import com.intellij.openapi.roots.ModuleRootListener
import com.intellij.openapi.startup.StartupManager
import org.jetbrains.kotlin.idea.configuration.checkHideNonConfiguredNotifications
import org.jetbrains.kotlin.idea.configuration.getModulesWithKotlinFiles
import org.jetbrains.kotlin.idea.configuration.showConfigureKotlinNotificationIfNeeded
import org.jetbrains.kotlin.idea.configuration.*
import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies
import org.jetbrains.kotlin.idea.versions.collectModulesWithOutdatedRuntime
import org.jetbrains.kotlin.idea.versions.findOutdatedKotlinLibraries
@@ -65,6 +64,10 @@ class KotlinConfigurationCheckerComponent(project: Project) : AbstractProjectCom
checkHideNonConfiguredNotifications(project)
}
})
connection.subscribe(ProjectDataImportListener.TOPIC, ProjectDataImportListener {
notifyOutdatedBundledCompilerIfNecessary(project)
})
}
override fun projectOpened() {
@@ -0,0 +1,23 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.maven
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import org.jetbrains.idea.maven.project.MavenImportListener
import org.jetbrains.idea.maven.project.MavenProject
import org.jetbrains.kotlin.idea.configuration.notifyOutdatedBundledCompilerIfNecessary
class MavenImportListener(val project: Project) {
init {
project.messageBus.connect().subscribe(
MavenImportListener.TOPIC,
MavenImportListener { _: Collection<MavenProject>, _: List<Module> ->
notifyOutdatedBundledCompilerIfNecessary(project)
}
)
}
}
+6
View File
@@ -1,4 +1,10 @@
<idea-plugin>
<project-components>
<component>
<implementation-class>org.jetbrains.kotlin.idea.maven.MavenImportListener</implementation-class>
</component>
</project-components>
<extensions defaultExtensionNs="org.jetbrains.kotlin">
<projectConfigurator implementation="org.jetbrains.kotlin.idea.maven.configuration.KotlinJavaMavenConfigurator"/>
<projectConfigurator implementation="org.jetbrains.kotlin.idea.maven.configuration.KotlinJavascriptMavenConfigurator"/>
@@ -27,4 +27,8 @@ class ConfigurePluginUpdatesAction : DumbAwareAction() {
val project = e.getData(CommonDataKeys.PROJECT)
ShowSettingsUtilImpl.showSettingsDialog(project, KotlinUpdatesSettingsConfigurable.ID, "")
}
companion object {
val ACTION_ID = "KotlinConfigureUpdates"
}
}
@@ -0,0 +1,187 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.configuration
import com.intellij.ide.DataManager
import com.intellij.ide.util.PropertiesComponent
import com.intellij.notification.Notification
import com.intellij.notification.NotificationListener
import com.intellij.notification.NotificationType
import com.intellij.notification.Notifications
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.config.KotlinCompilerVersion
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.actions.ConfigurePluginUpdatesAction
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.psi.UserDataProperty
import javax.swing.event.HyperlinkEvent
var Module.externalCompilerVersion: String? by UserDataProperty(Key.create("EXTERNAL_COMPILER_VERSION"))
fun notifyOutdatedBundledCompilerIfNecessary(project: Project) {
val pluginVersion = KotlinPluginUtil.getPluginVersion()
if (pluginVersion == PropertiesComponent.getInstance(project).getValue(SUPPRESSED_OUTDATED_COMPILER_PROPERTY_NAME)) {
return
}
val message: String = createOutdatedBundledCompilerMessage(project) ?: return
if (ApplicationManager.getApplication().isUnitTestMode) {
return
}
Notifications.Bus.notify(
Notification(
OUTDATED_BUNDLED_COMPILER_GROUP_DISPLAY_ID, OUTDATED_BUNDLED_COMPILER_GROUP_DISPLAY_ID, message,
NotificationType.WARNING, NotificationListener { notification, event ->
if (event.eventType == HyperlinkEvent.EventType.ACTIVATED) {
when {
"update" == event.description -> {
val action = ActionManager.getInstance().getAction(ConfigurePluginUpdatesAction.ACTION_ID)
val dataContext = DataManager.getInstance().dataContextFromFocus.result
val actionEvent = AnActionEvent.createFromAnAction(action, null, ActionPlaces.ACTION_SEARCH, dataContext)
action.actionPerformed(actionEvent)
}
"ignore" == event.description -> {
if (!project.isDisposed) {
PropertiesComponent.getInstance(project).setValue(SUPPRESSED_OUTDATED_COMPILER_PROPERTY_NAME, pluginVersion)
}
}
else -> {
throw AssertionError()
}
}
notification.expire()
}
}
),
project
)
}
fun createOutdatedBundledCompilerMessage(project: Project, bundledCompilerVersion: String = KotlinCompilerVersion.VERSION): String? {
val bundledCompilerMajorVersion = MajorVersion.create(bundledCompilerVersion) ?: return null
val usedCompilerInfo = ArrayList<ModuleCompilerInfo>()
for (module in ModuleManager.getInstance(project).modules) {
val externalCompilerVersion = module.externalCompilerVersion ?: continue
val externalCompilerMajorVersion = MajorVersion.create(externalCompilerVersion) ?: continue
usedCompilerInfo.add(
ModuleCompilerInfo(
module,
externalCompilerVersion,
externalCompilerMajorVersion = externalCompilerMajorVersion,
languageMajorVersion = MajorVersion.create(module.languageVersionSettings.languageVersion)
)
)
}
val selectedBaseModules = HashSet<Module>()
val selectedNewerModulesInfos = ArrayList<ModuleCompilerInfo>()
val moduleSourceRootMap = ModuleSourceRootMap(project)
for (moduleCompilerInfo in usedCompilerInfo) {
val languageMajorVersion = moduleCompilerInfo.languageMajorVersion
val externalCompilerMajorVersion = moduleCompilerInfo.externalCompilerMajorVersion
if (externalCompilerMajorVersion > bundledCompilerMajorVersion && languageMajorVersion > bundledCompilerMajorVersion) {
val wholeModuleGroup = moduleSourceRootMap.getWholeModuleGroup(moduleCompilerInfo.module)
if (!selectedBaseModules.contains(wholeModuleGroup.baseModule)) {
// Remap to base module
selectedNewerModulesInfos.add(
ModuleCompilerInfo(
wholeModuleGroup.baseModule,
moduleCompilerInfo.externalCompilerVersion,
externalCompilerMajorVersion = externalCompilerMajorVersion,
languageMajorVersion = languageMajorVersion
)
)
selectedBaseModules.add(wholeModuleGroup.baseModule)
}
}
if (selectedNewerModulesInfos.size > NUMBER_OF_MODULES_TO_SHOW) {
break
}
}
if (selectedNewerModulesInfos.isEmpty()) {
return null
}
var modulesStr =
selectedNewerModulesInfos.take(NUMBER_OF_MODULES_TO_SHOW).joinToString(separator = "") {
"<li>${it.module.name} (${it.externalCompilerVersion})</li><br/>"
}
if (selectedNewerModulesInfos.size > NUMBER_OF_MODULES_TO_SHOW) {
modulesStr += "<li> ... </li>"
}
// <br/> are going to be replaced to \n for the `Event Log` view. Remove last <br/>, to avoid additional empty line.
modulesStr = modulesStr.removeSuffix("<br/>")
return """
<p>The compiler bundled to Kotlin plugin ($bundledCompilerVersion) is older than external compiler used for building modules:</p>
<ul>$modulesStr</ul>
<p>This may cause different set of errors and warnings reported in IDE.</p>
<p><a href="update">Update</a> <a href="ignore">Ignore</a></p>"""
.trimIndent().lines().joinToString(separator = "").replace("<br/>", "\n")
}
private class ModuleCompilerInfo(
val module: Module,
val externalCompilerVersion: String,
val externalCompilerMajorVersion: MajorVersion,
val languageMajorVersion: MajorVersion)
private data class MajorVersion(val major: Int, val minor: Int) : Comparable<MajorVersion> {
override fun compareTo(other: MajorVersion): Int {
if (major > other.major) return 1
if (major < other.major) return -1
if (minor > other.minor) return 1
if (minor < other.minor) return -1
return 0
}
override fun toString(): String = "$major.$minor"
companion object {
fun create(languageVersion: LanguageVersion): MajorVersion {
return MajorVersion(languageVersion.major, languageVersion.minor)
}
fun create(versionStr: String): MajorVersion? {
if (versionStr == "@snapshot@") {
return MajorVersion(Int.MAX_VALUE, Int.MAX_VALUE)
}
val regex = "(\\d+)\\.(\\d+).*".toRegex()
val matchResult = regex.matchEntire(versionStr) ?: return null
val major: Int = matchResult.groupValues[1].toInt()
val minor: Int = matchResult.groupValues[2].toInt()
return MajorVersion(major, minor)
}
}
}
private const val NUMBER_OF_MODULES_TO_SHOW = 2
private const val SUPPRESSED_OUTDATED_COMPILER_PROPERTY_NAME = "oudtdated.bundled.kotlin.compiler"
private const val OUTDATED_BUNDLED_COMPILER_GROUP_DISPLAY_ID = "Outdated Bundled Kotlin Compiler"
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JsCompilerArgumen
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
import org.jetbrains.kotlin.idea.configuration.externalCompilerVersion
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.versions.*
@@ -57,7 +58,7 @@ fun KotlinFacetSettings.initializeIfNeeded(
module: Module,
rootModel: ModuleRootModel?,
platformKind: TargetPlatformKind<*>? = null, // if null, detect by module dependencies
languageVersion: String? = null
compilerVersion: String? = null
) {
val project = module.project
@@ -80,7 +81,7 @@ fun KotlinFacetSettings.initializeIfNeeded(
if (shouldInferLanguageLevel) {
languageLevel = (if (useProjectSettings) LanguageVersion.fromVersionString(commonArguments.languageVersion) else null)
?: getDefaultLanguageLevel(module, languageVersion)
?: getDefaultLanguageLevel(module, compilerVersion)
}
if (shouldInferAPILevel) {
@@ -162,6 +163,8 @@ fun KotlinFacet.configureFacet(
}
this.coroutineSupport = coroutineSupport
}
module.externalCompilerVersion = compilerVersion
}
fun KotlinFacet.noVersionAutoAdvance() {
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JsCompilerArgumen
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
import org.jetbrains.kotlin.idea.configuration.externalCompilerVersion
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.versions.*
@@ -57,7 +58,7 @@ fun KotlinFacetSettings.initializeIfNeeded(
module: Module,
rootModel: ModuleRootModel?,
platformKind: TargetPlatformKind<*>? = null, // if null, detect by module dependencies
languageVersion: String? = null
compilerVersion: String? = null
) {
val project = module.project
@@ -80,7 +81,7 @@ fun KotlinFacetSettings.initializeIfNeeded(
if (shouldInferLanguageLevel) {
languageLevel = (if (useProjectSettings) LanguageVersion.fromVersionString(commonArguments.languageVersion) else null)
?: getDefaultLanguageLevel(module, languageVersion)
?: getDefaultLanguageLevel(module, compilerVersion)
}
if (shouldInferAPILevel) {
@@ -162,6 +163,8 @@ fun KotlinFacet.configureFacet(
}
this.coroutineSupport = coroutineSupport
}
module.externalCompilerVersion = compilerVersion
}
fun KotlinFacet.noVersionAutoAdvance() {
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JsCompilerArgumen
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
import org.jetbrains.kotlin.idea.configuration.externalCompilerVersion
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.versions.*
@@ -57,7 +58,7 @@ fun KotlinFacetSettings.initializeIfNeeded(
module: Module,
rootModel: ModuleRootModel?,
platformKind: TargetPlatformKind<*>? = null, // if null, detect by module dependencies
languageVersion: String? = null
compilerVersion: String? = null
) {
val project = module.project
@@ -80,7 +81,7 @@ fun KotlinFacetSettings.initializeIfNeeded(
if (shouldInferLanguageLevel) {
languageLevel = (if (useProjectSettings) LanguageVersion.fromVersionString(commonArguments.languageVersion) else null)
?: getDefaultLanguageLevel(module, languageVersion)
?: getDefaultLanguageLevel(module, compilerVersion)
}
if (shouldInferAPILevel) {
@@ -162,6 +163,8 @@ fun KotlinFacet.configureFacet(
}
this.coroutineSupport = coroutineSupport
}
module.externalCompilerVersion = compilerVersion
}
fun KotlinFacet.noVersionAutoAdvance() {