112 lines
3.3 KiB
Python
Executable file
112 lines
3.3 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Version management for UniversalisOS.
|
|
|
|
Reads VERSION file and provides version strings for builds, tags, and releases.
|
|
Can be called from Makefiles or release scripts.
|
|
|
|
Usage:
|
|
python tools/version.py # full version (1.0.0-alpha.1)
|
|
python tools/version.py --major # major only (1)
|
|
python tools/version.py --minor # minor only (0)
|
|
python tools/version.py --patch # patch only (0)
|
|
python tools/version.py --kernel armv7 qemu-arm-virt
|
|
# arch.platform suffix
|
|
"""
|
|
|
|
import argparse
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
VERSION_FILE = Path(__file__).resolve().parent.parent / "VERSION"
|
|
|
|
SEMVER_RE = re.compile(
|
|
r"^(?P<major>0|[1-9]\d*)"
|
|
r"\.(?P<minor>0|[1-9]\d*)"
|
|
r"\.(?P<patch>0|[1-9]\d*)"
|
|
r"(?:-(?P<pre>[0-9A-Za-z.-]+))?"
|
|
r"(?:\+(?P<build>[0-9A-Za-z.-]+))?$"
|
|
)
|
|
|
|
|
|
def read_version() -> str:
|
|
"""Read and return the raw version string from VERSION file."""
|
|
if not VERSION_FILE.exists():
|
|
print(f"error: {VERSION_FILE} not found", file=sys.stderr)
|
|
sys.exit(1)
|
|
return VERSION_FILE.read_text().strip()
|
|
|
|
|
|
def parse_version(raw: str) -> dict:
|
|
"""Parse a semver string into components."""
|
|
m = SEMVER_RE.match(raw)
|
|
if not m:
|
|
print(f"error: invalid semver '{raw}'", file=sys.stderr)
|
|
sys.exit(1)
|
|
return m.groupdict()
|
|
|
|
|
|
def write_version(version: str) -> None:
|
|
"""Write a version string to VERSION file."""
|
|
VERSION_FILE.write_text(version + "\n")
|
|
|
|
|
|
def bump(version: str, component: str) -> str:
|
|
"""Bump a version component and reset lower components."""
|
|
v = parse_version(version)
|
|
major, minor, patch = int(v["major"]), int(v["minor"]), int(v["patch"])
|
|
|
|
if component == "major":
|
|
major += 1
|
|
minor = 0
|
|
patch = 0
|
|
elif component == "minor":
|
|
minor += 1
|
|
patch = 0
|
|
elif component == "patch":
|
|
patch += 1
|
|
|
|
return f"{major}.{minor}.{patch}"
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="UniversalisOS version tool")
|
|
group = parser.add_mutually_exclusive_group()
|
|
group.add_argument("--major", action="store_true", help="Print major version")
|
|
group.add_argument("--minor", action="store_true", help="Print minor version")
|
|
group.add_argument("--patch", action="store_true", help="Print patch version")
|
|
group.add_argument("--bump", choices=["major", "minor", "patch"],
|
|
help="Bump a version component and update VERSION file")
|
|
parser.add_argument("--kernel", nargs=2, metavar=("ARCH", "PLATFORM"),
|
|
help="Append arch.platform suffix (e.g. armv7 qemu-arm-virt)")
|
|
parser.add_argument("--set", dest="set_version", metavar="VERSION",
|
|
help="Set VERSION file to the given value")
|
|
|
|
args = parser.parse_args()
|
|
raw = read_version()
|
|
|
|
if args.set_version:
|
|
write_version(args.set_version)
|
|
raw = args.set_version
|
|
|
|
if args.bump:
|
|
raw = bump(raw, args.bump)
|
|
write_version(raw)
|
|
|
|
v = parse_version(raw)
|
|
|
|
if args.major:
|
|
print(v["major"])
|
|
elif args.minor:
|
|
print(v["minor"])
|
|
elif args.patch:
|
|
print(v["patch"])
|
|
elif args.kernel:
|
|
arch, platform = args.kernel
|
|
print(f"{raw}.{arch}.{platform}")
|
|
else:
|
|
print(raw)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|