| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- """Regenerate motian_bridge/dialects/v20/VKFly.py from the dialect submodule.
- The generated module must never be hand-edited. Run this script after updating
- the `msg_definitions` submodule, then commit both the submodule pointer and the
- regenerated file.
- """
- import argparse
- import hashlib
- import logging
- import subprocess
- import sys
- import tempfile
- from pathlib import Path
- if __package__ in (None, ""):
- # Allow `python tools/gen_dialect.py` as well as `from tools import ...`.
- sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
- ROOT = Path(__file__).resolve().parent.parent
- OUTPUT = ROOT / "motian_bridge" / "dialects" / "v20" / "VKFly.py"
- SOURCE = ROOT / "msg_definitions" / "msg_definitions" / "VKFly.xml"
- INCLUDES = ("common.xml", "standard.xml", "minimal.xml")
- LOG = logging.getLogger("gen_dialect")
- def _sha256(path: Path) -> str:
- digest = hashlib.sha256()
- with open(path, "rb") as stream:
- for block in iter(lambda: stream.read(1 << 20), b""):
- digest.update(block)
- return digest.hexdigest()
- def check_sources() -> None:
- """Fail early with an actionable message instead of a mavgen traceback."""
- missing = [path for path in (SOURCE, *(SOURCE.parent / name for name in INCLUDES))
- if not path.is_file()]
- if missing:
- listing = "\n".join(f" - {path}" for path in missing)
- raise SystemExit(
- "MAVLink XML sources are missing:\n"
- f"{listing}\n"
- "Initialize the dialect submodule first:\n"
- " git submodule update --init --recursive"
- )
- def mavgen(extra_args: list[str], output: Path) -> None:
- command = [
- sys.executable, "-m", "pymavlink.tools.mavgen",
- "--lang", "Python",
- "--wire-protocol", "2.0",
- "--output", str(output),
- *extra_args,
- str(SOURCE),
- ]
- LOG.debug("running: %s", " ".join(command))
- subprocess.run(command, cwd=ROOT, check=True)
- def generate(dry_run: bool = False, check: bool = False, no_validate: bool = False) -> bool:
- """Generate the dialect. Returns True when the committed file was updated."""
- check_sources()
- previous = _sha256(OUTPUT) if OUTPUT.is_file() else None
- with tempfile.TemporaryDirectory(prefix="mavgen-") as directory:
- candidate = Path(directory) / "VKFly.py"
- mavgen(["--no-validate"] if no_validate else [], candidate)
- generated = candidate.read_bytes()
- if check:
- if previous is None:
- raise SystemExit(f"{OUTPUT} does not exist; run: python tools/gen_dialect.py")
- if _sha256(OUTPUT) != hashlib.sha256(generated).hexdigest():
- raise SystemExit(
- f"{OUTPUT} is stale. Regenerate with: python tools/gen_dialect.py"
- )
- LOG.info("generated dialect matches the submodule XML")
- return False
- if previous == hashlib.sha256(generated).hexdigest():
- LOG.info("generated dialect already up to date")
- return False
- if dry_run:
- LOG.info("dry run: %s would be regenerated", OUTPUT)
- return True
- OUTPUT.parent.mkdir(parents=True, exist_ok=True)
- OUTPUT.write_bytes(generated)
- LOG.info("wrote %s (%d bytes)", OUTPUT, len(generated))
- return True
- def main() -> None:
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument("--check", action="store_true",
- help="verify the committed file matches the XML; do not write")
- parser.add_argument("--dry-run", action="store_true",
- help="report whether regeneration is needed; do not write")
- parser.add_argument("--no-validate", action="store_true",
- help="pass --no-validate to mavgen (skips upstream enum warnings)")
- parser.add_argument("--quiet", action="store_true")
- args = parser.parse_args()
- logging.basicConfig(
- level=logging.WARNING if args.quiet else logging.INFO,
- format="%(levelname)s %(name)s: %(message)s",
- )
- try:
- generate(dry_run=args.dry_run, check=args.check, no_validate=args.no_validate)
- except subprocess.CalledProcessError as exc:
- raise SystemExit(f"mavgen failed with exit code {exc.returncode}")
- if __name__ == "__main__":
- main()
|