[Gradle, JS] Fetch NPM package versions in separate module

This commit is contained in:
Ilya Goncharov
2020-09-10 19:23:20 +03:00
parent db90c9cc88
commit 4986e8c9cc
6 changed files with 234 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
plugins {
kotlin("jvm")
}
dependencies {
// implementation(project(":kotlin-gradle-plugin"))
implementation("io.ktor:ktor-client-cio:1.4.0")
implementation("com.google.code.gson:gson:${rootProject.extra["versions.jar.gson"]}")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.0.0-RC")
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.generators.gradle.targets.js
val npmPackages = listOf(
"dukat",
"webpack",
"webpack-cli",
"webpack-bundle-analyzer",
"webpack-dev-server",
"source-map-loader",
"source-map-support",
"css-loader",
"style-loader",
"to-string-loader",
"mini-css-extract-plugin",
"mocha",
"karma",
"karma-chrome-launcher",
"karma-phantomjs-launcher",
"karma-firefox-launcher",
"karma-opera-launcher",
"karma-ie-launcher",
"karma-safari-launcher",
"karma-mocha",
"karma-webpack",
"karma-coverage",
"karma-sourcemap-loader",
)

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.generators.gradle.targets.js
import java.math.BigInteger
data class SemVer(
val major: BigInteger,
val minor: BigInteger,
val patch: BigInteger,
val preRelease: String? = null,
val build: String? = null
) : Comparable<SemVer> {
override fun compareTo(other: SemVer): Int {
val compareMajor = major.compareTo(other.major)
if (compareMajor != 0) return compareMajor
val compareMinor = minor.compareTo(other.minor)
if (compareMinor != 0) return compareMinor
val comparePatch = patch.compareTo(other.patch)
if (comparePatch != 0) return comparePatch
val comparePreRelease = compareValues(preRelease, other.preRelease)
if (comparePreRelease != 0) return comparePreRelease
val compareBuild = compareValues(build, other.build)
if (compareBuild != 0) return compareBuild
return 0
}
override fun toString() = "$major.$minor.$patch" +
(if (preRelease != null) "-$preRelease" else "") +
(if (build != null) "+$build" else "")
companion object {
fun from(string: String): SemVer {
val minorStart = string.indexOf('.')
check(minorStart != -1) { "Bad semver: $string. Minor version missed." }
val patchStart = string.indexOf('.', minorStart + 1)
check(patchStart != -1) { "Bad semver: $string. Patch version missed." }
val preReleaseStart = string.indexOf('-', patchStart + 1)
val buildStart = string.indexOf('+', if (preReleaseStart == -1) patchStart + 1 else preReleaseStart + 1)
val preReleaseEnd = when {
buildStart != -1 -> buildStart
else -> string.length
}
val patchEnd = when {
preReleaseStart != -1 -> preReleaseStart
buildStart != -1 -> buildStart
else -> string.length
}
val major = string.substring(0, minorStart)
val minor = string.substring(minorStart + 1, patchStart)
val patch = string.substring(patchStart + 1, patchEnd)
val preRelease = if (preReleaseStart != -1) string.substring(preReleaseStart + 1, preReleaseEnd) else ""
val build = if (buildStart != -1) string.substring(buildStart + 1) else ""
check(major.isNotBlank()) { "Bad semver: $string. Major version missed." }
check(minor.isNotBlank()) { "Bad semver: $string. Minor version missed." }
check(patch.isNotBlank()) { "Bad semver: $string. Patch version missed." }
return SemVer(
BigInteger(major),
BigInteger(minor),
BigInteger(patch),
preRelease.takeIf { it.isNotBlank() },
build.takeIf { it.isNotBlank() }
)
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.generators.gradle.targets.js
import com.google.gson.Gson
import io.ktor.client.*
import io.ktor.client.request.*
import kotlinx.coroutines.async
import kotlinx.coroutines.withContext
import java.io.UnsupportedEncodingException
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import kotlin.coroutines.CoroutineContext
class VersionFetcher(
private val coroutineContext: CoroutineContext
) {
private val client = HttpClient()
suspend fun fetch(): List<PackageInformation> {
return withContext(coroutineContext) {
npmPackages
.map { packageName ->
val packagePath =
if (packageName.startsWith("@"))
"@" + encodeURIComponent(packageName)
else
encodeURIComponent(packageName)
val fetch = async<String> {
client.get("http://registry.npmjs.org/$packagePath")
}
val fetchedPackageInformation = Gson().fromJson(fetch.await(), FetchedPackageInformation::class.java)
PackageInformation(
packageName,
fetchedPackageInformation.versions.keys
)
}.also {
client.close()
}
}
}
}
fun encodeURIComponent(s: String): String {
return try {
URLEncoder.encode(s, StandardCharsets.UTF_8.name())
.replace("+", "%20")
.replace("%21", "!")
.replace("%27", "'")
.replace("%28", "(")
.replace("%29", ")")
.replace("%7E", "~")
} catch (e: UnsupportedEncodingException) {
s
}
}
data class PackageInformation(
val name: String,
val versions: Set<String>
)
data class Package(
val name: String,
val version: SemVer
)
data class FetchedPackageInformation(
val versions: Map<String, Any>
)

View File

@@ -0,0 +1,33 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.generators.gradle.targets.js
import kotlinx.coroutines.runBlocking
fun main() {
runBlocking {
val packages = VersionFetcher(coroutineContext).fetch()
findLastVersions(packages)
.forEach {
println(it)
}
}
}
fun findLastVersions(packages: List<PackageInformation>): List<Package> {
return packages
.map { packageInformation ->
val maximumVersion = packageInformation.versions
.map { SemVer.from(it) }
.filter { it.preRelease == null && it.build == null }
.maxOrNull() ?: throw error("There is no applicable version for ${packageInformation.name}")
Package(
packageInformation.name,
maximumVersion
)
}
}

View File

@@ -237,6 +237,7 @@ include ":benchmarks",
":tools:kotlinp",
":kotlin-gradle-plugin-api",
":kotlin-gradle-plugin-dsl-codegen",
":kotlin-gradle-plugin-npm-versions-codegen",
":kotlin-gradle-statistics",
":kotlin-gradle-plugin",
":kotlin-gradle-plugin-model",
@@ -489,6 +490,7 @@ project(':sam-with-receiver-ide-plugin').projectDir = "$rootDir/plugins/sam-with
project(':tools:kotlinp').projectDir = "$rootDir/libraries/tools/kotlinp" as File
project(':kotlin-gradle-plugin-api').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin-api" as File
project(':kotlin-gradle-plugin-dsl-codegen').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin-dsl-codegen" as File
project(':kotlin-gradle-plugin-npm-versions-codegen').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen" as File
project(':kotlin-gradle-statistics').projectDir = "$rootDir/libraries/tools/kotlin-gradle-statistics" as File
project(':kotlin-gradle-plugin').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin" as File
project(':kotlin-gradle-plugin-model').projectDir = "$rootDir/libraries/tools/kotlin-gradle-plugin-model" as File