Skip to content

Commit 1d40b5a

Browse files
committed
✨ feat(updator): 替换为采用 Semver 语义化版本来比较版本
1 parent 33836da commit 1d40b5a

2 files changed

Lines changed: 93 additions & 25 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import re
2+
3+
4+
class VersionComparator:
5+
@staticmethod
6+
def compare_version(v1: str, v2: str) -> int:
7+
"""根据 Semver 语义版本规范来比较版本号的大小。支持不仅局限于 3 个数字的版本号,并处理预发布标签。
8+
9+
参考: https://semver.org/lang/zh-CN/
10+
11+
返回 1 表示 v1 > v2,返回 -1 表示 v1 < v2,返回 0 表示 v1 = v2。
12+
"""
13+
v1 = v1.lower().replace("v", "")
14+
v2 = v2.lower().replace("v", "")
15+
16+
def split_version(version):
17+
match = re.match(
18+
r"^([0-9]+(?:\.[0-9]+)*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+(.+))?$",
19+
version,
20+
)
21+
if not match:
22+
return [], None
23+
major_minor_patch = match.group(1).split(".")
24+
prerelease = match.group(2)
25+
# buildmetadata = match.group(3) # 构建元数据在比较时忽略
26+
parts = [int(x) for x in major_minor_patch]
27+
prerelease = VersionComparator._split_prerelease(prerelease)
28+
return parts, prerelease
29+
30+
v1_parts, v1_prerelease = split_version(v1)
31+
v2_parts, v2_prerelease = split_version(v2)
32+
33+
# 比较数字部分
34+
length = max(len(v1_parts), len(v2_parts))
35+
v1_parts.extend([0] * (length - len(v1_parts)))
36+
v2_parts.extend([0] * (length - len(v2_parts)))
37+
38+
for i in range(length):
39+
if v1_parts[i] > v2_parts[i]:
40+
return 1
41+
elif v1_parts[i] < v2_parts[i]:
42+
return -1
43+
44+
# 比较预发布标签
45+
if v1_prerelease is None and v2_prerelease is not None:
46+
return 1 # 没有预发布标签的版本高于有预发布标签的版本
47+
elif v1_prerelease is not None and v2_prerelease is None:
48+
return -1 # 有预发布标签的版本低于没有预发布标签的版本
49+
elif v1_prerelease is not None and v2_prerelease is not None:
50+
len_pre = max(len(v1_prerelease), len(v2_prerelease))
51+
for i in range(len_pre):
52+
p1 = v1_prerelease[i] if i < len(v1_prerelease) else None
53+
p2 = v2_prerelease[i] if i < len(v2_prerelease) else None
54+
55+
if p1 is None and p2 is not None:
56+
return -1
57+
elif p1 is not None and p2 is None:
58+
return 1
59+
elif isinstance(p1, int) and isinstance(p2, str):
60+
return -1
61+
elif isinstance(p1, str) and isinstance(p2, int):
62+
return 1
63+
elif isinstance(p1, int) and isinstance(p2, int):
64+
if p1 > p2:
65+
return 1
66+
elif p1 < p2:
67+
return -1
68+
elif isinstance(p1, str) and isinstance(p2, str):
69+
if p1 > p2:
70+
return 1
71+
elif p1 < p2:
72+
return -1
73+
return 0 # 预发布标签完全相同
74+
75+
return 0 # 数字部分和预发布标签都相同
76+
77+
@staticmethod
78+
def _split_prerelease(prerelease):
79+
if not prerelease:
80+
return None
81+
parts = prerelease.split(".")
82+
result = []
83+
for part in parts:
84+
if part.isdigit():
85+
result.append(int(part))
86+
else:
87+
result.append(part)
88+
return result

astrbot/core/zip_updator.py

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
from astrbot.core.utils.io import on_error, download_file
1010
from astrbot.core import logger
11+
from astrbot.core.utils.version_comparator import VersionComparator
1112

1213

1314
class ReleaseInfo:
@@ -102,31 +103,10 @@ async def update(self):
102103
raise NotImplementedError()
103104

104105
def compare_version(self, v1: str, v2: str) -> int:
105-
"""
106-
比较两个版本号的大小。
107-
返回 1 表示 v1 > v2,返回 -1 表示 v1 < v2,返回 0 表示 v1 = v2。
108-
支持任意长度的版本号,如v1.2.3或v3.5.3.1。
109-
"""
110-
v1 = v1.replace("v", "")
111-
v2 = v2.replace("v", "")
112-
v1_parts = v1.split(".")
113-
v2_parts = v2.split(".")
114-
115-
# 获取最长的版本号长度
116-
length = max(len(v1_parts), len(v2_parts))
117-
118-
# 将短版本号补0以便比较
119-
v1_parts.extend(["0"] * (length - len(v1_parts)))
120-
v2_parts.extend(["0"] * (length - len(v2_parts)))
121-
122-
for i in range(length):
123-
if int(v1_parts[i]) > int(v2_parts[i]):
124-
return 1
125-
elif int(v1_parts[i]) < int(v2_parts[i]):
126-
return -1
127-
return 0
128-
129-
async def check_update(self, url: str, current_version: str) -> ReleaseInfo:
106+
"""Semver 版本比较"""
107+
return VersionComparator.compare_version(v1, v2)
108+
109+
async def check_update(self, url: str, current_version: str) -> ReleaseInfo | None:
130110
update_data = await self.fetch_release_info(url)
131111
tag_name = update_data[0]["tag_name"]
132112

0 commit comments

Comments
 (0)