diff --git a/src/bonsai/Makefile b/src/bonsai/Makefile index b937a932d3..53c135a2e6 100644 --- a/src/bonsai/Makefile +++ b/src/bonsai/Makefile @@ -229,12 +229,15 @@ endif # Required for Desktop icon and file association cp -r bonsai/libs/desktop build/bonsai/libs/ + # folder for executable files + mkdir -p build/bonsai/libs/bin + # required for three-way git merging ifeq ($(PLATFORM), win) - cd build/bonsai/libs/desktop && wget https://github.com/brunopostle/ifcmerge/releases/download/2024-06-24/ifcmerge.zip - cd build/bonsai/libs/desktop && unzip ifcmerge.zip && rm ifcmerge.zip + cd build/bonsai/libs/bin && wget https://github.com/brunopostle/ifcmerge/releases/download/2024-06-24/ifcmerge.zip + cd build/bonsai/libs/bin && unzip ifcmerge.zip && rm ifcmerge.zip else - cd build/bonsai/libs/desktop && wget https://raw.githubusercontent.com/brunopostle/ifcmerge/main/ifcmerge + cd build/bonsai/libs/bin && wget https://raw.githubusercontent.com/brunopostle/ifcmerge/main/ifcmerge && chmod +x ifcmerge endif # Generate translations module for Bonsai build diff --git a/src/bonsai/bonsai/bim/__init__.py b/src/bonsai/bonsai/bim/__init__.py index 170fba0ae6..b3655fcd32 100644 --- a/src/bonsai/bonsai/bim/__init__.py +++ b/src/bonsai/bonsai/bim/__init__.py @@ -258,6 +258,9 @@ def register(): icons = icon_preview bpy.app.translations.register("bonsai", translations_dict) + import bonsai.tool as tool + tool.Blender.ensure_bin_in_path() + def unregister(): global icons diff --git a/src/bonsai/bonsai/bim/module/ifcgit/__init__.py b/src/bonsai/bonsai/bim/module/ifcgit/__init__.py index 6c87a659e8..d48f6e285d 100644 --- a/src/bonsai/bonsai/bim/module/ifcgit/__init__.py +++ b/src/bonsai/bonsai/bim/module/ifcgit/__init__.py @@ -38,7 +38,6 @@ classes = ( operator.RefreshGit, operator.SwitchRevision, operator.InstallGit, - operator.InstallIfcmerge, prop.IfcGitTag, prop.IfcGitListItem, prop.IfcGitProperties, diff --git a/src/bonsai/bonsai/bim/module/ifcgit/operator.py b/src/bonsai/bonsai/bim/module/ifcgit/operator.py index 4555a94190..266b85bc92 100644 --- a/src/bonsai/bonsai/bim/module/ifcgit/operator.py +++ b/src/bonsai/bonsai/bim/module/ifcgit/operator.py @@ -389,7 +389,9 @@ class ObjectLog(bpy.types.Operator): class InstallGit(bpy.types.Operator): - """Installs Git if possible""" + """Install Git Version Control System from the +Windows Package Manager Community Repository, +requires restarting Blender after installation""" bl_label = "Install Git" bl_idname = "ifcgit.install_git" @@ -406,16 +408,3 @@ class InstallGit(bpy.types.Operator): core.install_git(tool.IfcGit, self) refresh() return {"FINISHED"} - - -class InstallIfcmerge(bpy.types.Operator): - """Installs ifcmerge if possible""" - - bl_label = "Install ifcmerge" - bl_idname = "ifcgit.install_ifcmerge" - bl_options = {"REGISTER"} - - def execute(self, context): - core.install_ifcmerge(tool.IfcGit, self) - refresh() - return {"FINISHED"} diff --git a/src/bonsai/bonsai/bim/module/ifcgit/ui.py b/src/bonsai/bonsai/bim/module/ifcgit/ui.py index 25665d362c..b8d288c77b 100644 --- a/src/bonsai/bonsai/bim/module/ifcgit/ui.py +++ b/src/bonsai/bonsai/bim/module/ifcgit/ui.py @@ -30,19 +30,10 @@ class IFCGIT_PT_panel(bpy.types.Panel): if platform.system() == "Windows": row.operator( "ifcgit.install_git", - text="Install Git from Microsoft Store", + text="Install Git", icon="PACKAGE", ) return - elif not IfcGitData.data["ifcmerge_exe"]: - # TODO check if ifcmerge is up-to-date - row = layout.row() - row.label(text="ifcmerge is not installed", icon="ERROR") - row.operator( - "ifcgit.install_ifcmerge", - text="Install ifcmerge", - icon="PACKAGE", - ) props = context.scene.IfcGitProperties diff --git a/src/bonsai/bonsai/core/ifcgit.py b/src/bonsai/bonsai/core/ifcgit.py index 6e4ac90ac9..731e3751f2 100644 --- a/src/bonsai/bonsai/core/ifcgit.py +++ b/src/bonsai/bonsai/core/ifcgit.py @@ -138,12 +138,3 @@ def install_git(ifcgit: tool.IfcGit, operator: bpy.types.Operator) -> None: ifcgit.install_git_windows(operator=operator) else: print("install_git() not implemented") - - -def install_ifcmerge(ifcgit: tool.IfcGit, operator: bpy.types.Operator) -> None: - if platform.system() == "Windows": - ifcgit.install_ifcmerge_windows(name_exe="ifcmerge.exe", operator=operator) - elif platform.system() == "Linux": - ifcgit.install_ifcmerge_linux(name_exe="ifcmerge", operator=operator) - elif platform.system() == "Darwin": - print("install_ifcmerge() not implemented") diff --git a/src/bonsai/bonsai/tool/blender.py b/src/bonsai/bonsai/tool/blender.py index 051dfa9dc3..e1c4852387 100644 --- a/src/bonsai/bonsai/tool/blender.py +++ b/src/bonsai/bonsai/tool/blender.py @@ -21,6 +21,7 @@ import bpy import bmesh import json import os +import platform from ifcopenshell import entity_instance import ifcopenshell.api import ifcopenshell.util.element @@ -430,6 +431,18 @@ class Blender(bonsai.core.tool.Blender): return blender_path return bpy.path.abspath("//") / blender_path + @classmethod + def ensure_bin_in_path(cls) -> None: + """Check 'bin' folder is in PATH, if not add for this session""" + bin_dir = str(Path(__file__).parent.parent.resolve() / "libs" / "bin") + current_path = os.environ["PATH"] + if bin_dir not in current_path: + if platform.system() == "Windows": + path_separator = ";" + else: + path_separator = ":" + os.environ["PATH"] = current_path + path_separator + bin_dir + @classmethod def get_default_selection_keypmap(cls) -> tuple: """keymap to replicate default blender selection behaviour with click and box selection""" diff --git a/src/bonsai/bonsai/tool/ifcgit.py b/src/bonsai/bonsai/tool/ifcgit.py index 011d5800a9..5b0f9b88e5 100644 --- a/src/bonsai/bonsai/tool/ifcgit.py +++ b/src/bonsai/bonsai/tool/ifcgit.py @@ -20,7 +20,6 @@ from __future__ import annotations import os import re import subprocess -import shutil import bpy import logging from bonsai.bim import import_ifc @@ -551,7 +550,7 @@ class IfcGit: @classmethod def install_git_windows(cls, operator: bpy.types.Operator) -> None: """Command to install Git on Windows using winget""" - command = ["winget", "install", "--id", "Git.Git", "-e", "--source", "msstore"] + command = ["winget", "install", "--id", "Git.Git", "-e", "--source", "winget"] try: subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except subprocess.CalledProcessError as e: @@ -559,40 +558,6 @@ class IfcGit: except FileNotFoundError: operator.report({"ERROR"}, "Winget is not available. Make sure Windows Package Manager is installed.") - @classmethod - def install_ifcmerge_linux(cls, name_exe: str, operator: bpy.types.Operator) -> None: - """Command to install ifcmerge on Linux""" - src_dir = os.path.join(os.path.dirname(__file__), "../libs/desktop") - destdir = os.path.join(os.environ["HOME"], ".local", "bin") - try: - os.makedirs(destdir, exist_ok=True) - shutil.copy(os.path.join(src_dir, name_exe), destdir) - os.chmod(os.path.join(destdir, name_exe), 0o755) - except Exception as e: - operator.report({"ERROR"}, f"Error installing file: {e}") - - @classmethod - def install_ifcmerge_windows(cls, name_exe: str, operator: bpy.types.Operator) -> None: - """Command to install ifcmerge on Windows""" - src_dir = os.path.join(os.path.dirname(__file__), "..\\libs\\desktop") - destdir = os.path.join(os.environ["USERPROFILE"], "AppData", "Local", "Bonsai", "bin") - try: - os.makedirs(destdir, exist_ok=True) - shutil.copy(os.path.join(src_dir, name_exe), destdir) - except Exception as e: - operator.report({"ERROR"}, f"Error installing file: {e}") - - current_path = os.environ["PATH"] - - if destdir not in current_path: - os.environ["PATH"] = current_path + ";" + destdir - command = f'setx PATH "%PATH%;{destdir}"' - try: - subprocess.run(command, check=True, shell=True) - print(f"User %PATH% updated permanently with: {destdir}") - except subprocess.CalledProcessError as e: - operator.report({"ERROR"}, f"Error permanently updating %PATH%: {e}") - class IfcGitRepo: repo: git.Repo = None