Skip to content

Commit 63dd0fc

Browse files
committed
streamlined plugin update logic
1 parent 765d58b commit 63dd0fc

File tree

2 files changed

+79
-67
lines changed

2 files changed

+79
-67
lines changed

idea/src/org/jetbrains/kotlin/idea/KotlinPluginUpdater.kt

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,35 @@ import com.intellij.util.Alarm
4242
import com.intellij.util.io.HttpRequests
4343
import com.intellij.util.text.VersionComparatorUtil
4444
import java.io.File
45+
import java.io.PrintWriter
46+
import java.io.StringWriter
4547
import java.net.URLEncoder
4648
import java.util.concurrent.TimeUnit
4749

4850
sealed class PluginUpdateStatus {
4951
object LatestVersionInstalled : PluginUpdateStatus()
5052

51-
class Update(val newVersion: String,
52-
val descriptorToInstall: IdeaPluginDescriptor,
53+
class Update(val pluginDescriptor: IdeaPluginDescriptor,
5354
val hostToInstallFrom: String?) : PluginUpdateStatus()
5455

55-
class CheckFailed(val message: String) : PluginUpdateStatus()
56+
class CheckFailed(val message: String, val detail: String? = null) : PluginUpdateStatus()
57+
58+
fun mergeWith(other: PluginUpdateStatus): PluginUpdateStatus {
59+
if (other is Update && (this is LatestVersionInstalled ||
60+
(this is Update && VersionComparatorUtil.compare(other.pluginDescriptor.version,
61+
pluginDescriptor.version) > 0))) {
62+
return other
63+
}
64+
return this
65+
}
66+
67+
companion object {
68+
fun fromException(message: String, e: Exception): PluginUpdateStatus {
69+
val writer = StringWriter()
70+
e.printStackTrace(PrintWriter(writer))
71+
return CheckFailed(message, writer.toString())
72+
}
73+
}
5674
}
5775

5876
class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Disposable {
@@ -69,8 +87,9 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
6987
val lastUpdateTime = java.lang.Long.parseLong(propertiesComponent.getValue(PROPERTY_NAME, "0"))
7088
if (lastUpdateTime == 0L || System.currentTimeMillis() - lastUpdateTime > TimeUnit.DAYS.toMillis(1)) {
7189
queueUpdateCheck { updateStatus ->
72-
if (updateStatus is PluginUpdateStatus.Update) {
73-
notifyPluginUpdateAvailable(updateStatus)
90+
when (updateStatus) {
91+
is PluginUpdateStatus.Update -> notifyPluginUpdateAvailable(updateStatus)
92+
is PluginUpdateStatus.CheckFailed -> LOG.info("Plugin update check failed: ${updateStatus.message}, details: ${updateStatus.detail}")
7493
}
7594
true
7695
}
@@ -86,61 +105,37 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
86105
}
87106
}
88107

108+
fun runUpdateCheck(callback: (PluginUpdateStatus) -> Boolean) {
109+
ApplicationManager.getApplication().executeOnPooledThread {
110+
updateCheck(callback)
111+
}
112+
}
113+
89114
private fun updateCheck(callback: (PluginUpdateStatus) -> Boolean) {
115+
var updateStatus: PluginUpdateStatus
90116
try {
91-
var (mainRepoUpdateSuccess, latestVersionInRepository) = getPluginVersionFromMainRepository()
92-
var descriptorToInstall: IdeaPluginDescriptor? = initPluginDescriptor(latestVersionInRepository)
93-
var hostToInstallFrom: String? = null
117+
updateStatus = checkUpdatesInMainRepository()
94118

95119
for (host in RepositoryHelper.getPluginHosts().filterNotNull()) {
96-
val plugins = try {
97-
RepositoryHelper.loadPlugins(host, null)
98-
}
99-
catch(e: Exception) {
100-
LOG.info("Checking custom plugin repository $host failed", e)
101-
continue
102-
}
103-
104-
val kotlinPlugin = plugins.find { it.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID }
105-
if (kotlinPlugin != null && VersionComparatorUtil.compare(kotlinPlugin.version, latestVersionInRepository) > 0) {
106-
latestVersionInRepository = kotlinPlugin.version
107-
descriptorToInstall = kotlinPlugin
108-
hostToInstallFrom = host
109-
}
110-
}
111-
112-
checkQueued = false
113-
114-
if (mainRepoUpdateSuccess || latestVersionInRepository != null) {
115-
recordSuccessfulUpdateCheck()
116-
if (latestVersionInRepository != null && VersionComparatorUtil.compare(latestVersionInRepository, KotlinPluginUtil.getPluginVersion()) > 0) {
117-
ApplicationManager.getApplication().invokeLater({
118-
callback(PluginUpdateStatus.Update(latestVersionInRepository!!, descriptorToInstall!!, hostToInstallFrom))
119-
}, ModalityState.any())
120-
}
121-
else {
122-
ApplicationManager.getApplication().invokeLater({
123-
callback(PluginUpdateStatus.LatestVersionInstalled)
124-
}, ModalityState.any())
125-
}
126-
}
127-
else {
128-
ApplicationManager.getApplication().invokeLater {
129-
if (callback(PluginUpdateStatus.CheckFailed("Plugin not found in repository"))) queueUpdateCheck(callback)
130-
}
120+
val customUpdateStatus = checkUpdatesInCustomRepository(host)
121+
updateStatus = updateStatus.mergeWith(customUpdateStatus)
131122
}
132123
}
133124
catch(e: Exception) {
134-
LOG.info("Kotlin plugin update check failed", e)
135-
checkQueued = false
136-
ApplicationManager.getApplication().invokeLater {
137-
if (callback(PluginUpdateStatus.CheckFailed(e.message ?: "Unknown error"))) queueUpdateCheck(callback)
138-
}
125+
updateStatus = PluginUpdateStatus.fromException("Kotlin plugin update check failed", e)
139126
}
127+
128+
checkQueued = false
129+
130+
if (updateStatus !is PluginUpdateStatus.CheckFailed) {
131+
recordSuccessfulUpdateCheck()
132+
}
133+
ApplicationManager.getApplication().invokeLater({
134+
callback(updateStatus)
135+
}, ModalityState.any())
140136
}
141137

142-
private fun initPluginDescriptor(newVersion: String?): IdeaPluginDescriptor? {
143-
if (newVersion == null) return null
138+
private fun initPluginDescriptor(newVersion: String): IdeaPluginDescriptor {
144139
val originalPlugin = PluginManager.getPlugin(KotlinPluginUtil.KOTLIN_PLUGIN_ID)!!
145140
return PluginNode(KotlinPluginUtil.KOTLIN_PLUGIN_ID).apply {
146141
version = newVersion
@@ -149,31 +144,48 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
149144
}
150145
}
151146

152-
data class RepositoryCheckResult(val success: Boolean, val newVersion: String?)
153-
154-
fun getPluginVersionFromMainRepository(): RepositoryCheckResult {
147+
fun checkUpdatesInMainRepository(): PluginUpdateStatus {
155148
val buildNumber = ApplicationInfo.getInstance().build.asString()
156-
val pluginVersion = KotlinPluginUtil.getPluginVersion()
149+
val currentVersion = KotlinPluginUtil.getPluginVersion()
157150
val os = URLEncoder.encode(SystemInfo.OS_NAME + " " + SystemInfo.OS_VERSION, CharsetToolkit.UTF8)
158151
val uid = UpdateChecker.getInstallationUID(propertiesComponent)
159-
val url = "https://plugins.jetbrains.com/plugins/list?pluginId=6954&build=$buildNumber&pluginVersion=$pluginVersion&os=$os&uuid=$uid"
152+
val url = "https://plugins.jetbrains.com/plugins/list?pluginId=6954&build=$buildNumber&pluginVersion=$currentVersion&os=$os&uuid=$uid"
160153
val responseDoc = HttpRequests.request(url).connect {
161154
JDOMUtil.load(it.inputStream)
162155
}
163156
if (responseDoc.name != "plugin-repository") {
164-
LOG.info("Unexpected plugin repository response: ${JDOMUtil.writeElement(responseDoc, "\n")}")
165-
return RepositoryCheckResult(false, null)
157+
return PluginUpdateStatus.CheckFailed("Unexpected plugin repository response", JDOMUtil.writeElement(responseDoc, "\n"))
166158
}
167159
if (responseDoc.children.isEmpty()) {
168160
// No plugin version compatible with current IDEA build; don't retry updates
169-
return RepositoryCheckResult(true, null)
161+
return PluginUpdateStatus.LatestVersionInstalled
162+
}
163+
val newVersion = responseDoc.getChild("category")?.getChild("idea-plugin")?.getChild("version")?.text
164+
if (newVersion == null) {
165+
return PluginUpdateStatus.CheckFailed("Couldn't find plugin version in repository response", JDOMUtil.writeElement(responseDoc, "\n"))
170166
}
171-
val version = responseDoc.getChild("category")?.getChild("idea-plugin")?.getChild("version")?.text
172-
if (version == null) {
173-
LOG.info("Couldn't find plugin version in repository response: ${JDOMUtil.writeElement(responseDoc, "\n")}")
174-
return RepositoryCheckResult(false, null)
167+
val pluginDescriptor = initPluginDescriptor(newVersion)
168+
return updateIfNotLatest(pluginDescriptor, null)
169+
}
170+
171+
private fun checkUpdatesInCustomRepository(host: String): PluginUpdateStatus {
172+
val plugins = try {
173+
RepositoryHelper.loadPlugins(host, null)
175174
}
176-
return RepositoryCheckResult(true, version)
175+
catch(e: Exception) {
176+
return PluginUpdateStatus.fromException("Checking custom plugin repository $host failed", e)
177+
}
178+
179+
val kotlinPlugin = plugins.find { it.pluginId == KotlinPluginUtil.KOTLIN_PLUGIN_ID } ?: return PluginUpdateStatus.LatestVersionInstalled
180+
return updateIfNotLatest(kotlinPlugin, host)
181+
}
182+
183+
private fun updateIfNotLatest(kotlinPlugin: IdeaPluginDescriptor, host: String?): PluginUpdateStatus {
184+
if (VersionComparatorUtil.compare(kotlinPlugin.version, KotlinPluginUtil.getPluginVersion()) <= 0) {
185+
return PluginUpdateStatus.LatestVersionInstalled
186+
}
187+
188+
return PluginUpdateStatus.Update(kotlinPlugin, host)
177189
}
178190

179191
private fun recordSuccessfulUpdateCheck() {
@@ -184,7 +196,7 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
184196
private fun notifyPluginUpdateAvailable(update: PluginUpdateStatus.Update) {
185197
val notification = notificationGroup.createNotification(
186198
"Kotlin",
187-
"A new version ${update.newVersion} of the Kotlin plugin is available. <b><a href=\"#\">Install</a></b>",
199+
"A new version ${update.pluginDescriptor.version} of the Kotlin plugin is available. <b><a href=\"#\">Install</a></b>",
188200
NotificationType.INFORMATION) { notification, event ->
189201
notification.expire()
190202
installPluginUpdate(update) {
@@ -197,7 +209,7 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
197209

198210
fun installPluginUpdate(update: PluginUpdateStatus.Update,
199211
cancelCallback: () -> Unit = {}) {
200-
val descriptor = update.descriptorToInstall
212+
val descriptor = update.pluginDescriptor
201213
val pluginDownloader = PluginDownloader.createDownloader(descriptor, update.hostToInstallFrom, null)
202214
ProgressManager.getInstance().run(object : Task.Backgroundable(null, "Downloading plugins", true) {
203215
override fun run(indicator: ProgressIndicator) {

idea/src/org/jetbrains/kotlin/idea/actions/ConfigurePluginUpdatesAction.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class ConfigurePluginUpdatesDialog(project: Project) : DialogWrapper(project, fa
4646
saveSettings()
4747
form.updateCheckProgressIcon.resume()
4848
resetUpdateStatus()
49-
KotlinPluginUpdater.getInstance().queueUpdateCheck() { pluginUpdateStatus ->
49+
KotlinPluginUpdater.getInstance().runUpdateCheck{ pluginUpdateStatus ->
5050
form.updateCheckProgressIcon.suspend()
5151
when (pluginUpdateStatus) {
5252
PluginUpdateStatus.LatestVersionInstalled ->
@@ -55,7 +55,7 @@ class ConfigurePluginUpdatesDialog(project: Project) : DialogWrapper(project, fa
5555
is PluginUpdateStatus.Update -> {
5656
update = pluginUpdateStatus
5757
form.installButton.isVisible = true
58-
form.updateStatusLabel.text = "A new version ${pluginUpdateStatus.newVersion} is available"
58+
form.updateStatusLabel.text = "A new version ${pluginUpdateStatus.pluginDescriptor.version} is available"
5959
}
6060

6161
is PluginUpdateStatus.CheckFailed ->

0 commit comments

Comments
 (0)