77 lines
3.7 KiB
Python
77 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Stage official source/runtime files for the headless BIM probe."""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import hashlib
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def copy_tree(source: Path, target: Path) -> None:
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copytree(source, target, dirs_exist_ok=True, ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
|
|
|
|
|
|
def copy_file(source: Path, target: Path) -> None:
|
|
target.parent.mkdir(parents=True, exist_ok=True)
|
|
shutil.copy2(source, target)
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--output", required=True, type=Path)
|
|
args = parser.parse_args()
|
|
root = Path(__file__).resolve().parents[1]
|
|
source = root / "freecad-source"
|
|
python_root = source / "build-web" / "python-install" / "lib" / "python3.12"
|
|
output = args.output.resolve()
|
|
if output.exists():
|
|
shutil.rmtree(output)
|
|
copy_tree(source / "src" / "Mod" / "BIM", output / "share" / "Mod" / "BIM")
|
|
parser_source = source / "src" / "Mod" / "BIM" / "Resources" / "ArchSqlParserGenerator.py"
|
|
grammar = source / "src" / "Mod" / "BIM" / "Resources" / "ArchSql.lark"
|
|
generated_parser = output / "share" / "Mod" / "BIM" / "generated_sql_parser.py"
|
|
subprocess.run([sys.executable, str(parser_source), str(grammar), str(generated_parser)], check=True)
|
|
copy_tree(source / "src" / "Mod" / "Draft", output / "freecad-mod" / "Draft")
|
|
copy_tree(source / "src" / "3rdParty" / "lazy_loader", output / "freecad-mod" / "lazy_loader")
|
|
schema_candidates = (
|
|
root.parent / "FreeCADBaseLib" / "sources" / "src" / "Qt-5.15.13" / "qt3d" / "src" / "3rdparty" / "assimp" / "src" / "scripts" / "StepImporter" / "schema_ifc2x3.exp",
|
|
root / "FreeCADBaseLib" / "sources" / "src" / "Qt-5.15.13" / "qt3d" / "src" / "3rdparty" / "assimp" / "src" / "scripts" / "StepImporter" / "schema_ifc2x3.exp",
|
|
)
|
|
schema = next((path for path in schema_candidates if path.exists()), None)
|
|
if schema is None:
|
|
raise FileNotFoundError("official IFC EXPRESS schema resource is unavailable")
|
|
copy_file(schema, output / "share" / "Mod" / "BIM" / "schema_ifc2x3.exp")
|
|
(output / "share" / "Mod" / "BIM" / "legacy-fixture.ifc").write_text(
|
|
"ISO-10303-21;\nHEADER;\nFILE_DESCRIPTION(('FreeCAD Web legacy probe'),'2;1');\nENDSEC;\n"
|
|
"DATA;\n#1=IFCPERSON($,$,$,$,$,$,$,$);\nENDSEC;\nEND-ISO-10303-21;\n",
|
|
encoding="ascii",
|
|
)
|
|
# DAE imports xml.sax.saxutils -> urllib.request, which needs both email
|
|
# and http.client even when the document is read from a local file.
|
|
for name in (
|
|
"encodings", "json", "xml", "re", "collections", "logging", "importlib", "zipfile", "urllib",
|
|
"email", "http",
|
|
):
|
|
copy_tree(python_root / name, output / "freecad-python" / name)
|
|
# Stage every top-level pure-Python standard-library module produced by the
|
|
# same Emscripten Python build. Import chains such as Draft -> uuid ->
|
|
# random -> pickle are implementation details of that runtime and a manual
|
|
# allow-list repeatedly omitted valid dependencies. Native extension
|
|
# modules remain excluded because this only selects ``*.py`` files.
|
|
for module in sorted(python_root.glob("*.py")):
|
|
copy_file(module, output / "freecad-python" / module.name)
|
|
manifest = []
|
|
for resource in sorted(path for path in output.rglob("*") if path.is_file()):
|
|
digest = hashlib.sha256(resource.read_bytes()).hexdigest()
|
|
manifest.append(f"{digest} {resource.relative_to(output).as_posix()}")
|
|
(output / ".resource-manifest.sha256").write_text("\n".join(manifest) + "\n", encoding="ascii")
|
|
print(output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|