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>
|
<extensionPoints>
|
||||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/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>
|
</extensionPoints>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||||
|
|||||||
@@ -2946,6 +2946,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
|||||||
|
|
||||||
<extensionPoints>
|
<extensionPoints>
|
||||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/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>
|
</extensionPoints>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||||
|
|||||||
@@ -2944,6 +2944,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
|||||||
|
|
||||||
<extensionPoints>
|
<extensionPoints>
|
||||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/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>
|
</extensionPoints>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||||
|
|||||||
@@ -2945,6 +2945,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
|||||||
|
|
||||||
<extensionPoints>
|
<extensionPoints>
|
||||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/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>
|
</extensionPoints>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||||
|
|||||||
@@ -2944,6 +2944,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
|||||||
|
|
||||||
<extensionPoints>
|
<extensionPoints>
|
||||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/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>
|
</extensionPoints>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||||
|
|||||||
@@ -2944,6 +2944,9 @@ The Kotlin plugin provides language support in IntelliJ IDEA and Android Studio.
|
|||||||
|
|
||||||
<extensionPoints>
|
<extensionPoints>
|
||||||
<xi:include href="extensions/compiler.xml" xpointer="xpointer(/idea-plugin/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>
|
</extensionPoints>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
<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"/>
|
<binaryExtension implementation="org.jetbrains.kotlin.idea.util.KotlinJsMetaBinary"/>
|
||||||
|
|
||||||
<highlighterExtension implementation="org.jetbrains.kotlin.idea.highlighter.dsl.DslHighlighterExtension"/>
|
<highlighterExtension implementation="org.jetbrains.kotlin.idea.highlighter.dsl.DslHighlighterExtension"/>
|
||||||
|
|
||||||
|
<pluginUpdateVerifier implementation="org.jetbrains.kotlin.idea.update.GooglePluginUpdateVerifier"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import com.intellij.openapi.vfs.VirtualFile
|
|||||||
import com.intellij.util.Alarm
|
import com.intellij.util.Alarm
|
||||||
import com.intellij.util.io.HttpRequests
|
import com.intellij.util.io.HttpRequests
|
||||||
import com.intellij.util.text.VersionComparatorUtil
|
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.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
@@ -46,6 +48,8 @@ sealed class PluginUpdateStatus {
|
|||||||
|
|
||||||
class CheckFailed(val message: String, val detail: String? = null) : 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 {
|
fun mergeWith(other: PluginUpdateStatus): PluginUpdateStatus {
|
||||||
if (other is Update) {
|
if (other is Update) {
|
||||||
when (this) {
|
when (this) {
|
||||||
@@ -57,7 +61,7 @@ sealed class PluginUpdateStatus {
|
|||||||
return other
|
return other
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is PluginUpdateStatus.CheckFailed -> {
|
is CheckFailed, is Unverified -> {
|
||||||
// proceed to return this
|
// proceed to return this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,9 +154,14 @@ class KotlinPluginUpdater(val propertiesComponent: PropertiesComponent) : Dispos
|
|||||||
lastUpdateStatus = updateStatus
|
lastUpdateStatus = updateStatus
|
||||||
checkQueued = false
|
checkQueued = false
|
||||||
|
|
||||||
|
if (updateStatus is PluginUpdateStatus.Update) {
|
||||||
|
updateStatus = verify(updateStatus)
|
||||||
|
}
|
||||||
|
|
||||||
if (updateStatus !is PluginUpdateStatus.CheckFailed) {
|
if (updateStatus !is PluginUpdateStatus.CheckFailed) {
|
||||||
recordSuccessfulUpdateCheck()
|
recordSuccessfulUpdateCheck()
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplicationManager.getApplication().invokeLater({
|
ApplicationManager.getApplication().invokeLater({
|
||||||
callback(updateStatus)
|
callback(updateStatus)
|
||||||
}, ModalityState.any())
|
}, ModalityState.any())
|
||||||
|
|||||||
@@ -156,6 +156,11 @@ class KotlinUpdatesSettingsConfigurable : SearchableConfigurable, Configurable.N
|
|||||||
|
|
||||||
is PluginUpdateStatus.CheckFailed ->
|
is PluginUpdateStatus.CheckFailed ->
|
||||||
form.setUpdateStatus("Update check failed: ${pluginUpdateStatus.message}", false)
|
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
|
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