Add registry-backed module package releases
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate the optional GovOPlaN developer convenience meta-package."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import tomllib
|
||||
|
||||
|
||||
META_ROOT = Path(__file__).resolve().parents[2]
|
||||
DIRECT = re.compile(r"^(govoplan-[a-z0-9-]+)(?:\[([^]]+)\])?\s+@\s+.*@v([A-Za-z0-9._+!-]+)$")
|
||||
LOCAL_CORE = re.compile(r"^(?:-e\s+)?\.\./govoplan-core(?:\[([^]]+)\])?$")
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--workspace", type=Path, default=META_ROOT.parent)
|
||||
parser.add_argument(
|
||||
"--requirements",
|
||||
type=Path,
|
||||
default=META_ROOT / "requirements-release.txt",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
type=Path,
|
||||
default=META_ROOT / "packages" / "govoplan-meta" / "pyproject.toml",
|
||||
)
|
||||
parser.add_argument("--check", action="store_true")
|
||||
return parser
|
||||
|
||||
|
||||
def render(*, workspace: Path, requirements: Path) -> str:
|
||||
core = tomllib.loads((workspace / "govoplan-core/pyproject.toml").read_text(encoding="utf-8"))["project"]
|
||||
version = str(core["version"])
|
||||
base: list[str] = []
|
||||
for raw in requirements.read_text(encoding="utf-8").splitlines():
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#"):
|
||||
continue
|
||||
local = LOCAL_CORE.fullmatch(line)
|
||||
if local:
|
||||
extra = f"[{local.group(1)}]" if local.group(1) else ""
|
||||
base.append(f"govoplan-core{extra}=={version}")
|
||||
continue
|
||||
match = DIRECT.fullmatch(line)
|
||||
if match is None:
|
||||
raise ValueError(f"unsupported release requirement: {line!r}")
|
||||
extra = f"[{match.group(2)}]" if match.group(2) else ""
|
||||
base.append(f"{match.group(1)}{extra}=={match.group(3)}")
|
||||
|
||||
base_names = {_requirement_name(item) for item in base}
|
||||
full: list[str] = []
|
||||
for project_path in sorted(workspace.glob("govoplan-*/pyproject.toml")):
|
||||
project = tomllib.loads(project_path.read_text(encoding="utf-8"))["project"]
|
||||
name = str(project.get("name") or "")
|
||||
package_version = str(project.get("version") or "")
|
||||
if name.startswith("govoplan-") and name not in base_names:
|
||||
full.append(f"{name}=={package_version}")
|
||||
|
||||
return "\n".join(
|
||||
[
|
||||
"[build-system]",
|
||||
'requires = ["setuptools>=69", "wheel"]',
|
||||
'build-backend = "setuptools.build_meta"',
|
||||
"",
|
||||
"[project]",
|
||||
'name = "govoplan"',
|
||||
f'version = {json.dumps(version)}',
|
||||
'description = "Developer convenience package for a versioned GovOPlaN composition"',
|
||||
'readme = "README.md"',
|
||||
'requires-python = ">=3.12"',
|
||||
'license = { text = "AGPL-3.0-or-later" }',
|
||||
"dependencies = [",
|
||||
*[f" {json.dumps(item)}," for item in base],
|
||||
"]",
|
||||
"",
|
||||
"[project.optional-dependencies]",
|
||||
"full = [",
|
||||
*[f" {json.dumps(item)}," for item in full],
|
||||
"]",
|
||||
"",
|
||||
"[project.urls]",
|
||||
'Repository = "https://git.add-ideas.de/GovOPlaN/govoplan"',
|
||||
'Documentation = "https://govoplan.add-ideas.de"',
|
||||
"",
|
||||
"[tool.setuptools.packages.find]",
|
||||
'where = ["src"]',
|
||||
"",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def _requirement_name(value: str) -> str:
|
||||
return value.split("[", 1)[0].split("==", 1)[0]
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = build_parser().parse_args()
|
||||
try:
|
||||
expected = render(
|
||||
workspace=args.workspace.expanduser().resolve(),
|
||||
requirements=args.requirements.expanduser().resolve(),
|
||||
)
|
||||
except (OSError, KeyError, ValueError, tomllib.TOMLDecodeError) as exc:
|
||||
print(f"error: {exc}")
|
||||
return 1
|
||||
output = args.output.expanduser()
|
||||
current = output.read_text(encoding="utf-8") if output.is_file() else None
|
||||
if args.check:
|
||||
if current != expected:
|
||||
print(f"error: developer meta-package is stale: {output}")
|
||||
return 1
|
||||
print("Developer meta-package is synchronized.")
|
||||
return 0
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
output.write_text(expected, encoding="utf-8")
|
||||
print(f"Developer meta-package written to {output}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user