from __future__ import annotations
import argparse
import contextlib
import pathlib
import sys
import tomllib
from collections.abc import Generator
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Read installer/dependency-binaries.toml and emit TSV rows."
)
parser.add_argument(
"manifest",
nargs="?",
default="installer/dependency-binaries.toml",
help="Path to the dependency-binaries manifest.",
)
parser.add_argument(
"--output",
"-o",
default=None,
help="Output file path (default: stdout).",
)
return parser.parse_args()
def _collect_manifest_lines(
manifest_path: pathlib.Path,
) -> list[bytes] | int:
with manifest_path.open("rb") as handle:
manifest = tomllib.load(handle)
seen_packages: set[str] = set()
output_lines: list[bytes] = []
for entry in manifest["dependency_binaries"]:
package = entry["package"]
if package in seen_packages:
print(
f"error: duplicate package '{package}' in manifest",
file=sys.stderr,
)
return 1
seen_packages.add(package)
line = f"{entry['package']}\t{entry['binary']}\t{entry['version']}\n".encode()
output_lines.append(line)
return output_lines
@contextlib.contextmanager
def _open_output(output: str | None) -> Generator:
if output is not None:
if output == "":
print("error: output path cannot be empty", file=sys.stderr)
raise SystemExit(1)
with pathlib.Path(output).open("wb") as handle:
yield handle
else:
yield sys.stdout.buffer
def _write_lines(lines: list[bytes], output: str | None) -> None:
with _open_output(output) as handle:
handle.writelines(lines)
def main() -> int:
args = parse_args()
result = _collect_manifest_lines(pathlib.Path(args.manifest))
match result:
case int():
return result
case list():
_write_lines(result, args.output)
return 0
if __name__ == "__main__":
raise SystemExit(main())