84 lines
2.4 KiB
Python
Executable File
84 lines
2.4 KiB
Python
Executable File
#!/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())
|