| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
- """
- 语义版本解析与校验,用于客户端分发的 version_code(如 1.2.3)。
- """
- import re
- from typing import Tuple
- # 允许:x / x.y / x.y.z,可选 -prerelease 后缀;前导 v 可选
- VERSION_CODE_PATTERN = re.compile(
- r"^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:[-.]([a-zA-Z0-9.-]+))?$",
- re.IGNORECASE,
- )
- def parse_version_code(version_code: str) -> Tuple[int, int, int, str]:
- """
- 将 version_code 解析为可比较元组 (major, minor, patch, prerelease)。
- 不符合格式的返回 (0, 0, 0, raw),保证可排序。
- """
- if not version_code or not isinstance(version_code, str):
- return (0, 0, 0, "")
- s = version_code.strip()
- m = VERSION_CODE_PATTERN.match(s)
- if not m:
- return (0, 0, 0, s)
- major = int(m.group(1))
- minor = int(m.group(2)) if m.group(2) else 0
- patch = int(m.group(3)) if m.group(3) else 0
- prerelease = (m.group(4) or "").strip()
- return (major, minor, patch, prerelease)
- def version_sort_key(version_code: str) -> Tuple[int, int, int, str]:
- """用于 sorted(key=...) 的排序键。"""
- return parse_version_code(version_code)
- def validate_version_code(version_code: str) -> None:
- """校验 version_code 格式,不符合则抛出 ValueError。"""
- if not version_code or not isinstance(version_code, str):
- raise ValueError("版本号不能为空")
- s = version_code.strip()
- if len(s) > 32:
- raise ValueError("版本号长度不能超过 32 字符")
- if not VERSION_CODE_PATTERN.match(s):
- raise ValueError(
- "版本号格式应为数字版本,如 1、1.2、1.2.3,可选 -prerelease 后缀(如 1.0.0-beta)"
- )
|