Add channel-aware release tooling and updater recovery

This commit is contained in:
2026-09-10 00:39:37 +02:00
parent cc48bf45d2
commit 0a89323533
42 changed files with 7840 additions and 0 deletions

83
scripts/set_version.py Executable file
View File

@@ -0,0 +1,83 @@
#!/usr/bin/env python3
"""Update the authoritative launcher version and its project metadata mirror."""
from __future__ import annotations
import argparse
import os
from pathlib import Path
import re
import sys
PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from scripts.release_lib import ReleaseToolError, load_config # noqa: E402
from ptlinux.update_resolver import SemanticVersion
SOURCE_PATTERN = re.compile(
r'(?m)^__version__ = "[0-9]+\.[0-9]+\.[0-9]+(?:-(?:beta|rc)\.[0-9]+)?"$'
)
PROJECT_PATTERN = re.compile(
r'(?m)^version = "[0-9]+\.[0-9]+\.[0-9]+(?:-(?:beta|rc)\.[0-9]+)?"$'
)
def replace_once(path: Path, pattern: re.Pattern[str], replacement: str) -> None:
try:
original = path.read_text(encoding="utf-8")
except (OSError, UnicodeError) as exc:
raise ReleaseToolError(f"cannot read version file {path}: {exc}") from exc
updated, count = pattern.subn(replacement, original)
if count != 1:
raise ReleaseToolError(
f"expected exactly one version declaration in {path}, found {count}"
)
if updated == original:
return
temporary = path.with_name(f".{path.name}.{os.getpid()}.tmp")
try:
with temporary.open("x", encoding="utf-8", newline="\n") as handle:
handle.write(updated)
handle.flush()
os.fsync(handle.fileno())
temporary.chmod(path.stat().st_mode & 0o777)
os.replace(temporary, path)
finally:
temporary.unlink(missing_ok=True)
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("version")
arguments = parser.parse_args()
try:
SemanticVersion.parse(arguments.version)
config = load_config()
version_source = config.get("version_source")
if not isinstance(version_source, str):
raise ReleaseToolError("version_source must be configured")
replace_once(
PROJECT_ROOT / version_source,
SOURCE_PATTERN,
f'__version__ = "{arguments.version}"',
)
mirrors = config.get("version_mirrors")
if not isinstance(mirrors, list) or not all(isinstance(item, str) for item in mirrors):
raise ReleaseToolError("version_mirrors must be configured")
for mirror in mirrors:
replace_once(
PROJECT_ROOT / mirror,
PROJECT_PATTERN,
f'version = "{arguments.version}"',
)
except (OSError, ValueError, ReleaseToolError) as exc:
print(f"Version update failed: {exc}", file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())