mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Update SemVersion rules
This commit is contained in:
parent
e299ecffb9
commit
001fac65cc
@ -184,8 +184,8 @@ internal object SemVersionInternal {
|
||||
identifier0 = identifier0.substring(ignoredSize)
|
||||
identifier1 = identifier1.substring(ignoredSize)
|
||||
// Multi-chunk comparing
|
||||
val chunks0 = identifier0.split('-', '.', '_')
|
||||
val chunks1 = identifier1.split('-', '.', '_')
|
||||
val chunks0 = identifier0.split('-', '.')
|
||||
val chunks1 = identifier1.split('-', '.')
|
||||
chunkLoop@ for (index in 0 until (max(chunks0.size, chunks1.size))) {
|
||||
val value0 = chunks0.getOrNull(index)
|
||||
val value1 = chunks1.getOrNull(index)
|
||||
|
@ -39,16 +39,14 @@ import net.mamoe.mirai.console.util.SemVersion.Companion.equals
|
||||
* metadata = "c25733b8"
|
||||
* )
|
||||
* ```
|
||||
* 其中 identifier 和 metadata 都是可选的, 该实现对于 mainVersion 的最大长度不作出限制,
|
||||
* 也建议 mainVersion 的长度不要过长或过短
|
||||
* 但是必须至少拥有两位及以上的版本描述符, (即必须拥有主版本号和次版本号).
|
||||
*
|
||||
* 比如 `1-M4` 是不合法的, 但是 `1.0-M4` 是合法的
|
||||
* 其中 identifier 和 metadata 都是可选的.
|
||||
* 对于核心版本号, 此实现稍微比 semver 宽松一些, 允许 x.y 的存在.
|
||||
* 但是不允许 0.0.0.0 之类的存在
|
||||
*
|
||||
*/
|
||||
@Serializable
|
||||
public data class SemVersion internal constructor(
|
||||
/** 核心版本号, 至少包含一个主版本号和一个次版本号 */
|
||||
/** 核心版本号, 由主版本号, 次版本号和修订号组成, 其中修订号不一定存在 */
|
||||
public val mainVersion: IntArray,
|
||||
/** 先行版本号识别符 */
|
||||
public val identifier: String? = null,
|
||||
@ -65,6 +63,9 @@ public data class SemVersion internal constructor(
|
||||
}
|
||||
|
||||
public companion object {
|
||||
private val SEM_VERSION_REGEX =
|
||||
"""^(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$""".toRegex()
|
||||
|
||||
/** 解析核心版本号, eg: `1.0.0` -> IntArray[1, 0, 0] */
|
||||
@JvmStatic
|
||||
private fun String.parseMainVersion(): IntArray =
|
||||
@ -78,14 +79,23 @@ public data class SemVersion internal constructor(
|
||||
* - 必须包含主版本号和次版本号
|
||||
* - 存在 先行版本号 的时候 先行版本号 不能为空
|
||||
* - 存在 元数据 的时候 元数据 不能为空
|
||||
* - 核心版本号只允许 `x.y` 和 `x.y.z` 的存在
|
||||
* - `1.0-RC` 是合法的
|
||||
* - `1.0.0-RC` 也是合法的, 与 `1.0-RC` 一样
|
||||
* - `1.0.0.0-RC` 是不合法的, 将会抛出一个 [IllegalArgumentException]
|
||||
*
|
||||
* 注意情况:
|
||||
* - 第一个 `+` 之后的所有内容全部识别为元数据
|
||||
* - `1.0+METADATA-M4`, metadata="METADATA-M4"
|
||||
* - 如果不确定版本号是否合法, 可以使用 [regex101.com](https://regex101.com/r/vkijKf/1/) 进行检查
|
||||
* - 此实现使用的正则表达式为 `^(0|[1-9]\d*)\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*))?(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$`
|
||||
*/
|
||||
@Throws(IllegalArgumentException::class, NumberFormatException::class)
|
||||
@JvmStatic
|
||||
public fun parse(version: String): SemVersion {
|
||||
if (!SEM_VERSION_REGEX.matches(version)) {
|
||||
throw IllegalArgumentException("`$version` not a valid version")
|
||||
}
|
||||
var mainVersionEnd: Int = 0
|
||||
kotlin.run {
|
||||
val iterator = version.iterator()
|
||||
@ -116,24 +126,9 @@ public data class SemVersion internal constructor(
|
||||
}
|
||||
}
|
||||
return SemVersion(
|
||||
mainVersion = version.substring(0, mainVersionEnd).also { mainVersion ->
|
||||
if (mainVersion.indexOf('.') == -1) {
|
||||
throw IllegalArgumentException("$mainVersion must has more than one label")
|
||||
}
|
||||
if (mainVersion.last() == '.') {
|
||||
throw IllegalArgumentException("Version string cannot end-with `.`")
|
||||
}
|
||||
}.parseMainVersion(),
|
||||
identifier = identifier?.also {
|
||||
if (it.isBlank()) {
|
||||
throw IllegalArgumentException("The identifier cannot be blank.")
|
||||
}
|
||||
},
|
||||
metadata = metadata?.also {
|
||||
if (it.isBlank()) {
|
||||
throw IllegalArgumentException("The metadata cannot be blank.")
|
||||
}
|
||||
}
|
||||
mainVersion = version.substring(0, mainVersionEnd).parseMainVersion(),
|
||||
identifier = identifier,
|
||||
metadata = metadata
|
||||
)
|
||||
}
|
||||
|
||||
@ -153,7 +148,7 @@ public data class SemVersion internal constructor(
|
||||
*
|
||||
* 对于多个规则, 也允许使用 `||` 拼接在一起.
|
||||
* 例如:
|
||||
* - `1.x || 2.x || 3.0`
|
||||
* - `1.x || 2.x || 3.0.0`
|
||||
* - `<= 0.5.3 || >= 1.0.0`
|
||||
*
|
||||
* 特别注意:
|
||||
|
@ -23,7 +23,7 @@ internal class TestSemVersion {
|
||||
fun String.sem(): SemVersion = SemVersion.parse(this)
|
||||
assert("1.0".sem() < "1.0.1".sem())
|
||||
assert("1.0.0".sem() == "1.0".sem())
|
||||
assert("1.1".sem() > "1.0.0.1".sem())
|
||||
assert("1.1".sem() > "1.0.0".sem())
|
||||
assert("1.0-M4".sem() < "1.0-M5".sem())
|
||||
assert("1.0-M5-dev-7".sem() < "1.0-M5-dev-15".sem())
|
||||
assert("1.0-M5-dev-79".sem() < "1.0-M5-dev-7001".sem())
|
||||
@ -54,7 +54,6 @@ internal class TestSemVersion {
|
||||
}
|
||||
SemVersion.parseRangeRequirement("1.0")
|
||||
.assert("1.0").assert("1.0.0")
|
||||
.assert("1.0.0.0")
|
||||
.assertFalse("1.1.0").assertFalse("2.0.0")
|
||||
SemVersion.parseRangeRequirement("1.x")
|
||||
.assert("1.0").assert("1.1")
|
||||
@ -62,12 +61,12 @@ internal class TestSemVersion {
|
||||
.assertFalse("2.33")
|
||||
SemVersion.parseRangeRequirement("2.0 || 1.2.x")
|
||||
.assert("2.0").assert("2.0.0")
|
||||
.assertFalse("2.1").assertFalse("2.0.0.1")
|
||||
.assertFalse("2.1")
|
||||
.assert("1.2.5").assert("1.2.0").assertFalse("1.2")
|
||||
.assertFalse("1.0.0")
|
||||
SemVersion.parseRangeRequirement("1.0.0 - 114.514.1919.810")
|
||||
SemVersion.parseRangeRequirement("1.0.0 - 114.514.1919")
|
||||
.assert("1.0.0")
|
||||
.assert("114.514").assert("114.514.1919.810")
|
||||
.assert("114.514").assert("114.514.1919")
|
||||
.assertFalse("0.0.1")
|
||||
.assertFalse("4444.4444")
|
||||
SemVersion.parseRangeRequirement("[1.0.0, 19190.0]")
|
||||
@ -75,7 +74,7 @@ internal class TestSemVersion {
|
||||
.assert("19190.0").assertFalse("19198.10")
|
||||
SemVersion.parseRangeRequirement(" >= 1.0.0")
|
||||
.assert("1.0.0")
|
||||
.assert("114.514.1919.810")
|
||||
.assert("114.514.1919")
|
||||
.assertFalse("0.0.0")
|
||||
.assertFalse("0.98774587")
|
||||
SemVersion.parseRangeRequirement("> 1.0.0")
|
||||
@ -85,6 +84,16 @@ internal class TestSemVersion {
|
||||
|
||||
}
|
||||
|
||||
private fun String.check() {
|
||||
val sem = SemVersion.parse(this)
|
||||
assert(this == sem.toString()) { "$this != $sem" }
|
||||
}
|
||||
|
||||
private fun String.checkInvalid() {
|
||||
kotlin.runCatching { SemVersion.parse(this) }
|
||||
.onSuccess { assert(false) { "$this not a invalid sem-version" } }
|
||||
}
|
||||
|
||||
@Test
|
||||
internal fun testSemVersionParsing() {
|
||||
fun String.check() {
|
||||
@ -99,7 +108,7 @@ internal class TestSemVersion {
|
||||
}
|
||||
"0.0".check()
|
||||
"1.0.0".check()
|
||||
"1.2.3.4.5.6.7.8".check()
|
||||
"1.2.3.4.5.6.7.8".checkInvalid()
|
||||
"5555.0-A".check()
|
||||
"5555.0-A+METADATA".check()
|
||||
"5555.0+METADATA".check()
|
||||
@ -113,4 +122,81 @@ internal class TestSemVersion {
|
||||
"5.1+68-7".check()
|
||||
"5.1+68-".check()
|
||||
}
|
||||
@Test
|
||||
internal fun testSemVersionOfficial(){
|
||||
"""
|
||||
1.0-RC
|
||||
0.0.4
|
||||
1.2.3
|
||||
10.20.30
|
||||
1.1.2-prerelease+meta
|
||||
1.1.2+meta
|
||||
1.1.2+meta-valid
|
||||
1.0.0-alpha
|
||||
1.0.0-beta
|
||||
1.0.0-alpha.beta
|
||||
1.0.0-alpha.beta.1
|
||||
1.0.0-alpha.1
|
||||
1.0.0-alpha0.valid
|
||||
1.0.0-alpha.0valid
|
||||
1.0.0-alpha-a.b-c-somethinglong+build.1-aef.1-its-okay
|
||||
1.0.0-rc.1+build.1
|
||||
2.0.0-rc.1+build.123
|
||||
1.2.3-beta
|
||||
10.2.3-DEV-SNAPSHOT
|
||||
1.2.3-SNAPSHOT-123
|
||||
1.0.0
|
||||
2.0.0
|
||||
1.1.7
|
||||
2.0.0+build.1848
|
||||
2.0.1-alpha.1227
|
||||
1.0.0-alpha+beta
|
||||
1.2.3----RC-SNAPSHOT.12.9.1--.12+788
|
||||
1.2.3----R-S.12.9.1--.12+meta
|
||||
1.2.3----RC-SNAPSHOT.12.9.1--.12
|
||||
1.0.0+0.build.1-rc.10000aaa-kk-0.1
|
||||
1.0.0-0A.is.legal
|
||||
""".trimIndent().split('\n').asSequence()
|
||||
.filter { it.isNotBlank() }.map { it.trim() }.forEach { it.check() }
|
||||
"""
|
||||
1
|
||||
1.2.3-0123
|
||||
1.2.3-0123.0123
|
||||
1.1.2+.123
|
||||
+invalid
|
||||
-invalid
|
||||
-invalid+invalid
|
||||
-invalid.01
|
||||
alpha
|
||||
alpha.beta
|
||||
alpha.beta.1
|
||||
alpha.1
|
||||
alpha+beta
|
||||
alpha_beta
|
||||
alpha.
|
||||
alpha..
|
||||
beta
|
||||
1.0.0-alpha_beta
|
||||
-alpha.
|
||||
1.0.0-alpha..
|
||||
1.0.0-alpha..1
|
||||
1.0.0-alpha...1
|
||||
1.0.0-alpha....1
|
||||
1.0.0-alpha.....1
|
||||
1.0.0-alpha......1
|
||||
1.0.0-alpha.......1
|
||||
01.1.1
|
||||
1.01.1
|
||||
1.1.01
|
||||
1.2.3.DEV
|
||||
1.2.31.2.3----RC-SNAPSHOT.12.09.1--..12+788
|
||||
1.2.31.2.3-RC
|
||||
-1.0.3-gamma+b7718
|
||||
+justmeta
|
||||
9.8.7+meta+meta
|
||||
9.8.7-whatever+meta+meta
|
||||
99999999999999999999999.999999999999999999.99999999999999999----RC-SNAPSHOT.12.09.1--------------------------------..12
|
||||
""".trimIndent().split('\n').asSequence()
|
||||
.filter { it.isNotBlank() }.map { it.trim() }.forEach { it.checkInvalid() }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user