Prototype verify extension and apply it for Kotlin updater in AS 3.2
This commit is contained in:
@@ -2946,6 +2946,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
|
||||
<extensionPoints>
|
||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
|
||||
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
|
||||
interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
@@ -2946,6 +2946,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
|
||||
<extensionPoints>
|
||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
|
||||
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
|
||||
interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
@@ -2944,6 +2944,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
|
||||
<extensionPoints>
|
||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
|
||||
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
|
||||
interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
@@ -2945,6 +2945,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
|
||||
<extensionPoints>
|
||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
|
||||
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
|
||||
interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
@@ -2944,6 +2944,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
|
||||
<extensionPoints>
|
||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
|
||||
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
|
||||
interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
|
||||
@@ -2944,6 +2944,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
|
||||
<extensionPoints>
|
||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/extensionPoints/*)"/>
|
||||
|
||||
<extensionPoint qualifiedName="org.jetbrains.kotlin.pluginUpdateVerifier"
|
||||
interface="org.jetbrains.kotlin.idea.update.PluginUpdateVerifier"/>
|
||||
</extensionPoints>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
@@ -2971,6 +2974,8 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
||||
<binaryExtension implementation="org.jetbrains.kotlin.idea.util.KotlinJsMetaBinary"/>
|
||||
|
||||
<highlighterExtension implementation="org.jetbrains.kotlin.idea.highlighter.dsl.DslHighlighterExtension"/>
|
||||
|
||||
<pluginUpdateVerifier implementation="org.jetbrains.kotlin.idea.update.GooglePluginUpdateVerifier"/>
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
||||
|
||||
@@ -27,6 +27,8 @@ import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.Alarm
|
||||
import com.intellij.util.io.HttpRequests
|
||||
import com.intellij.util.text.VersionComparatorUtil
|
||||
import org.jetbrains.kotlin.idea.update.PluginUpdateVerifier
|
||||
import org.jetbrains.kotlin.idea.update.verify
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.PrintWriter
|
||||
@@ -46,6 +48,8 @@ sealed class PluginUpdateStatus {
|
||||
|
||||
class CheckFailed(val message: String, val detail: String? = null) : PluginUpdateStatus()
|
||||
|
||||
class Unverified(val message: String, val updateStatus: Update) : PluginUpdateStatus()
|
||||
|
||||
fun mergeWith(other: PluginUpdateStatus): PluginUpdateStatus {
|
||||
if (other is Update) {
|
||||
when (this) {
|
||||
@@ -57,7 +61,7 @@ sealed class PluginUpdateStatus {
|
||||
return other
|
||||
}
|
||||
}
|
||||
is PluginUpdateStatus.CheckFailed -> {
|
||||
is CheckFailed, is Unverified -> {
|
||||
// proceed to return this
|
||||
}
|
||||
}
|
||||
@@ -150,9 +154,14 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
|
||||
lastUpdateStatus = updateStatus
|
||||
checkQueued = false
|
||||
|
||||
if (updateStatus is PluginUpdateStatus.Update) {
|
||||
updateStatus = verify(updateStatus)
|
||||
}
|
||||
|
||||
if (updateStatus !is PluginUpdateStatus.CheckFailed) {
|
||||
recordSuccessfulUpdateCheck()
|
||||
}
|
||||
|
||||
ApplicationManager.getApplication().invokeLater({
|
||||
callback(updateStatus)
|
||||
}, ModalityState.any())
|
||||
|
||||
@@ -156,6 +156,11 @@ class KotlinUpdatesSettingsConfigurable : SearchableConfigurable, Configurable.N
|
||||
|
||||
is PluginUpdateStatus.CheckFailed ->
|
||||
form.setUpdateStatus("Update check failed: ${pluginUpdateStatus.message}", false)
|
||||
|
||||
is PluginUpdateStatus.Unverified -> {
|
||||
val version = pluginUpdateStatus.updateStatus.pluginDescriptor.version
|
||||
form.setUpdateStatus("A new version $version is found. ${pluginUpdateStatus.message}", false)
|
||||
}
|
||||
}
|
||||
|
||||
false // do not auto-retry update check
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* 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.update
|
||||
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
|
||||
import org.intellij.lang.annotations.Language
|
||||
import java.util.*
|
||||
import javax.xml.bind.JAXBContext
|
||||
import javax.xml.bind.annotation.*
|
||||
import kotlin.collections.HashSet
|
||||
|
||||
class GooglePluginUpdateVerifier : PluginUpdateVerifier() {
|
||||
override fun verify(pluginDescriptor: IdeaPluginDescriptor): PluginVerifyResult? {
|
||||
if (pluginDescriptor.pluginId.idString != "org.jetbrains.kotlin") {
|
||||
return null
|
||||
}
|
||||
|
||||
// val approvedKotlinVersions = fetchApprovedKotlinVersions()
|
||||
// if (pluginDescriptor.version !in approvedKotlinVersions) {
|
||||
// // TODO: Modify message
|
||||
// return PluginVerifyResult.decline("Plugin is waiting for Google approve.")
|
||||
// }
|
||||
|
||||
return PluginVerifyResult.accept()
|
||||
}
|
||||
|
||||
private fun fetchApprovedKotlinVersions(): Set<String> {
|
||||
// TODO: Choose the host and do an actual request
|
||||
// TODO: Fetching the full list each time might be time-consuming
|
||||
// TODO: Process parsing and fetching errors
|
||||
|
||||
// TODO: Emulate long operation to check progress indicators. Remove after actual implementation is ready.
|
||||
Thread.sleep(200)
|
||||
|
||||
@Language("XML")
|
||||
val answer = """
|
||||
<plugin-compatibility>
|
||||
<studio-release name="3.2 Canary" channel="" since-build="181.1" until-build="181.*">
|
||||
<idea-plugin id="org.jetbrains.kotlin" version="1.2.41-release-Studio3.2c12-3" channel="stable" sha256="">
|
||||
<idea-version since-build="181.3007.1" until-build="181.*"/>
|
||||
</idea-plugin>
|
||||
<idea-plugin id="org.jetbrains.kotlin" version="1.2.50-eap-17-Studio3.2-1" channel="eap-1.2" sha256="">
|
||||
<idea-version since-build="181.3007.1" until-build="181.*"/>
|
||||
</idea-plugin>
|
||||
</studio-release>
|
||||
<studio-release name="3.1.2" channel="" since-build="173.4" until-build="173.*">
|
||||
<idea-plugin id="org.jetbrains.kotlin" version="1.2.41-release-Studio3.1-1" channel="stable" sha256="">
|
||||
<idea-version since-build="173.1" until-build="173.4301.25"/>
|
||||
</idea-plugin>
|
||||
</studio-release>
|
||||
</plugin-compatibility>
|
||||
""".trimIndent()
|
||||
|
||||
val context = JAXBContext.newInstance(PluginCompatibility::class.java)
|
||||
val unmarshaller = context.createUnmarshaller()
|
||||
val pluginCompatibility = unmarshaller.unmarshal(answer.byteInputStream()) as PluginCompatibility
|
||||
|
||||
val approvedKotlinVersions = HashSet<String>()
|
||||
for (studioRelease in pluginCompatibility.releases()) {
|
||||
for (ideaPlugin in studioRelease.plugins()) {
|
||||
if (ideaPlugin.id == KOTLIN_PLUGIN_ID) {
|
||||
val version = ideaPlugin.version
|
||||
if (version != null) {
|
||||
approvedKotlinVersions.add(version)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return approvedKotlinVersions
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KOTLIN_PLUGIN_ID = "org.jetbrains.kotlin"
|
||||
|
||||
private fun PluginCompatibility.releases() = studioRelease ?: emptyArray()
|
||||
private fun StudioRelease.plugins() = ideaPlugin ?: emptyArray()
|
||||
|
||||
@XmlRootElement(name = "plugin-compatibility")
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
class PluginCompatibility {
|
||||
@XmlElement(name = "studio-release")
|
||||
var studioRelease: Array<StudioRelease>? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "PluginCompatibility(studioRelease=${Arrays.toString(studioRelease)})"
|
||||
}
|
||||
}
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
class StudioRelease {
|
||||
@XmlAttribute(name = "until-build")
|
||||
var untilBuild: String? = null
|
||||
@XmlAttribute(name = "since-build")
|
||||
var sinceBuild: String? = null
|
||||
@XmlAttribute
|
||||
var name: String? = null
|
||||
@XmlAttribute
|
||||
var channel: String? = null
|
||||
|
||||
@XmlElement(name = "idea-plugin")
|
||||
var ideaPlugin: Array<IdeaPlugin>? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "StudioRelease(" +
|
||||
"untilBuild=$untilBuild, name=$name, ideaPlugin=${Arrays.toString(ideaPlugin)}, " +
|
||||
"sinceBuild=$sinceBuild, channel=$channel" +
|
||||
")"
|
||||
}
|
||||
}
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
class IdeaPlugin {
|
||||
@XmlAttribute
|
||||
var id: String? = null
|
||||
@XmlAttribute
|
||||
var sha256: String? = null
|
||||
@XmlAttribute
|
||||
var channel: String? = null
|
||||
@XmlAttribute
|
||||
var version: String? = null
|
||||
|
||||
@XmlElement(name = "idea-version")
|
||||
var ideaVersion: IdeaVersion? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "IdeaPlugin(id=$id, sha256=$sha256, ideaVersion=$ideaVersion, channel=$channel, version=$version)"
|
||||
}
|
||||
}
|
||||
|
||||
@XmlAccessorType(XmlAccessType.FIELD)
|
||||
class IdeaVersion {
|
||||
@XmlAttribute(name = "until-build")
|
||||
var untilBuild: String? = null
|
||||
@XmlAttribute(name = "since-build")
|
||||
var sinceBuild: String? = null
|
||||
|
||||
override fun toString(): String {
|
||||
return "IdeaVersion(untilBuild=$untilBuild, sinceBuild=$sinceBuild)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.update
|
||||
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
|
||||
abstract class PluginUpdateVerifier {
|
||||
/**
|
||||
* @param pluginDescriptor
|
||||
* @return null means verifier is not responsible for the given plugin descriptor.
|
||||
*/
|
||||
abstract fun verify(pluginDescriptor: IdeaPluginDescriptor): PluginVerifyResult?
|
||||
|
||||
companion object {
|
||||
internal var EP_NAME = ExtensionPointName<PluginUpdateVerifier>("org.jetbrains.kotlin.pluginUpdateVerifier")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.update
|
||||
|
||||
class PluginVerifyResult {
|
||||
var verified: Boolean = true
|
||||
|
||||
/**
|
||||
* Short sentence explaining why plugin is available in JetBrains repository but can't be installed.
|
||||
* Unapproved result should have a not-null declined message.
|
||||
*/
|
||||
var declineMessage: String? = null
|
||||
|
||||
companion object {
|
||||
fun decline(reason: String): PluginVerifyResult = PluginVerifyResult().apply {
|
||||
declineMessage = reason
|
||||
verified = false
|
||||
}
|
||||
|
||||
fun accept() = PluginVerifyResult()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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.update
|
||||
|
||||
import org.jetbrains.kotlin.idea.PluginUpdateStatus
|
||||
|
||||
// Do an additional verification with PluginUpdateVerifier. Enabled only in AS 32.
|
||||
fun verify(updateStatus: PluginUpdateStatus.Update): PluginUpdateStatus {
|
||||
return updateStatus
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.update
|
||||
|
||||
import com.intellij.ide.plugins.IdeaPluginDescriptor
|
||||
import org.jetbrains.kotlin.idea.PluginUpdateStatus
|
||||
|
||||
// Do an additional verification with PluginUpdateVerifier. Enabled only in AS 32.
|
||||
fun verify(updateStatus: PluginUpdateStatus.Update): PluginUpdateStatus {
|
||||
val pluginDescriptor: IdeaPluginDescriptor = updateStatus.pluginDescriptor
|
||||
val pluginVerifiers = PluginUpdateVerifier.EP_NAME.extensions
|
||||
|
||||
val declineMessage = pluginVerifiers.asSequence()
|
||||
.map { verifier ->
|
||||
val verifyResult = verifier.verify(pluginDescriptor)
|
||||
if (verifyResult != null && !verifyResult.verified) {
|
||||
verifyResult.declineMessage
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
.firstOrNull { reason -> reason != null }
|
||||
|
||||
if (declineMessage != null) {
|
||||
return PluginUpdateStatus.Unverified(declineMessage, updateStatus)
|
||||
}
|
||||
|
||||
return updateStatus
|
||||
}
|
||||
Reference in New Issue
Block a user