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

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env python3
"""Confirm that a Git remote points at the configured release repository."""
from __future__ import annotations
import argparse
from pathlib import Path
import re
import sys
from urllib.parse import unquote, urlsplit
class RemoteValidationError(ValueError):
pass
def repository_identity(value: str) -> tuple[str, str]:
if not value or any(character in value for character in "\r\n\0"):
raise RemoteValidationError("repository URL is empty or malformed")
scp = re.fullmatch(r"(?:[^@/:]+@)?([^/:]+):(.+)", value)
if scp is not None and "://" not in value:
return _remote_identity(scp.group(1), scp.group(2))
parts = urlsplit(value)
if parts.scheme in {"https", "http", "ssh", "git"}:
hostname = parts.hostname
if hostname is None:
raise RemoteValidationError("repository URL has no host")
host = hostname.casefold()
if parts.port is not None:
host += f":{parts.port}"
return _remote_identity(host, unquote(parts.path))
if parts.scheme == "file":
return "file", str(Path(unquote(parts.path)).expanduser().resolve())
if parts.scheme:
raise RemoteValidationError(f"unsupported repository URL scheme: {parts.scheme}")
return "file", str(Path(value).expanduser().resolve())
def remote_matches(actual: str, expected: list[str]) -> bool:
actual_identity = repository_identity(actual)
return any(repository_identity(candidate) == actual_identity for candidate in expected)
def _remote_identity(host: str, path: str) -> tuple[str, str]:
normalized = path.strip("/")
if normalized.endswith(".git"):
normalized = normalized[:-4]
if not host or not normalized or normalized.startswith("../"):
raise RemoteValidationError("repository URL has an invalid host or path")
return host.casefold(), normalized
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("actual")
parser.add_argument("expected", nargs="+")
arguments = parser.parse_args()
try:
if not remote_matches(arguments.actual, arguments.expected):
raise RemoteValidationError(
"configured Git remote does not point at the expected release repository"
)
except RemoteValidationError as exc:
print(f"Release remote validation failed: {exc}", file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())