diff --git a/idea/src/org/jetbrains/kotlin/idea/KotlinPluginUpdater.kt b/idea/src/org/jetbrains/kotlin/idea/KotlinPluginUpdater.kt
index 34598511d1c..fdf500779cb 100644
--- a/idea/src/org/jetbrains/kotlin/idea/KotlinPluginUpdater.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/KotlinPluginUpdater.kt
@@ -42,17 +42,35 @@ import com.intellij.util.Alarm
import com.intellij.util.io.HttpRequests
import com.intellij.util.text.VersionComparatorUtil
import java.io.File
+import java.io.PrintWriter
+import java.io.StringWriter
import java.net.URLEncoder
import java.util.concurrent.TimeUnit
sealed class PluginUpdateStatus {
object LatestVersionInstalled : PluginUpdateStatus()
- class Update(val newVersion: String,
- val descriptorToInstall: IdeaPluginDescriptor,
+ class Update(val pluginDescriptor: IdeaPluginDescriptor,
val hostToInstallFrom: String?) : PluginUpdateStatus()
- class CheckFailed(val message: String) : PluginUpdateStatus()
+ class CheckFailed(val message: String, val detail: String? = null) : PluginUpdateStatus()
+
+ fun mergeWith(other: PluginUpdateStatus): PluginUpdateStatus {
+ if (other is Update && (this is LatestVersionInstalled ||
+ (this is Update && VersionComparatorUtil.compare(other.pluginDescriptor.version,
+ pluginDescriptor.version) > 0))) {
+ return other
+ }
+ return this
+ }
+
+ companion object {
+ fun fromException(message: String, e: Exception): PluginUpdateStatus {
+ val writer = StringWriter()
+ e.printStackTrace(PrintWriter(writer))
+ return CheckFailed(message, writer.toString())
+ }
+ }
}
class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Disposable {
@@ -69,8 +87,9 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
val lastUpdateTime = java.lang.Long.parseLong(propertiesComponent.getValue(PROPERTY_NAME, "0"))
if (lastUpdateTime == 0L || System.currentTimeMillis() - lastUpdateTime > TimeUnit.DAYS.toMillis(1)) {
queueUpdateCheck { updateStatus ->
- if (updateStatus is PluginUpdateStatus.Update) {
- notifyPluginUpdateAvailable(updateStatus)
+ when (updateStatus) {
+ is PluginUpdateStatus.Update -> notifyPluginUpdateAvailable(updateStatus)
+ is PluginUpdateStatus.CheckFailed -> LOG.info("Plugin update check failed: ${updateStatus.message}, details: ${updateStatus.detail}")
}
true
}
@@ -86,61 +105,37 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
}
}
- private fun updateCheck(callback: (PluginUpdateStatus) -> Boolean) {
- try {
- var (mainRepoUpdateSuccess, latestVersionInRepository) = getPluginVersionFromMainRepository()
- var descriptorToInstall: IdeaPluginDescriptor? = initPluginDescriptor(latestVersionInRepository)
- var hostToInstallFrom: String? = null
-
- for (host in RepositoryHelper.getPluginHosts().filterNotNull()) {
- val plugins = try {
- RepositoryHelper.loadPlugins(host, null)
- }
- catch(e: Exception) {
- LOG.info("Checking custom plugin repository $host failed", e)
- continue
- }
-
- val kotlinPlugin = plugins.find { it.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID }
- if (kotlinPlugin != null && VersionComparatorUtil.compare(kotlinPlugin.version, latestVersionInRepository) > 0) {
- latestVersionInRepository = kotlinPlugin.version
- descriptorToInstall = kotlinPlugin
- hostToInstallFrom = host
- }
- }
-
- checkQueued = false
-
- if (mainRepoUpdateSuccess || latestVersionInRepository != null) {
- recordSuccessfulUpdateCheck()
- if (latestVersionInRepository != null && VersionComparatorUtil.compare(latestVersionInRepository, KotlinPluginUtil.getPluginVersion()) > 0) {
- ApplicationManager.getApplication().invokeLater({
- callback(PluginUpdateStatus.Update(latestVersionInRepository!!, descriptorToInstall!!, hostToInstallFrom))
- }, ModalityState.any())
- }
- else {
- ApplicationManager.getApplication().invokeLater({
- callback(PluginUpdateStatus.LatestVersionInstalled)
- }, ModalityState.any())
- }
- }
- else {
- ApplicationManager.getApplication().invokeLater {
- if (callback(PluginUpdateStatus.CheckFailed("Plugin not found in repository"))) queueUpdateCheck(callback)
- }
- }
- }
- catch(e: Exception) {
- LOG.info("Kotlin plugin update check failed", e)
- checkQueued = false
- ApplicationManager.getApplication().invokeLater {
- if (callback(PluginUpdateStatus.CheckFailed(e.message ?: "Unknown error"))) queueUpdateCheck(callback)
- }
+ fun runUpdateCheck(callback: (PluginUpdateStatus) -> Boolean) {
+ ApplicationManager.getApplication().executeOnPooledThread {
+ updateCheck(callback)
}
}
- private fun initPluginDescriptor(newVersion: String?): IdeaPluginDescriptor? {
- if (newVersion == null) return null
+ private fun updateCheck(callback: (PluginUpdateStatus) -> Boolean) {
+ var updateStatus: PluginUpdateStatus
+ try {
+ updateStatus = checkUpdatesInMainRepository()
+
+ for (host in RepositoryHelper.getPluginHosts().filterNotNull()) {
+ val customUpdateStatus = checkUpdatesInCustomRepository(host)
+ updateStatus = updateStatus.mergeWith(customUpdateStatus)
+ }
+ }
+ catch(e: Exception) {
+ updateStatus = PluginUpdateStatus.fromException("Kotlin plugin update check failed", e)
+ }
+
+ checkQueued = false
+
+ if (updateStatus !is PluginUpdateStatus.CheckFailed) {
+ recordSuccessfulUpdateCheck()
+ }
+ ApplicationManager.getApplication().invokeLater({
+ callback(updateStatus)
+ }, ModalityState.any())
+ }
+
+ private fun initPluginDescriptor(newVersion: String): IdeaPluginDescriptor {
val originalPlugin = PluginManager.getPlugin(KotlinPluginUtil.KOTLIN_PLUGIN_ID)!!
return PluginNode(KotlinPluginUtil.KOTLIN_PLUGIN_ID).apply {
version = newVersion
@@ -149,31 +144,48 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
}
}
- data class RepositoryCheckResult(val success: Boolean, val newVersion: String?)
-
- fun getPluginVersionFromMainRepository(): RepositoryCheckResult {
+ fun checkUpdatesInMainRepository(): PluginUpdateStatus {
val buildNumber = ApplicationInfo.getInstance().build.asString()
- val pluginVersion = KotlinPluginUtil.getPluginVersion()
+ val currentVersion = KotlinPluginUtil.getPluginVersion()
val os = URLEncoder.encode(SystemInfo.OS_NAME + " " + SystemInfo.OS_VERSION, CharsetToolkit.UTF8)
val uid = UpdateChecker.getInstallationUID(propertiesComponent)
- val url = "https://plugins.jetbrains.com/plugins/list?pluginId=6954&build=$buildNumber&pluginVersion=$pluginVersion&os=$os&uuid=$uid"
+ val url = "https://plugins.jetbrains.com/plugins/list?pluginId=6954&build=$buildNumber&pluginVersion=$currentVersion&os=$os&uuid=$uid"
val responseDoc = HttpRequests.request(url).connect {
JDOMUtil.load(it.inputStream)
}
if (responseDoc.name != "plugin-repository") {
- LOG.info("Unexpected plugin repository response: ${JDOMUtil.writeElement(responseDoc, "\n")}")
- return RepositoryCheckResult(false, null)
+ return PluginUpdateStatus.CheckFailed("Unexpected plugin repository response", JDOMUtil.writeElement(responseDoc, "\n"))
}
if (responseDoc.children.isEmpty()) {
// No plugin version compatible with current IDEA build; don't retry updates
- return RepositoryCheckResult(true, null)
+ return PluginUpdateStatus.LatestVersionInstalled
}
- val version = responseDoc.getChild("category")?.getChild("idea-plugin")?.getChild("version")?.text
- if (version == null) {
- LOG.info("Couldn't find plugin version in repository response: ${JDOMUtil.writeElement(responseDoc, "\n")}")
- return RepositoryCheckResult(false, null)
+ val newVersion = responseDoc.getChild("category")?.getChild("idea-plugin")?.getChild("version")?.text
+ if (newVersion == null) {
+ return PluginUpdateStatus.CheckFailed("Couldn't find plugin version in repository response", JDOMUtil.writeElement(responseDoc, "\n"))
}
- return RepositoryCheckResult(true, version)
+ val pluginDescriptor = initPluginDescriptor(newVersion)
+ return updateIfNotLatest(pluginDescriptor, null)
+ }
+
+ private fun checkUpdatesInCustomRepository(host: String): PluginUpdateStatus {
+ val plugins = try {
+ RepositoryHelper.loadPlugins(host, null)
+ }
+ catch(e: Exception) {
+ return PluginUpdateStatus.fromException("Checking custom plugin repository $host failed", e)
+ }
+
+ val kotlinPlugin = plugins.find { it.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID } ?: return PluginUpdateStatus.LatestVersionInstalled
+ return updateIfNotLatest(kotlinPlugin, host)
+ }
+
+ private fun updateIfNotLatest(kotlinPlugin: IdeaPluginDescriptor, host: String?): PluginUpdateStatus {
+ if (VersionComparatorUtil.compare(kotlinPlugin.version, KotlinPluginUtil.getPluginVersion()) <= 0) {
+ return PluginUpdateStatus.LatestVersionInstalled
+ }
+
+ return PluginUpdateStatus.Update(kotlinPlugin, host)
}
private fun recordSuccessfulUpdateCheck() {
@@ -184,7 +196,7 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
private fun notifyPluginUpdateAvailable(update: PluginUpdateStatus.Update) {
val notification = notificationGroup.createNotification(
"Kotlin",
- "A new version ${update.newVersion} of the Kotlin plugin is available. Install",
+ "A new version ${update.pluginDescriptor.version} of the Kotlin plugin is available. Install",
NotificationType.INFORMATION) { notification, event ->
notification.expire()
installPluginUpdate(update) {
@@ -197,7 +209,7 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
fun installPluginUpdate(update: PluginUpdateStatus.Update,
cancelCallback: () -> Unit = {}) {
- val descriptor = update.descriptorToInstall
+ val descriptor = update.pluginDescriptor
val pluginDownloader = PluginDownloader.createDownloader(descriptor, update.hostToInstallFrom, null)
ProgressManager.getInstance().run(object : Task.Backgroundable(null, "Downloading plugins", true) {
override fun run(indicator: ProgressIndicator) {
diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/ConfigurePluginUpdatesAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/ConfigurePluginUpdatesAction.kt
index 5728b29f266..c7d4d879ff5 100644
--- a/idea/src/org/jetbrains/kotlin/idea/actions/ConfigurePluginUpdatesAction.kt
+++ b/idea/src/org/jetbrains/kotlin/idea/actions/ConfigurePluginUpdatesAction.kt
@@ -46,7 +46,7 @@ class ConfigurePluginUpdatesDialog(project: Project) : DialogWrapper(project, fa
saveSettings()
form.updateCheckProgressIcon.resume()
resetUpdateStatus()
- KotlinPluginUpdater.getInstance().queueUpdateCheck() { pluginUpdateStatus ->
+ KotlinPluginUpdater.getInstance().runUpdateCheck{ pluginUpdateStatus ->
form.updateCheckProgressIcon.suspend()
when (pluginUpdateStatus) {
PluginUpdateStatus.LatestVersionInstalled ->
@@ -55,7 +55,7 @@ class ConfigurePluginUpdatesDialog(project: Project) : DialogWrapper(project, fa
is PluginUpdateStatus.Update -> {
update = pluginUpdateStatus
form.installButton.isVisible = true
- form.updateStatusLabel.text = "A new version ${pluginUpdateStatus.newVersion} is available"
+ form.updateStatusLabel.text = "A new version ${pluginUpdateStatus.pluginDescriptor.version} is available"
}
is PluginUpdateStatus.CheckFailed ->