diff --git a/freecad/silo_commands.py b/freecad/silo_commands.py index 661b800..6013cb5 100644 --- a/freecad/silo_commands.py +++ b/freecad/silo_commands.py @@ -965,6 +965,65 @@ class SiloPullDialog: return None +def _pull_dependencies(part_number, progress_callback=None): + """Recursively pull all BOM children that have files on the server. + + Returns list of (part_number, dest_path) tuples for successfully pulled files. + Skips children that already exist locally. + """ + pulled = [] + try: + bom = _client.get_bom(part_number) + except Exception as e: + FreeCAD.Console.PrintWarning(f"Could not fetch BOM for {part_number}: {e}\n") + return pulled + + for entry in bom: + child_pn = entry.get("child_part_number") + if not child_pn: + continue + + # Skip if already exists locally + existing = find_file_by_part_number(child_pn) + if existing and existing.exists(): + FreeCAD.Console.PrintMessage(f" {child_pn}: already exists at {existing}\n") + # Still recurse — this child may itself be an assembly with missing deps + _pull_dependencies(child_pn, progress_callback) + continue + + # Check if this child has a file on the server + try: + latest = _client.latest_file_revision(child_pn) + except Exception: + latest = None + + if not latest or not latest.get("file_key"): + FreeCAD.Console.PrintMessage(f" {child_pn}: no file on server, skipping\n") + continue + + # Determine destination path + child_desc = entry.get("child_description", "") + dest_path = get_cad_file_path(child_pn, child_desc) + dest_path.parent.mkdir(parents=True, exist_ok=True) + + rev_num = latest["revision_number"] + FreeCAD.Console.PrintMessage(f" Pulling {child_pn} rev {rev_num}...\n") + + try: + ok = _client._download_file( + child_pn, rev_num, str(dest_path), progress_callback=progress_callback + ) + if ok: + pulled.append((child_pn, dest_path)) + except Exception as e: + FreeCAD.Console.PrintWarning(f" Failed to pull {child_pn}: {e}\n") + + # Recurse into child (it may be a sub-assembly) + _pull_dependencies(child_pn, progress_callback) + + return pulled + + class Silo_Pull: """Download from MinIO / sync from database.""" @@ -1092,6 +1151,17 @@ class Silo_Pull: FreeCAD.Console.PrintMessage(f"Pulled revision {rev_num} of {part_number}\n") + # Pull assembly dependencies before opening so links resolve + if item.get("item_type") == "assembly": + progress.setLabelText(f"Pulling dependencies for {part_number}...") + progress.setValue(0) + progress.show() + dep_pulled = _pull_dependencies(part_number, progress_callback=on_progress) + progress.setValue(100) + progress.close() + if dep_pulled: + FreeCAD.Console.PrintMessage(f"Pulled {len(dep_pulled)} dependency file(s)\n") + # Close existing document if open, then reopen if doc and doc.FileName == str(dest_path): FreeCAD.closeDocument(doc.Name)