From 7a164032e031b8425aacdd2b998bed7617d5ba85 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Wed, 28 Jun 2023 18:35:41 +0100 Subject: [PATCH 1/9] Working callback for managing Xgen sidecar files. --- openpype/hosts/maya/api/pipeline.py | 103 ++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 5323717fa7..27d489418f 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -2,6 +2,7 @@ import os import errno import logging import contextlib +import shutil from maya import utils, cmds, OpenMaya import maya.api.OpenMaya as om @@ -113,6 +114,9 @@ class MayaHost(HostBase, IWorkfileHost, ILoadHost): register_event_callback("taskChanged", on_task_changed) register_event_callback("workfile.open.before", before_workfile_open) register_event_callback("workfile.save.before", before_workfile_save) + register_event_callback( + "workfile.save.before", workfile_save_before_xgen + ) register_event_callback("workfile.save.before", after_workfile_save) def open_workfile(self, filepath): @@ -681,6 +685,105 @@ def before_workfile_save(event): create_workspace_mel(workdir_path, project_name) +def display_warning(message, show_cancel=False): + """Show feedback to user. + + Returns: + bool + """ + + from qtpy import QtWidgets + + accept = QtWidgets.QMessageBox.Ok + if show_cancel: + buttons = accept | QtWidgets.QMessageBox.Cancel + else: + buttons = accept + + state = QtWidgets.QMessageBox.warning( + None, + "", + message, + buttons=buttons, + defaultButton=accept + ) + + return state == accept + + +def workfile_save_before_xgen(event): + current_work_dir = legacy_io.Session["AVALON_WORKDIR"].replace("\\", "/") + expected_work_dir = event.data["workdir_path"].replace("\\", "/") + if current_work_dir == expected_work_dir: + return + + palettes = cmds.ls(type="xgmPalette", long=True) + if not palettes: + return + + import xgenm + + transfers = [] + overwrites = [] + attribute_changes = {} + attrs = ["xgFileName", "xgBaseFile"] + for palette in palettes: + project_path = xgenm.getAttr("xgProjectPath", palette.replace("|", "")) + _, maya_extension = os.path.splitext(event.data["filename"]) + + for attr in attrs: + node_attr = "{}.{}".format(palette, attr) + attr_value = cmds.getAttr(node_attr) + + if not attr_value: + continue + + source = os.path.join(project_path, attr_value) + + attr_value = event.data["filename"].replace( + maya_extension, + "__{}{}".format( + palette.replace("|", "").replace(":", "__"), + os.path.splitext(attr_value)[1] + ) + ) + target = os.path.join(expected_work_dir, attr_value) + + transfers.append((source, target)) + attribute_changes[node_attr] = attr_value + + relative_path = xgenm.getAttr( + "xgDataPath", palette.replace("|", "") + ).split(os.pathsep)[0] + absolute_path = relative_path.replace("${PROJECT}", project_path) + for root, _, files in os.walk(absolute_path): + for f in files: + source = os.path.join(root, f).replace("\\", "/") + target = source.replace(project_path, expected_work_dir + "/") + transfers.append((source, target)) + if os.path.exists(target): + overwrites.append(target) + + # Ask user about overwriting files. + msg = ( + "WARNING! Potential loss of data.\n\n" + "Found duplicate Xgen files in new context.\n" + "Do you want to overwrite?\n\n{}".format("\n".join(overwrites)) + ) + if overwrites: + accept = display_warning(msg, show_cancel=True) + if not accept: + return + + for attribute, value in attribute_changes.items(): + cmds.setAttr(attribute, value, type="string") + + for source, destination in transfers: + if not os.path.exists(os.path.dirname(destination)): + os.makedirs(os.path.dirname(destination)) + shutil.copy(source, destination) + + def after_workfile_save(event): workfile_name = event["filename"] if ( From 25a03628c949df07af76dbedb1b30767f8ffc37f Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 29 Jun 2023 08:49:43 +0100 Subject: [PATCH 2/9] BigRoy feedback --- openpype/hosts/maya/api/pipeline.py | 39 +++++++++++++++++++---------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 27d489418f..45064d53f9 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -712,6 +712,20 @@ def display_warning(message, show_cancel=False): def workfile_save_before_xgen(event): + """Manage Xgen external files when switching context. + + Xgen has various external files that needs to be unique and relative to the + workfile, so we need to copy and potentially overwrite these files when + switching context. + + Args: + event (Event) - openpype/lib/events.py + """ + if not cmds.pluginInfo("xgenToolkit", query=True, loaded=True): + return + + import xgenm + current_work_dir = legacy_io.Session["AVALON_WORKDIR"].replace("\\", "/") expected_work_dir = event.data["workdir_path"].replace("\\", "/") if current_work_dir == expected_work_dir: @@ -721,14 +735,13 @@ def workfile_save_before_xgen(event): if not palettes: return - import xgenm - transfers = [] overwrites = [] attribute_changes = {} attrs = ["xgFileName", "xgBaseFile"] for palette in palettes: - project_path = xgenm.getAttr("xgProjectPath", palette.replace("|", "")) + sanitized_palette = palette.replace("|", "") + project_path = xgenm.getAttr("xgProjectPath", sanitized_palette) _, maya_extension = os.path.splitext(event.data["filename"]) for attr in attrs: @@ -743,7 +756,7 @@ def workfile_save_before_xgen(event): attr_value = event.data["filename"].replace( maya_extension, "__{}{}".format( - palette.replace("|", "").replace(":", "__"), + sanitized_palette.replace(":", "__"), os.path.splitext(attr_value)[1] ) ) @@ -753,7 +766,7 @@ def workfile_save_before_xgen(event): attribute_changes[node_attr] = attr_value relative_path = xgenm.getAttr( - "xgDataPath", palette.replace("|", "") + "xgDataPath", sanitized_palette ).split(os.pathsep)[0] absolute_path = relative_path.replace("${PROJECT}", project_path) for root, _, files in os.walk(absolute_path): @@ -765,24 +778,24 @@ def workfile_save_before_xgen(event): overwrites.append(target) # Ask user about overwriting files. - msg = ( - "WARNING! Potential loss of data.\n\n" - "Found duplicate Xgen files in new context.\n" - "Do you want to overwrite?\n\n{}".format("\n".join(overwrites)) - ) if overwrites: + msg = ( + "WARNING! Potential loss of data.\n\n" + "Found duplicate Xgen files in new context.\n" + "Do you want to overwrite?\n\n{}".format("\n".join(overwrites)) + ) accept = display_warning(msg, show_cancel=True) if not accept: return - for attribute, value in attribute_changes.items(): - cmds.setAttr(attribute, value, type="string") - for source, destination in transfers: if not os.path.exists(os.path.dirname(destination)): os.makedirs(os.path.dirname(destination)) shutil.copy(source, destination) + for attribute, value in attribute_changes.items(): + cmds.setAttr(attribute, value, type="string") + def after_workfile_save(event): workfile_name = event["filename"] From 7ca847ce247d7278190143885d4cb5a3a6ba5267 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Thu, 29 Jun 2023 10:36:41 +0100 Subject: [PATCH 3/9] Change name of warning method. --- openpype/hosts/maya/api/pipeline.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 8e5c2f9fb0..98ebd9f028 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -685,7 +685,7 @@ def before_workfile_save(event): create_workspace_mel(workdir_path, project_name) -def display_warning(message, show_cancel=False): +def prompt_warning(message, show_cancel=False): """Show feedback to user. Returns: @@ -784,7 +784,7 @@ def workfile_save_before_xgen(event): "Found duplicate Xgen files in new context.\n" "Do you want to overwrite?\n\n{}".format("\n".join(overwrites)) ) - accept = display_warning(msg, show_cancel=True) + accept = prompt_warning(msg, show_cancel=True) if not accept: return From aa5236128b5a8f63cfa0e2495c28ad1adaf61693 Mon Sep 17 00:00:00 2001 From: Toke Jepsen Date: Fri, 30 Jun 2023 08:15:07 +0100 Subject: [PATCH 4/9] Update openpype/hosts/maya/api/pipeline.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/maya/api/pipeline.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 98ebd9f028..c2e4ffaba0 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -688,9 +688,9 @@ def before_workfile_save(event): def prompt_warning(message, show_cancel=False): """Show feedback to user. - Returns: - bool - """ + Returns: + bool + """ from qtpy import QtWidgets From 2a40984858d20d47a7f99f5b8ca070d0e63159f4 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 30 Jun 2023 08:16:37 +0100 Subject: [PATCH 5/9] import at top --- openpype/hosts/maya/api/pipeline.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 98ebd9f028..33ab2ac71e 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -8,6 +8,7 @@ from maya import utils, cmds, OpenMaya import maya.api.OpenMaya as om import pyblish.api +from qtpy import QtWidgets from openpype.settings import get_project_settings from openpype.host import ( @@ -691,9 +692,6 @@ def prompt_warning(message, show_cancel=False): Returns: bool """ - - from qtpy import QtWidgets - accept = QtWidgets.QMessageBox.Ok if show_cancel: buttons = accept | QtWidgets.QMessageBox.Cancel From 8e9f4eb40e4d5595c9786f4b6dc7ffd9a4dcfdc6 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 30 Jun 2023 15:40:31 +0100 Subject: [PATCH 6/9] Log message about overwrites and continue --- openpype/hosts/maya/api/pipeline.py | 35 +++++------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 8cc4359205..9fab825105 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -686,30 +686,6 @@ def before_workfile_save(event): create_workspace_mel(workdir_path, project_name) -def prompt_warning(message, show_cancel=False): - """Show feedback to user. - - Returns: - bool - """ - - accept = QtWidgets.QMessageBox.Ok - if show_cancel: - buttons = accept | QtWidgets.QMessageBox.Cancel - else: - buttons = accept - - state = QtWidgets.QMessageBox.warning( - None, - "", - message, - buttons=buttons, - defaultButton=accept - ) - - return state == accept - - def workfile_save_before_xgen(event): """Manage Xgen external files when switching context. @@ -778,14 +754,13 @@ def workfile_save_before_xgen(event): # Ask user about overwriting files. if overwrites: - msg = ( + log.warning( "WARNING! Potential loss of data.\n\n" - "Found duplicate Xgen files in new context.\n" - "Do you want to overwrite?\n\n{}".format("\n".join(overwrites)) + "Found duplicate Xgen files in new context.\n{}".format( + "\n".join(overwrites) + ) ) - accept = prompt_warning(msg, show_cancel=True) - if not accept: - return + return for source, destination in transfers: if not os.path.exists(os.path.dirname(destination)): From e7bdf25b9a126bf0e4cffbcc6a2529db1f15af37 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 30 Jun 2023 15:41:39 +0100 Subject: [PATCH 7/9] HOund --- openpype/hosts/maya/api/pipeline.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 9fab825105..b4042fd3d7 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -8,7 +8,6 @@ from maya import utils, cmds, OpenMaya import maya.api.OpenMaya as om import pyblish.api -from qtpy import QtWidgets from openpype.settings import get_project_settings from openpype.host import ( From 8713759c18ba8e5b617ada2add27bbc154cc6069 Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 30 Jun 2023 15:53:08 +0100 Subject: [PATCH 8/9] Hound --- openpype/hosts/maya/api/pipeline.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index b4042fd3d7..9fab825105 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -8,6 +8,7 @@ from maya import utils, cmds, OpenMaya import maya.api.OpenMaya as om import pyblish.api +from qtpy import QtWidgets from openpype.settings import get_project_settings from openpype.host import ( From aaf3a9acfefa4f7f9663c4d96ec273e09a7d4f0c Mon Sep 17 00:00:00 2001 From: Toke Stuart Jepsen Date: Fri, 30 Jun 2023 15:53:34 +0100 Subject: [PATCH 9/9] Hound --- openpype/hosts/maya/api/pipeline.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openpype/hosts/maya/api/pipeline.py b/openpype/hosts/maya/api/pipeline.py index 9fab825105..b4042fd3d7 100644 --- a/openpype/hosts/maya/api/pipeline.py +++ b/openpype/hosts/maya/api/pipeline.py @@ -8,7 +8,6 @@ from maya import utils, cmds, OpenMaya import maya.api.OpenMaya as om import pyblish.api -from qtpy import QtWidgets from openpype.settings import get_project_settings from openpype.host import (