diff --git a/integration/blender/__init__.py b/integration/blender/__init__.py index 298f65e..df95a2d 100644 --- a/integration/blender/__init__.py +++ b/integration/blender/__init__.py @@ -21,7 +21,7 @@ "warning" : "", "category" : "Generic" } -from . import properties, menu, project_browser, select_project, export, export_menu, load_asset, utils +from . import properties, menu, project_browser, select_project, configure_setup, export, export_menu, load_asset, utils import bpy from bpy.app.handlers import persistent @@ -39,6 +39,7 @@ def register(): properties.register() export.register() select_project.register() + configure_setup.register() menu.register() export_menu.register() project_browser.register() @@ -53,6 +54,7 @@ def unregister(): export_menu.unregister() menu.unregister() select_project.unregister() + configure_setup.unregister() export.unregister() properties.unregister() \ No newline at end of file diff --git a/integration/blender/configure_setup.py b/integration/blender/configure_setup.py new file mode 100644 index 0000000..ef969e2 --- /dev/null +++ b/integration/blender/configure_setup.py @@ -0,0 +1,42 @@ +from bpy.types import Operator +from bpy.props import StringProperty +import bpy +import json +from . import utils +import os + +class OT_ConfigureSetup(Operator): + + bl_idname = "conduct.configure_setup" + bl_label = "Configure Setup" + + def execute(self, context): + + data = utils.get_conduct_data() + if data == None: + data = bpy.data.scenes[0].conduct + + conduct = utils.get_conduct_object() + + result = conduct.setup(".blend") + if result['result'] != 'ok': + return {'FINISHED'} + + dialog_data = result['data'] + + data.asset = dialog_data['asset'] + data.department = dialog_data['department'] + + if dialog_data['shot'] is not None: + data.shot = dialog_data['shot'] + + bpy.ops.wm.save_as_mainfile(filepath=dialog_data['path']) + self.report({'INFO'}, "Saved Setup!") + + return {'FINISHED'} + +def register(): + bpy.utils.register_class(OT_ConfigureSetup) + +def unregister(): + bpy.utils.unregister_class(OT_ConfigureSetup) diff --git a/integration/blender/menu.py b/integration/blender/menu.py index afb51bc..442e551 100644 --- a/integration/blender/menu.py +++ b/integration/blender/menu.py @@ -1,5 +1,6 @@ import bpy from . import utils +from .conduct import conduct class ConductMenu(bpy.types.Menu): bl_label = "Conduct" @@ -10,7 +11,10 @@ def draw(self, context): data = utils.get_conduct_data() if data == None: - layout.operator("conduct.select_project", icon='ADD', text="Select Project") + if conduct.can_load_from_env(): + layout.operator("conduct.configure_setup", icon='ADD', text="Configure Setup") + else: + layout.operator("conduct.select_project", icon='ADD', text="Select Project") else: layout.operator("conduct.load_asset", icon='IMPORT', text="Load Asset(s)") diff --git a/integration/blender/project_browser.py b/integration/blender/project_browser.py index b9d36ed..3387802 100644 --- a/integration/blender/project_browser.py +++ b/integration/blender/project_browser.py @@ -1,6 +1,7 @@ import bpy from . import utils +from .conduct import conduct class TaskItemSlot(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): @@ -28,7 +29,10 @@ def draw(self, context): data = utils.get_conduct_data() if data == None or data.asset == None or data.asset == "": - layout.operator("conduct.select_project", icon='ADD', text="Select Project") + if conduct.can_load_from_env(): + layout.operator("conduct.configure_setup", icon='ADD', text="Configure Setup") + else: + layout.operator("conduct.select_project", icon='ADD', text="Select Project") return if data.department != "": diff --git a/integration/blender/utils.py b/integration/blender/utils.py index 1b4af74..d71fa72 100644 --- a/integration/blender/utils.py +++ b/integration/blender/utils.py @@ -14,5 +14,8 @@ def get_conduct_object(manifest_path = None) -> conduct.Conduct: if manifest_path != None: return conduct.get_from_manifest_path(manifest_path, "blender") else: + if conduct.can_load_from_env(): + return conduct.load_from_env("blender") + return conduct.find_from_current_path(bpy.data.filepath, "blender") diff --git a/integration/common/conduct.py b/integration/common/conduct.py index 380f7e1..0baf1d5 100644 --- a/integration/common/conduct.py +++ b/integration/common/conduct.py @@ -16,7 +16,12 @@ def __init__(self, conduct_exe, current_program): self.current_program = current_program def run_process(self, args): - args = [self.conduct_exe] + args + + exe = self.conduct_exe + if "CONDUCT_EXE" in os.environ: + exe = os.environ["CONDUCT_EXE"] + + args = [exe] + args #Hide the cmd window on windows startupinfo = None @@ -26,13 +31,37 @@ def run_process(self, args): startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags = subprocess.CREATE_NO_WINDOW creation_flags = subprocess.CREATE_NO_WINDOW - - log("Executing: " + str(args)) - - process=subprocess.Popen(args, cwd=os.path.dirname(self.conduct_exe), startupinfo=startupinfo, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, encoding='utf-8', creationflags=creation_flags) - - data = process.communicate()[0] - + + env = os.environ.copy() + + # Fix errors where conduct tries to inherit env from the host app (occurred in inkscape appimage) + for name in [ + "LD_LIBRARY_PATH", + "LD_PRELOAD", + "GDK_PIXBUF_MODULE_FILE", + "GDK_PIXBUF_MODULEDIR", + "GTK_PATH", + "GTK_DATA_PREFIX", + "GTK_EXE_PREFIX", + "GIO_EXTRA_MODULES", + "PYTHONPATH", + "PYTHONHOME", + ]: + env.pop(name, None) + + + cwd = None + if "CONDUCT_ROOT" in os.environ: + cwd = os.environ["CONDUCT_ROOT"] + else: + os.path.dirname(self.conduct_exe) + + log("Running process: " + str(args)) + process=subprocess.Popen(args, cwd=cwd, startupinfo=startupinfo, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf-8', creationflags=creation_flags, env=env) + res = process.communicate() + code = process.returncode + data = res[0] + err = res[1] log(data) return json.loads(data) @@ -42,6 +71,7 @@ def get_summary(self): return summary def setup(self, file_format): + log("Running process") args = ["dialog", "create_setup", "--", "--file-format", file_format] return self.run_process(args) @@ -88,6 +118,12 @@ def export(self, department, format, asset, element, shot=None): return self.run_process(args) +def can_load_from_env(): + return "CONDUCT_MANIFEST" in os.environ + +def load_from_env(current_program): + return Conduct("conduct", current_program) + def get_from_manifest_path(manifest_path, current_program): log("Getting exe from manifest path: " + manifest_path) @@ -114,8 +150,3 @@ def find_from_current_path(current_file, current_program): return get_from_manifest_path(check, current_program) path = os.path.dirname(path) - - - - - diff --git a/integration/inkscape/conduct_create_setup.py b/integration/inkscape/conduct_create_setup.py index 277e1df..57f928d 100644 --- a/integration/inkscape/conduct_create_setup.py +++ b/integration/inkscape/conduct_create_setup.py @@ -3,6 +3,7 @@ import os from conduct import conduct import subprocess +import signal def log_stub(info): pass @@ -13,13 +14,20 @@ def log(info): class ConductCreateSetup(inkex.EffectExtension): def add_arguments(self, pars): - pars.add_argument("-m", "--manifest", default="", help="Manifest File Path") + if not conduct.can_load_from_env(): + pars.add_argument("-m", "--manifest", default="", help="Manifest File Path") def effect(self): - manifest_path = self.options.manifest conduct.log = log_stub - c = conduct.get_from_manifest_path(manifest_path, "inkscape") + + c = None + if conduct.can_load_from_env(): + c = conduct.load_from_env("inkscape") + else: + manifest_path = self.options.manifest + c = conduct.get_from_manifest_path(manifest_path, "inkscape") + result = c.setup('.svg') if result['result'] != 'ok': @@ -42,17 +50,19 @@ def effect(self): exe = inkex.command.which('inkscape') - if(exe.startswith('/tmp/.mount')): - log("Detected running in an AppImage, this process will hang until the new instance is closed!") - inkex.command.inkscape(path) - return - + appimage = os.environ.get("APPIMAGE") + if appimage != None: + exe = appimage + #if we could find a good way to kill the original inkscape instance after starting the new one, that would be ideal if os.name == 'nt': creation_flags = subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS proc = subprocess.Popen([exe, path], creationflags=creation_flags, start_new_session=True) else: - proc = subprocess.Popen([exe, path], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL) - + args = [exe, path] + log("args: " + str(args)) + proc = subprocess.Popen(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL) + + if __name__ == '__main__': ConductCreateSetup().run() \ No newline at end of file diff --git a/integration/inkscape/conduct_export.py b/integration/inkscape/conduct_export.py index 9f6e1e3..7965d92 100644 --- a/integration/inkscape/conduct_export.py +++ b/integration/inkscape/conduct_export.py @@ -27,8 +27,11 @@ def effect(self): prev_state = self.svg.get("com.lagmachine.conduct.export_save_state") if prev_state != None: prev_state = json.loads(prev_state) - - c = conduct.find_from_current_path(file_path, "inkscape") + c = None + if conduct.can_load_from_env(): + c = conduct.load_from_env("inkscape") + else: + c = conduct.find_from_current_path(file_path, "inkscape") # We arent using get_pages because this is more reliable # get_pages result doesnt contain the page label if there is only one page diff --git a/src/cli/mod.rs b/src/cli/mod.rs index db2bd73..37c2fbb 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -43,6 +43,13 @@ fn get_project_manifest_path(cli: &CLI) -> PathBuf { paths.push(path); } + match std::env::var("CONDUCT_MANIFEST") { + Ok(var) => { + return PathBuf::from(var); + } + Err(_) => (), + } + for path in paths.iter() { let mut test_path = PathBuf::from(path); test_path.push("manifest.yml");