import hashlib import json import os import stat import FreeCAD as App FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d" def file_snapshot(document): obj = document.getObject("IncludedProbe") path = str(obj.File) exists = os.path.isfile(path) payload = open(path, "rb").read() if exists else b"" mode = stat.S_IMODE(os.stat(path).st_mode) if exists else None return { "objectSet": [{"name": item.Name, "typeId": item.TypeId} for item in document.Objects], "object": { "name": obj.Name, "typeId": obj.TypeId, "propertyTypeId": obj.getTypeIdOfProperty("File"), "value": path, "baseName": os.path.basename(path) if path else "", "exists": exists, "bytes": len(payload), "sha256": hashlib.sha256(payload).hexdigest() if payload else "", "mode": mode, "writeBits": mode & 0o222 if mode is not None else None, "underTransientDir": bool(path) and os.path.commonpath([os.path.abspath(path), os.path.abspath(document.TransientDir)]) == os.path.abspath(document.TransientDir), "propertyStatus": [str(item) for item in obj.getPropertyStatus("File")], "editorMode": [str(item) for item in obj.getEditorMode("File")], "state": [str(item) for item in obj.State], "statusString": str(obj.getStatusString()), "hasShapeProperty": "Shape" in obj.PropertiesList, }, } def create_native(path, source_path): document = App.newDocument("PropertyFileIncludedRoundtrip") try: obj = document.addObject("App::DocumentObjectFileIncluded", "IncludedProbe") obj.File = (source_path, "payload.bin") document.recompute() document.saveAs(path) finally: App.closeDocument(document.Name) reopened = App.openDocument(path) try: reopened.recompute() return file_snapshot(reopened) finally: App.closeDocument(reopened.Name) def verify_native(path, resaved_path): document = App.openDocument(path) try: document.recompute() reopened = file_snapshot(document) document.saveAs(resaved_path) finally: App.closeDocument(document.Name) resaved_document = App.openDocument(resaved_path) try: resaved_document.recompute() resaved = file_snapshot(resaved_document) finally: App.closeDocument(resaved_document.Name) return {"reopened": reopened, "resaved": resaved} mode = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_MODE", "") path = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_PATH", "") resaved_path = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_RESAVED_PATH", "") source_path = os.environ.get("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_SOURCE", "") if mode == "create": result = create_native(path, source_path) elif mode == "verify": result = verify_native(path, resaved_path) else: raise RuntimeError("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_MODE must be create or verify") print("FREECAD_PROPERTY_FILEINCLUDED_ROUNDTRIP_RESULT=" + json.dumps({ "schemaVersion": 1, "status": "pass", "baselineId": "freecad-1.1.1-property-fileincluded-roundtrip", "freecadVersion": ".".join(str(value) for value in App.Version()[:3]), "gitCommit": FREECAD_COMMIT, "mode": mode, "result": result, }, sort_keys=True))