From 4986e8c9ccb22c6e31187e422d542eea8d32f4d8 Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Thu, 10 Sep 2020 19:23:20 +0300 Subject: [PATCH] [Gradle, JS] Fetch NPM package versions in separate module --- .../build.gradle.kts | 10 +++ .../gradle/targets/js/NpmPackages.kt | 32 ++++++++ .../generators/gradle/targets/js/SemVer.kt | 81 +++++++++++++++++++ .../gradle/targets/js/VersionFetcher.kt | 76 +++++++++++++++++ .../generators/gradle/targets/js/main.kt | 33 ++++++++ settings.gradle | 2 + 6 files changed, 234 insertions(+) create mode 100644 libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/build.gradle.kts create mode 100644 libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/NpmPackages.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/SemVer.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/VersionFetcher.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/main.kt diff --git a/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/build.gradle.kts new file mode 100644 index 00000000000..fbcda6c4a60 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/build.gradle.kts @@ -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") +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/NpmPackages.kt b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/NpmPackages.kt new file mode 100644 index 00000000000..9999dbb6a94 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/NpmPackages.kt @@ -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", +) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/SemVer.kt b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/SemVer.kt new file mode 100644 index 00000000000..02efa47516d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/SemVer.kt @@ -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 { + 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() } + ) + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/VersionFetcher.kt b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/VersionFetcher.kt new file mode 100644 index 00000000000..80b72f92f2d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/VersionFetcher.kt @@ -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 { + return withContext(coroutineContext) { + npmPackages + .map { packageName -> + val packagePath = + if (packageName.startsWith("@")) + "@" + encodeURIComponent(packageName) + else + encodeURIComponent(packageName) + + val fetch = async { + 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 +) + +data class Package( + val name: String, + val version: SemVer +) + +data class FetchedPackageInformation( + val versions: Map +) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/main.kt b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/main.kt new file mode 100644 index 00000000000..06c507d7539 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-npm-versions-codegen/src/main/kotlin/org/jetbrains/kotlin/generators/gradle/targets/js/main.kt @@ -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): List { + 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 + ) + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index d2f8b4bd76b..fe69d3e36fa 100644 --- a/settings.gradle +++ b/settings.gradle @@ -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