初始化奇妙小屏幕控制器项目
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
_VERSION_PATTERN = re.compile(r"^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$")
|
||||
_FEATURE_UPDATED_AT_PATTERN = re.compile(
|
||||
r"^[0-9]{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])T(?:[01][0-9]|2[0-3]):[0-5][0-9]\+08:00$"
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True, order=True)
|
||||
class SoftwareVersion:
|
||||
major: int
|
||||
minor: int
|
||||
patch: int
|
||||
|
||||
@classmethod
|
||||
def parse(cls, value: str) -> "SoftwareVersion":
|
||||
if not isinstance(value, str):
|
||||
raise ValueError("software version must be a string")
|
||||
match = _VERSION_PATTERN.fullmatch(value.strip())
|
||||
if match is None:
|
||||
raise ValueError("software version must use strict MAJOR.MINOR.PATCH digits")
|
||||
return cls(*(int(part) for part in match.groups()))
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"{self.major}.{self.minor}.{self.patch}"
|
||||
|
||||
|
||||
def read_software_version(code_root: Path) -> SoftwareVersion:
|
||||
path = Path(code_root) / "VERSION"
|
||||
try:
|
||||
return SoftwareVersion.parse(path.read_text(encoding="utf-8"))
|
||||
except OSError as exc:
|
||||
raise RuntimeError(f"software VERSION file is unreadable: {path}") from exc
|
||||
|
||||
|
||||
def read_feature_updated_at(code_root: Path) -> str:
|
||||
path = Path(code_root) / "FEATURE_UPDATED_AT"
|
||||
try:
|
||||
value = path.read_text(encoding="utf-8").strip()
|
||||
except OSError as exc:
|
||||
raise RuntimeError(f"feature update timestamp file is unreadable: {path}") from exc
|
||||
if _FEATURE_UPDATED_AT_PATTERN.fullmatch(value) is None:
|
||||
raise ValueError("feature update timestamp must use YYYY-MM-DDTHH:MM+08:00")
|
||||
try:
|
||||
parsed = datetime.fromisoformat(value)
|
||||
except ValueError as exc:
|
||||
raise ValueError("feature update timestamp is not a valid calendar time") from exc
|
||||
if parsed.utcoffset() != timedelta(hours=8):
|
||||
raise ValueError("feature update timestamp must use Beijing UTC+08:00")
|
||||
return value
|
||||
Reference in New Issue
Block a user