From d15a0e2b4f8e1458f20622b172e99d1add47e312 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Thu, 16 Jul 2026 18:06:40 +0300 Subject: [PATCH] Bonsai: expose git describe string to titleblock templates Adds IfcGit.get_repo_description(), which returns a git-describe style string (tags, always, dirty) for the repo containing an IFC file, or None when GitPython is unavailable, the file isn't in a git repo, or the repo has no commits yet. sheeter.py's build_titleblock() now makes this available to the pystache titleblock template render as a "GitDescribe" key, falling back to an empty string rather than the literal word "None". This is purely additive: sheet.get_info() itself is untouched, no shipped titleblock SVG references the new key, and existing Revision, Identification and Name substitution behaviour is unchanged. Users who want the git description on their titleblock can reference {{GitDescribe}} in their own custom titleblock SVG. Part of the "Make revision list and most recent tag available to drawing generation" item from issue #3096. Generated with the assistance of an AI coding tool. --- .../bonsai/bim/module/drawing/sheeter.py | 7 +++++- src/bonsai/bonsai/tool/ifcgit.py | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/bonsai/bonsai/bim/module/drawing/sheeter.py b/src/bonsai/bonsai/bim/module/drawing/sheeter.py index df57b6efb5..7b54e23ed5 100644 --- a/src/bonsai/bonsai/bim/module/drawing/sheeter.py +++ b/src/bonsai/bonsai/bim/module/drawing/sheeter.py @@ -319,7 +319,12 @@ class SheetBuilder: def build_titleblock(self, root: ET.Element, sheet: ifcopenshell.entity_instance) -> None: titleblock = root.findall(f'{SVG}g[@data-type="titleblock"]')[0] image = titleblock.findall(f"{SVG}image")[0] - g = self.parse_embedded_svg(image, sheet.get_info()) + # Extend the raw IFC attribute dict with extra, non-IFC substitution + # keys available to custom titleblock templates. This does not + # change what sheet.get_info() itself returns elsewhere. + titleblock_data = dict(sheet.get_info()) + titleblock_data["GitDescribe"] = tool.IfcGit.get_repo_description(tool.Ifc.get_path()) or "" + g = self.parse_embedded_svg(image, titleblock_data) grid_north = ifcopenshell.util.geolocation.get_grid_north(tool.Ifc.get()) * -1 true_north = ifcopenshell.util.geolocation.get_true_north(tool.Ifc.get()) * -1 for north in g.iterfind(f'.//{SVG}g[@data-type="grid-north"]'): diff --git a/src/bonsai/bonsai/tool/ifcgit.py b/src/bonsai/bonsai/tool/ifcgit.py index 4ceb6fb5e5..8b13274664 100644 --- a/src/bonsai/bonsai/tool/ifcgit.py +++ b/src/bonsai/bonsai/tool/ifcgit.py @@ -40,8 +40,11 @@ try: import git import git.exc import git.objects + + GIT_AVAILABLE = True except ImportError: print("Warning: GitPython not available.") + GIT_AVAILABLE = False if TYPE_CHECKING: import git @@ -124,6 +127,25 @@ class IfcGit(bonsai.core.tool.IfcGit): IfcGitRepo.repo = repo return repo + @classmethod + def get_repo_description(cls, path_ifc: str) -> Union[str, None]: + """Return a `git describe --tags --always --dirty` style string for the + repository containing path_ifc (e.g. "v1.2-4-gabcdef1"), or None if + unavailable. + + Returns None instead of raising when GitPython isn't installed, the + path isn't inside a git repository, or the repository has no commits. + """ + if not GIT_AVAILABLE: + return None + try: + repo = cls.repo_from_path(path_ifc) + if repo is None: + return None + return repo.git.describe(tags=True, always=True, dirty=True) + except Exception: + return None + @classmethod def add_file_to_repo(cls, repo: git.Repo, path_file: str) -> None: if os.name == "nt":