3. 版本号管理
任务说明
在OTA升级流程中,版本号管理是防止回滚和重复安装的第一道防线。本案例实现一个轻量级版本号模块,支持:
- 版本号解析与存储(格式:主版本.次版本.修订号,如
2.1.0) - 版本号比较逻辑,判定候选升级包是否高于当前已安装版本
- 仅当候选版本严格高于当前版本时,返回允许升级
核心实现
# version_manager.py
from dataclasses import dataclass
@dataclass(frozen=True)
class Version:
major: int
minor: int
patch: int
@classmethod
def from_string(cls, s: str) -> "Version":
parts = s.strip().split(".")
if len(parts) != 3:
raise ValueError(f"版本号格式必须为 x.y.z,收到: {s}")
try:
major, minor, patch = (int(p) for p in parts)
except ValueError:
raise ValueError(f"版本号必须包含整数,收到: {s}")
if major < 0 or minor < 0 or patch < 0:
raise ValueError(f"版本号不允许负数: {s}")
return cls(major=major, minor=minor, patch=patch)
def __str__(self) -> str:
return f"{self.major}.{self.minor}.{self.patch}"
def __lt__(self, other: "Version") -> bool:
return (self.major, self.minor, self.patch) < (other.major, other.minor, other.patch)
def __eq__(self, other: object) -> bool:
if not isinstance(other, Version):
return NotImplemented
return (self.major, self.minor, self.patch) == (other.major, other.minor, other.patch)
def is_upgrade_allowed(current: str, candidate: str) -> tuple[bool, str]:
"""
判断候选升级包是否允许安装。
返回 (是否允许, 原因说明)。
"""
try:
cur = Version.from_string(current)
cand = Version.from_string(candidate)
except ValueError as e:
return False, str(e)
if cand > cur:
return True, f"允许升级: {candidate} > {current}"
elif cand == cur:
return False, f"拒绝: 候选版本 {candidate} 与当前版本相同,无需重复安装"
else:
return False, f"拒绝: 候选版本 {candidate} 低于当前版本 {current},禁止回滚"
# 最小调用入口
if __name__ == "__main__":
test_cases = [
("1.0.0", "1.0.1"), # 修订号升级,允许
("1.0.0", "1.1.0"), # 次版本升级,允许
("1.0.0", "2.0.0"), # 主版本升级,允许
("1.2.3", "1.2.3"), # 相同版本,拒绝
("1.2.3", "1.2.2"), # 降级,拒绝
("1.0.0", "1.0.0.1"), # 格式错误,拒绝
]
for cur, cand in test_cases:
allowed, reason = is_upgrade_allowed(cur, cand)
print(f"当前={cur:<8} 候选={cand:<8} -> {'允许' if allowed else '拒绝'} | {reason}")
运行与验证
- 将上述代码保存为
version_manager.py,无需安装第三方依赖(仅使用Python标准库)。 - 在终端执行:
python version_manager.py - 预期输出(由代码逻辑直接推出):
当前=1.0.0 候选=1.0.1 -> 允许 | 允许升级: 1.0.1 > 1.0.0
当前=1.0.0 候选=1.1.0 -> 允许 | 允许升级: 1.1.0 > 1.0.0
当前=1.0.0 候选=2.0.0 -> 允许 | 允许升级: 2.0.0 > 1.0.0
当前=1.2.3 候选=1.2.3 -> 拒绝 | 拒绝: 候选版本 1.2.3 与当前版本相同,无需重复安装
当前=1.2.3 候选=1.2.2 -> 拒绝 | 拒绝: 候选版本 1.2.2 低于当前版本 1.2.3,禁止回滚
当前=1.0.0 候选=1.0.0.1 -> 拒绝 | 版本号格式必须为 x.y.z,收到: 1.0.0.1
通过判定标准:前3条输出为“允许”,后3条为“拒绝”,且拒绝原因分别对应“相同版本”“降级”“格式错误”三类场景,即视为验证通过。
集成说明
在实际OTA升级服务中,将当前已安装版本号从持久化存储(如配置文件或数据库)读出,候选版本号由升级包元数据解析获得,调用 is_upgrade_allowed() 后根据返回的布尔值决定是否继续后续的包校验与安装流程。本模块只负责版本判定,不涉及包体下载与刷写逻辑。