Files
OrcaSlicer/tools/run_codegen.py

121 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""
Convenience script: runs the codegen pipeline.
1. Compile .proto -> binary descriptor set (protoc)
2. Generate C++ from descriptors (config_codegen.py)
3. Validate output against original
Usage:
python tools/run_codegen.py # full pipeline
python tools/run_codegen.py --validate-only # just validate
"""
import argparse
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
PROTO_DIR = ROOT / "src" / "PrintConfigs"
CODEGEN_OUT = ROOT / "src" / "slic3r" / "GUI" / "generated"
DESC_FILE = ROOT / "config.desc"
LAYOUT_YAML = PROTO_DIR / "layout.yaml"
def _ensure_pyyaml():
"""Install pyyaml if not present — needed for tab layout generation."""
try:
import yaml # noqa: F401
return True
except ImportError:
print(" Installing pyyaml (required for tab layout generation)...")
result = subprocess.run(
[sys.executable, "-m", "pip", "install", "pyyaml", "-q"],
capture_output=True)
if result.returncode != 0:
print(" ERROR: failed to install pyyaml")
return False
return True
def run(cmd, **kwargs):
print(f" $ {' '.join(str(c) for c in cmd)}")
result = subprocess.run(cmd, **kwargs)
if result.returncode != 0:
print(f" FAILED (exit code {result.returncode})")
return False
return True
def _protoc_cmd():
"""Return the protoc command list. Prefers standalone protoc, falls back to grpc_tools."""
if shutil.which("protoc"):
return ["protoc"]
try:
import grpc_tools.protoc # noqa: F401
return [sys.executable, "-m", "grpc_tools.protoc"]
except ImportError:
pass
print(" ERROR: protoc not found. Install protoc or run: pip install grpcio-tools")
return None
def step_compile():
print("\n=== Step 1: Compile .proto -> descriptor set ===")
proto_files = [f for f in PROTO_DIR.glob("*.proto") if not f.name.endswith("_gen.proto") and f.name != "config_metadata.proto"]
if not proto_files:
print(" ERROR: No .proto files found")
return False
protoc = _protoc_cmd()
if protoc is None:
return False
return run(protoc + [
f"--proto_path={PROTO_DIR}",
f"--descriptor_set_out={DESC_FILE}",
"--include_imports",
] + [str(f) for f in proto_files])
def step_generate():
print("\n=== Step 2: Generate C++ from descriptors + layout.yaml ===")
_ensure_pyyaml() # tab layout generation requires pyyaml
return run([sys.executable, str(ROOT / "tools" / "config_codegen.py"),
str(DESC_FILE), str(CODEGEN_OUT)])
def step_validate():
print("\n=== Step 3: Validate ===")
return run([sys.executable, str(ROOT / "tools" / "validate_codegen.py")])
def main():
parser = argparse.ArgumentParser(description="Run OrcaSlicer config codegen pipeline")
parser.add_argument("--validate-only", action="store_true",
help="Only run validation")
parser.add_argument("--no-validate", action="store_true",
help="Skip validation step (used by cmake build)")
args = parser.parse_args()
if args.validate_only:
sys.exit(0 if step_validate() else 1)
for name, fn in [("Compile", step_compile), ("Generate", step_generate)]:
if not fn():
print(f"\n*** Pipeline FAILED at: {name} ***")
sys.exit(1)
if not args.no_validate:
if not step_validate():
print("\n*** Validate FAILED (run with --no-validate to skip) ***")
sys.exit(1)
print("\n=== Pipeline completed successfully ===")
if __name__ == "__main__":
main()