From 46a1ec28bfd54380d1d68b4838121108832bf65b Mon Sep 17 00:00:00 2001 From: Sergey Rostov Date: Fri, 31 May 2019 12:17:09 +0300 Subject: [PATCH] Gradle, npm: implement semver comparision --- .../kotlin/gradle/targets/js/npm/semver.kt | 80 +++++++++++++++++++ .../gradle/targets/js/npm/SemVerTest.kt | 47 +++++++++++ 2 files changed, 127 insertions(+) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/SemVerTest.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/semver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/semver.kt index edccd5e0d4d..f538a1fa946 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/semver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/semver.kt @@ -5,6 +5,86 @@ package org.jetbrains.kotlin.gradle.targets.js.npm +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 "") + + fun toDebugString(): String { + return "SemVer(major=$major, minor=$minor, patch=$patch, preRelease=$preRelease, build=$build)" + } + + companion object { + fun from(string: String, loose: Boolean = false): SemVer { + val fixed = if (loose) fixSemver(string) else string + + val minorStart = fixed.indexOf('.') + check(minorStart != -1) { "Bad semver: $string. Minor version missed." } + + val patchStart = fixed.indexOf('.', minorStart + 1) + check(patchStart != -1) { "Bad semver: $string. Patch version missed." } + + val preReleaseStart = fixed.indexOf('-', patchStart + 1) + val buildStart = fixed.indexOf('+', if (preReleaseStart == -1) patchStart + 1 else preReleaseStart + 1) + val preReleaseEnd = when { + buildStart != -1 -> buildStart + else -> fixed.length + } + val patchEnd = when { + preReleaseStart != -1 -> preReleaseStart + buildStart != -1 -> buildStart + else -> fixed.length + } + + val major = fixed.substring(0, minorStart) + val minor = fixed.substring(minorStart + 1, patchStart) + val patch = fixed.substring(patchStart + 1, patchEnd) + val preRelease = if (preReleaseStart != -1) fixed.substring(preReleaseStart + 1, preReleaseEnd) else "" + val build = if (buildStart != -1) fixed.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() } + ) + } + } +} + internal fun fixSemver(version: String): String { var i = 0 var number = 0 diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/SemVerTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/SemVerTest.kt new file mode 100644 index 00000000000..e6d8da74541 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/targets/js/npm/SemVerTest.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2010-2019 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.gradle.targets.js.npm + +import org.junit.Assert.* +import org.junit.Test + +class SemVerTest { + @Test + fun testParse() { + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=null, build=null)", SemVer.from("0.0.0").toDebugString()) + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=a, build=null)", SemVer.from("0.0.0-a").toDebugString()) + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=a, build=b)", SemVer.from("0.0.0-a+b").toDebugString()) + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=null, build=b)", SemVer.from("0.0.0+b").toDebugString()) + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=null, build=null)", SemVer.from("0.0.0-").toDebugString()) + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=null, build=null)", SemVer.from("0.0.0-+").toDebugString()) + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=null, build=null)", SemVer.from("0.0.0+").toDebugString()) + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=a-b, build=null)", SemVer.from("0.0.0-a-b").toDebugString()) + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=a-b, build=b)", SemVer.from("0.0.0-a-b+b").toDebugString()) + assertEquals("SemVer(major=0, minor=0, patch=0, preRelease=a, build=b-c)", SemVer.from("0.0.0-a+b-c").toDebugString()) + assertEquals( + "SemVer(major=9999999999999999, minor=9999999999999999, patch=9999999999999999, preRelease=9999999999999999, build=9999999999999999)", + SemVer.from("9999999999999999.9999999999999999.9999999999999999-9999999999999999+9999999999999999").toDebugString() + ) + } + + @Test + fun testSort() { + assertEquals( + "1.3.0, 1.3.0+1, 1.3.0-SNAPSHOT, 1.3.0-SNAPSHOT+1, 1.3.30, 1.3.31, 1.3.40, 1.4.0, 2.0.0", + listOf( + SemVer.from("1.3.40"), + SemVer.from("1.3-SNAPSHOT", true), + SemVer.from("1.3.31"), + SemVer.from("1.3.30"), + SemVer.from("1.4.0"), + SemVer.from("2.0.0"), + SemVer.from("1.3-SNAPSHOT+1", true), + SemVer.from("1.3", true), + SemVer.from("1.3+1", true) + ).sorted().joinToString(", ") + ) + } +} \ No newline at end of file