KT-11261 Implement MavenArchetypesProvider extension point
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
</extensions>
|
</extensions>
|
||||||
<extensions defaultExtensionNs="org.jetbrains.idea.maven">
|
<extensions defaultExtensionNs="org.jetbrains.idea.maven">
|
||||||
<importer implementation="org.jetbrains.kotlin.idea.configuration.KotlinMavenImporter" />
|
<importer implementation="org.jetbrains.kotlin.idea.configuration.KotlinMavenImporter" />
|
||||||
|
<archetypesProvider implementation="org.jetbrains.kotlin.idea.configuration.KotlinMavenArchetypesProvider" />
|
||||||
</extensions>
|
</extensions>
|
||||||
<module-components>
|
<module-components>
|
||||||
<component>
|
<component>
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.configuration
|
||||||
|
|
||||||
|
import com.google.gson.JsonElement
|
||||||
|
import com.google.gson.JsonParser
|
||||||
|
import com.intellij.util.net.HttpConfigurable
|
||||||
|
import org.jetbrains.idea.maven.dom.MavenVersionComparable
|
||||||
|
import org.jetbrains.idea.maven.indices.MavenArchetypesProvider
|
||||||
|
import org.jetbrains.idea.maven.model.MavenArchetype
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinPluginUtil
|
||||||
|
import org.jetbrains.kotlin.utils.ifEmpty
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class KotlinMavenArchetypesProvider(val kotlinPluginVersion: String) : MavenArchetypesProvider {
|
||||||
|
constructor() : this(KotlinPluginUtil.getPluginVersion())
|
||||||
|
|
||||||
|
val VERSIONS_LIST_URL = mavenSearchUrl("org.jetbrains.kotlin", packaging = "maven-archetype", rowsLimit = 1000)
|
||||||
|
private val versionPrefix by lazy { """^\d+\.\d+\.""".toRegex().find(kotlinPluginVersion)?.value ?: "1.0." }
|
||||||
|
|
||||||
|
private val archetypesBlocking by lazy {
|
||||||
|
try {
|
||||||
|
loadVersions().ifEmpty { defaultArchetypes() }
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
defaultArchetypes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getArchetypes() = archetypesBlocking.toMutableList()
|
||||||
|
|
||||||
|
private fun defaultArchetypes() = listOf(MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.0", null, null))
|
||||||
|
|
||||||
|
private fun loadVersions(): List<MavenArchetype> {
|
||||||
|
return connectAndApply(VERSIONS_LIST_URL) { urlConnection ->
|
||||||
|
urlConnection.inputStream.bufferedReader().use { reader ->
|
||||||
|
extractVersions(JsonParser().parse(reader))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun extractVersions(root: JsonElement) =
|
||||||
|
root.asJsonObject.get("response")
|
||||||
|
.asJsonObject.get("docs")
|
||||||
|
.asJsonArray
|
||||||
|
.map { it.asJsonObject }
|
||||||
|
.map { MavenArchetype(it.get("g").asString, it.get("a").asString, it.get("v").asString, null, null) }
|
||||||
|
.filter { it.version?.startsWith(versionPrefix) ?: false }
|
||||||
|
.maxBy { MavenVersionComparable(it.version) }
|
||||||
|
.let { listOfNotNull(it) }
|
||||||
|
|
||||||
|
private fun mavenSearchUrl(group: String, artifactId: String? = null, version: String? = null, packaging: String? = null, rowsLimit: Int = 20): String {
|
||||||
|
val q = listOf(
|
||||||
|
"g" to group,
|
||||||
|
"a" to artifactId,
|
||||||
|
"v" to version,
|
||||||
|
"p" to packaging
|
||||||
|
)
|
||||||
|
.filter { it.second != null }
|
||||||
|
.map { "${it.first}:\"${it.second}\"" }
|
||||||
|
.joinToString(separator = " AND ")
|
||||||
|
|
||||||
|
return "http://search.maven.org/solrsearch/select?q=${q.encodeURL()}&core=gav&rows=$rowsLimit&wt=json"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <R> connectAndApply(url: String, timeoutSeconds: Int = 15, block: (HttpURLConnection) -> R): R {
|
||||||
|
return HttpConfigurable.getInstance().openHttpConnection(url).use { urlConnection ->
|
||||||
|
val timeout = TimeUnit.SECONDS.toMillis(timeoutSeconds.toLong()).toInt()
|
||||||
|
urlConnection.connectTimeout = timeout
|
||||||
|
urlConnection.readTimeout = timeout
|
||||||
|
|
||||||
|
urlConnection.connect()
|
||||||
|
block(urlConnection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <R> HttpURLConnection.use(block: (HttpURLConnection) -> R): R =
|
||||||
|
try {
|
||||||
|
block(this)
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.encodeURL() = URLEncoder.encode(this, "UTF-8")
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
{
|
||||||
|
"responseHeader": {
|
||||||
|
"status": 0,
|
||||||
|
"QTime": 2,
|
||||||
|
"params": {
|
||||||
|
"fl": "id,g,a,v,p,ec,timestamp,tags",
|
||||||
|
"sort": "score desc,timestamp desc,g asc,a asc,v desc",
|
||||||
|
"indent": "off",
|
||||||
|
"q": "g:\"org.jetbrains.kotlin\" AND p:\"maven-archetype\"",
|
||||||
|
"core": "gav",
|
||||||
|
"wt": "json",
|
||||||
|
"rows": "200",
|
||||||
|
"version": "2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"response": {
|
||||||
|
"numFound": 3,
|
||||||
|
"start": 0,
|
||||||
|
"docs": [
|
||||||
|
{
|
||||||
|
"id": "org.jetbrains.kotlin:kotlin-archetype-jvm:1.0.0",
|
||||||
|
"g": "org.jetbrains.kotlin",
|
||||||
|
"a": "kotlin-archetype-jvm",
|
||||||
|
"v": "1.0.0",
|
||||||
|
"p": "maven-archetype",
|
||||||
|
"timestamp": 1458127798000,
|
||||||
|
"tags": [
|
||||||
|
"using",
|
||||||
|
"restful",
|
||||||
|
"creates",
|
||||||
|
"example",
|
||||||
|
"webservice"
|
||||||
|
],
|
||||||
|
"ec": [
|
||||||
|
"-sources.jar",
|
||||||
|
".jar",
|
||||||
|
".pom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.jetbrains.kotlin:kotlin-archetype-js:1.0.0",
|
||||||
|
"g": "org.jetbrains.kotlin",
|
||||||
|
"a": "kotlin-archetype-js",
|
||||||
|
"v": "1.0.0",
|
||||||
|
"p": "maven-archetype",
|
||||||
|
"timestamp": 1458127798000,
|
||||||
|
"tags": [
|
||||||
|
"using",
|
||||||
|
"restful",
|
||||||
|
"creates",
|
||||||
|
"example",
|
||||||
|
"webservice"
|
||||||
|
],
|
||||||
|
"ec": [
|
||||||
|
"-sources.jar",
|
||||||
|
".jar",
|
||||||
|
".pom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.jetbrains.kotlin:kotlin-archetype-jvm:1.0.1",
|
||||||
|
"g": "org.jetbrains.kotlin",
|
||||||
|
"a": "kotlin-archetype-jvm",
|
||||||
|
"v": "1.0.1",
|
||||||
|
"p": "maven-archetype",
|
||||||
|
"timestamp": 1458127798000,
|
||||||
|
"tags": [
|
||||||
|
"using",
|
||||||
|
"restful",
|
||||||
|
"creates",
|
||||||
|
"example",
|
||||||
|
"webservice"
|
||||||
|
],
|
||||||
|
"ec": [
|
||||||
|
"-sources.jar",
|
||||||
|
".jar",
|
||||||
|
".pom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.jetbrains.kotlin:kotlin-archetype-jvm:1.0.1",
|
||||||
|
"g": "org.jetbrains.kotlin",
|
||||||
|
"a": "kotlin-archetype-jvm",
|
||||||
|
"v": "1.0.1-2",
|
||||||
|
"p": "maven-archetype",
|
||||||
|
"timestamp": 1458127798000,
|
||||||
|
"tags": [
|
||||||
|
"using",
|
||||||
|
"restful",
|
||||||
|
"creates",
|
||||||
|
"example",
|
||||||
|
"webservice"
|
||||||
|
],
|
||||||
|
"ec": [
|
||||||
|
"-sources.jar",
|
||||||
|
".jar",
|
||||||
|
".pom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "org.jetbrains.kotlin:kotlin-archetype-jvm:1.1.2",
|
||||||
|
"g": "org.jetbrains.kotlin",
|
||||||
|
"a": "kotlin-archetype-jvm",
|
||||||
|
"v": "1.1.2",
|
||||||
|
"p": "maven-archetype",
|
||||||
|
"timestamp": 1458127798000,
|
||||||
|
"tags": [
|
||||||
|
"using",
|
||||||
|
"restful",
|
||||||
|
"creates",
|
||||||
|
"example",
|
||||||
|
"webservice"
|
||||||
|
],
|
||||||
|
"ec": [
|
||||||
|
"-sources.jar",
|
||||||
|
".jar",
|
||||||
|
".pom"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2016 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.configuration
|
||||||
|
|
||||||
|
import com.google.gson.JsonParser
|
||||||
|
import org.jetbrains.idea.maven.model.MavenArchetype
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class KotlinMavenArchetypesProviderTest {
|
||||||
|
private val BASE_PATH = "idea/testData/configuration/"
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun extractVersions() {
|
||||||
|
val file = File(BASE_PATH, "extractVersions/maven-central-response.json")
|
||||||
|
assertTrue("Test data is missing", file.exists())
|
||||||
|
|
||||||
|
val json = file.bufferedReader().use {
|
||||||
|
JsonParser().parse(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val versions = KotlinMavenArchetypesProvider("1.0.0-Release-Something-1886").extractVersions(json)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.0.1-2", null, null)
|
||||||
|
).sortedBy { it.artifactId + "." + it.version },
|
||||||
|
versions.sortedBy { it.artifactId + "." + it.version }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun extractVersionsNewPlugin() {
|
||||||
|
val file = File(BASE_PATH, "extractVersions/maven-central-response.json")
|
||||||
|
assertTrue("Test data is missing", file.exists())
|
||||||
|
|
||||||
|
val json = file.bufferedReader().use {
|
||||||
|
JsonParser().parse(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
val versions = KotlinMavenArchetypesProvider("1.1.0-Next-Release-Something-9999").extractVersions(json)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
MavenArchetype("org.jetbrains.kotlin", "kotlin-archetype-jvm", "1.1.2", null, null)
|
||||||
|
).sortedBy { it.artifactId + "." + it.version },
|
||||||
|
versions.sortedBy { it.artifactId + "." + it.version }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user