From d404fbf8a285e0e25f5af3d8695c6df547f0ceab Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 30 May 2022 11:51:19 +0200 Subject: [PATCH 1/8] OP-3277 - added functionality to replace root value with environment variable. Useful for remote workflows where Site Sync is being used. When Load reference is used, real root value (c:/project) is replaced with ${OPENPYPE_ROOT_WORK}. --- openpype/hosts/maya/plugins/load/load_reference.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/maya/plugins/load/load_reference.py b/openpype/hosts/maya/plugins/load/load_reference.py index d65b5a2c1e..7fa7362ecc 100644 --- a/openpype/hosts/maya/plugins/load/load_reference.py +++ b/openpype/hosts/maya/plugins/load/load_reference.py @@ -8,6 +8,7 @@ from openpype.pipeline import ( legacy_create, ) import openpype.hosts.maya.api.plugin +from openpype.api import Anatomy from openpype.hosts.maya.api.lib import maintained_selection @@ -51,7 +52,9 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): with maintained_selection(): cmds.loadPlugin("AbcImport.mll", quiet=True) - nodes = cmds.file(self.fname, + anatomy = Anatomy(context["project"]["code"]) + file_url = anatomy.replace_root_with_env_key(self.fname, '${{{}}}') + nodes = cmds.file(file_url, namespace=namespace, sharedReferenceFile=False, reference=True, From 277024de81843a3198c47402e7b251f937ab0817 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 30 May 2022 13:23:24 +0200 Subject: [PATCH 2/8] OP-3277 - extracted logic to ReferenceLoader All inheriting plugins implementing shared method. Flag 'use_env_var_as_root' set to True for testing temporarily, proper location in Setting should be decided. --- openpype/hosts/maya/api/plugin.py | 25 +++++++++++++++++++ .../maya/plugins/load/_load_animation.py | 5 ++-- openpype/hosts/maya/plugins/load/load_ass.py | 12 ++++++--- openpype/hosts/maya/plugins/load/load_look.py | 4 ++- .../hosts/maya/plugins/load/load_reference.py | 5 ++-- .../hosts/maya/plugins/load/load_yeti_rig.py | 4 ++- 6 files changed, 45 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 3721868823..93b0793d9c 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -10,6 +10,7 @@ from openpype.pipeline import ( get_representation_path, AVALON_CONTAINER_ID, ) +from openpype.api import Anatomy from .pipeline import containerise from . import lib @@ -132,6 +133,7 @@ class ReferenceLoader(Loader): " imported representation ?" ) ] + use_env_var_as_root = True def load( self, @@ -191,6 +193,25 @@ class ReferenceLoader(Loader): """To be implemented by subclass""" raise NotImplementedError("Must be implemented by subclass") + def prepare_root_value(self, file_url, project_name): + """Replace root value with env var placeholder. + + Use ${OPENPYPE_ROOT_WORK} (or any other root) instead of proper root + value when storing referenced url into a workfile. + Useful for remote workflows with SiteSync. + + Args: + file_url (str) + project_name (dict) + Returns: + (str) + """ + if self.use_env_var_as_root: + anatomy = Anatomy(project_name) + file_url = anatomy.replace_root_with_env_key(file_url, '${{{}}}') + + return file_url + def update(self, container, representation): from maya import cmds from openpype.hosts.maya.api.lib import get_container_members @@ -230,6 +251,10 @@ class ReferenceLoader(Loader): self.log.debug("No alembic nodes found in {}".format(members)) try: + path = self.prepare_root_value(path, + representation["context"] + ["project"] + ["code"]) content = cmds.file(path, loadReference=reference_node, type=file_type, diff --git a/openpype/hosts/maya/plugins/load/_load_animation.py b/openpype/hosts/maya/plugins/load/_load_animation.py index 9c37e498ef..0010efb829 100644 --- a/openpype/hosts/maya/plugins/load/_load_animation.py +++ b/openpype/hosts/maya/plugins/load/_load_animation.py @@ -35,8 +35,9 @@ class AbcLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): # hero_001 (abc) # asset_counter{optional} - - nodes = cmds.file(self.fname, + file_url = self.prepare_root_value(self.fname, + context["project"]["code"]) + nodes = cmds.file(file_url, namespace=namespace, sharedReferenceFile=False, groupReference=True, diff --git a/openpype/hosts/maya/plugins/load/load_ass.py b/openpype/hosts/maya/plugins/load/load_ass.py index a284b7ec1f..1f0eb88995 100644 --- a/openpype/hosts/maya/plugins/load/load_ass.py +++ b/openpype/hosts/maya/plugins/load/load_ass.py @@ -64,9 +64,11 @@ class AssProxyLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): path = os.path.join(publish_folder, filename) proxyPath = proxyPath_base + ".ma" - self.log.info - nodes = cmds.file(proxyPath, + file_url = self.prepare_root_value(proxyPath, + context["project"]["code"]) + + nodes = cmds.file(file_url, namespace=namespace, reference=True, returnNewNodes=True, @@ -123,7 +125,11 @@ class AssProxyLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): assert os.path.exists(proxyPath), "%s does not exist." % proxyPath try: - content = cmds.file(proxyPath, + file_url = self.prepare_root_value(proxyPath, + representation["context"] + ["project"] + ["code"]) + content = cmds.file(file_url, loadReference=reference_node, type="mayaAscii", returnNewNodes=True) diff --git a/openpype/hosts/maya/plugins/load/load_look.py b/openpype/hosts/maya/plugins/load/load_look.py index 80eac8e0b5..ae3a683241 100644 --- a/openpype/hosts/maya/plugins/load/load_look.py +++ b/openpype/hosts/maya/plugins/load/load_look.py @@ -31,7 +31,9 @@ class LookLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): import maya.cmds as cmds with lib.maintained_selection(): - nodes = cmds.file(self.fname, + file_url = self.prepare_root_value(self.fname, + context["project"]["code"]) + nodes = cmds.file(file_url, namespace=namespace, reference=True, returnNewNodes=True) diff --git a/openpype/hosts/maya/plugins/load/load_reference.py b/openpype/hosts/maya/plugins/load/load_reference.py index 7fa7362ecc..e4355ed3d4 100644 --- a/openpype/hosts/maya/plugins/load/load_reference.py +++ b/openpype/hosts/maya/plugins/load/load_reference.py @@ -8,7 +8,6 @@ from openpype.pipeline import ( legacy_create, ) import openpype.hosts.maya.api.plugin -from openpype.api import Anatomy from openpype.hosts.maya.api.lib import maintained_selection @@ -52,8 +51,8 @@ class ReferenceLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): with maintained_selection(): cmds.loadPlugin("AbcImport.mll", quiet=True) - anatomy = Anatomy(context["project"]["code"]) - file_url = anatomy.replace_root_with_env_key(self.fname, '${{{}}}') + file_url = self.prepare_root_value(self.fname, + context["project"]["code"]) nodes = cmds.file(file_url, namespace=namespace, sharedReferenceFile=False, diff --git a/openpype/hosts/maya/plugins/load/load_yeti_rig.py b/openpype/hosts/maya/plugins/load/load_yeti_rig.py index b4d31b473f..241c28467a 100644 --- a/openpype/hosts/maya/plugins/load/load_yeti_rig.py +++ b/openpype/hosts/maya/plugins/load/load_yeti_rig.py @@ -53,7 +53,9 @@ class YetiRigLoader(openpype.hosts.maya.api.plugin.ReferenceLoader): # load rig with lib.maintained_selection(): - nodes = cmds.file(self.fname, + file_url = self.prepare_root_value(self.fname, + context["project"]["code"]) + nodes = cmds.file(file_url, namespace=namespace, reference=True, returnNewNodes=True, From 254455e786c50ef20d0f953bebd57d50af077b1e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 30 May 2022 18:05:56 +0200 Subject: [PATCH 3/8] OP-3277 - introduced Settings variable Configured via Maya/Maya-dirmap to use in all Loaders --- openpype/hosts/maya/api/plugin.py | 45 ++++++++++--------- .../defaults/project_settings/maya.json | 1 + .../projects_schema/schema_project_maya.json | 6 +++ 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/openpype/hosts/maya/api/plugin.py b/openpype/hosts/maya/api/plugin.py index 93b0793d9c..f05893a7b4 100644 --- a/openpype/hosts/maya/api/plugin.py +++ b/openpype/hosts/maya/api/plugin.py @@ -11,7 +11,7 @@ from openpype.pipeline import ( AVALON_CONTAINER_ID, ) from openpype.api import Anatomy - +from openpype.settings import get_project_settings from .pipeline import containerise from . import lib @@ -133,7 +133,6 @@ class ReferenceLoader(Loader): " imported representation ?" ) ] - use_env_var_as_root = True def load( self, @@ -193,25 +192,6 @@ class ReferenceLoader(Loader): """To be implemented by subclass""" raise NotImplementedError("Must be implemented by subclass") - def prepare_root_value(self, file_url, project_name): - """Replace root value with env var placeholder. - - Use ${OPENPYPE_ROOT_WORK} (or any other root) instead of proper root - value when storing referenced url into a workfile. - Useful for remote workflows with SiteSync. - - Args: - file_url (str) - project_name (dict) - Returns: - (str) - """ - if self.use_env_var_as_root: - anatomy = Anatomy(project_name) - file_url = anatomy.replace_root_with_env_key(file_url, '${{{}}}') - - return file_url - def update(self, container, representation): from maya import cmds from openpype.hosts.maya.api.lib import get_container_members @@ -344,6 +324,29 @@ class ReferenceLoader(Loader): except RuntimeError: pass + def prepare_root_value(self, file_url, project_name): + """Replace root value with env var placeholder. + + Use ${OPENPYPE_ROOT_WORK} (or any other root) instead of proper root + value when storing referenced url into a workfile. + Useful for remote workflows with SiteSync. + + Args: + file_url (str) + project_name (dict) + Returns: + (str) + """ + settings = get_project_settings(project_name) + use_env_var_as_root = (settings["maya"] + ["maya-dirmap"] + ["use_env_var_as_root"]) + if use_env_var_as_root: + anatomy = Anatomy(project_name) + file_url = anatomy.replace_root_with_env_key(file_url, '${{{}}}') + + return file_url + @staticmethod def _organize_containers(nodes, container): # type: (list, str) -> None diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index e03bdcecc3..a42f889e85 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -8,6 +8,7 @@ "yetiRig": "ma" }, "maya-dirmap": { + "use_env_var_as_root": true, "enabled": false, "paths": { "source-path": [], diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index 0c7943447b..f9523b1baa 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -22,6 +22,12 @@ "label": "Maya Directory Mapping", "is_group": true, "children": [ + { + "type": "boolean", + "key": "use_env_var_as_root", + "label": "Use env var placeholder in referenced url", + "docstring": "Use ${} placeholder instead of physical value of root when storing into workfile metadata." + }, { "type": "boolean", "key": "enabled", From b073853a0b1d056a0976b5a3f983184bfb195d2e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 18:58:13 +0200 Subject: [PATCH 4/8] Update openpype/settings/entities/schemas/projects_schema/schema_project_maya.json Co-authored-by: Milan Kolar --- .../entities/schemas/projects_schema/schema_project_maya.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index f9523b1baa..f7d92c385e 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -25,7 +25,7 @@ { "type": "boolean", "key": "use_env_var_as_root", - "label": "Use env var placeholder in referenced url", + "label": "Use env var placeholder in referenced paths", "docstring": "Use ${} placeholder instead of physical value of root when storing into workfile metadata." }, { From 6530fbd918f795077f0a715827e101c97b4bc8ea Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 31 May 2022 18:58:28 +0200 Subject: [PATCH 5/8] Update openpype/settings/entities/schemas/projects_schema/schema_project_maya.json Co-authored-by: Milan Kolar --- .../entities/schemas/projects_schema/schema_project_maya.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json index f7d92c385e..40e98b0333 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_maya.json @@ -26,7 +26,7 @@ "type": "boolean", "key": "use_env_var_as_root", "label": "Use env var placeholder in referenced paths", - "docstring": "Use ${} placeholder instead of physical value of root when storing into workfile metadata." + "docstring": "Use ${} placeholder instead of absolute value of a root in referenced filepaths." }, { "type": "boolean", From a10bbbcc79b5a369d51bb4716164611edcb4dbfa Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 1 Jun 2022 12:33:09 +0200 Subject: [PATCH 6/8] OP-3068 - better handling of legacy review subsets in Maya Multiple reviews from a Maya workfile are blocked by legacy subset names without variant. These names could be used in later process so we cannot replace them. Unique subset name validator was added, check for existing subset in DB too. --- .../maya/plugins/publish/collect_review.py | 17 +++++---- .../validate_review_subset_uniqueness.xml | 28 +++++++++++++++ .../validate_review_subset_uniqueness.py | 36 +++++++++++++++++++ 3 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 openpype/hosts/maya/plugins/publish/help/validate_review_subset_uniqueness.xml create mode 100644 openpype/hosts/maya/plugins/publish/validate_review_subset_uniqueness.py diff --git a/openpype/hosts/maya/plugins/publish/collect_review.py b/openpype/hosts/maya/plugins/publish/collect_review.py index 1af92c3bfc..e9e0d74c03 100644 --- a/openpype/hosts/maya/plugins/publish/collect_review.py +++ b/openpype/hosts/maya/plugins/publish/collect_review.py @@ -77,15 +77,14 @@ class CollectReview(pyblish.api.InstancePlugin): instance.data['remove'] = True self.log.debug('isntance data {}'.format(instance.data)) else: - if self.legacy: - instance.data['subset'] = task + 'Review' - else: - subset = "{}{}{}".format( - task, - instance.data["subset"][0].upper(), - instance.data["subset"][1:] - ) - instance.data['subset'] = subset + legacy_subset_name = task + 'Review' + asset_doc_id = instance.context.data['assetEntity']["_id"] + subsets = legacy_io.find({"type": "subset", + "name": legacy_subset_name, + "parent": asset_doc_id}).distinct("_id") + if len(list(subsets)) > 0: + self.log.debug("Existing subsets found, keep legacy name.") + instance.data['subset'] = legacy_subset_name instance.data['review_camera'] = camera instance.data['frameStartFtrack'] = \ diff --git a/openpype/hosts/maya/plugins/publish/help/validate_review_subset_uniqueness.xml b/openpype/hosts/maya/plugins/publish/help/validate_review_subset_uniqueness.xml new file mode 100644 index 0000000000..fd1bf4cbaa --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/help/validate_review_subset_uniqueness.xml @@ -0,0 +1,28 @@ + + + + Review subsets not unique + + ## Non unique subset name found + + Non unique subset names: '{non_unique}' + + ### __Detailed Info__ (optional) + + This might happen if you already published for this asset + review subset with legacy name {task}Review. + This legacy name limits possibility of publishing of multiple + reviews from a single workfile. Proper review subset name should + now + contain variant also (as 'Main', 'Default' etc.). That would + result in completely new subset though, so this situation must + be handled manually. + + ### How to repair? + + Legacy subsets must be removed from Openpype DB, please ask admin + to do that. Please provide them asset and subset names. + + + + \ No newline at end of file diff --git a/openpype/hosts/maya/plugins/publish/validate_review_subset_uniqueness.py b/openpype/hosts/maya/plugins/publish/validate_review_subset_uniqueness.py new file mode 100644 index 0000000000..d70096ee45 --- /dev/null +++ b/openpype/hosts/maya/plugins/publish/validate_review_subset_uniqueness.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +import collections +import pyblish.api +import openpype.api +from openpype.pipeline import PublishXmlValidationError + + +class ValidateReviewSubsetUniqueness(pyblish.api.ContextPlugin): + """Validates that nodes has common root.""" + + order = openpype.api.ValidateContentsOrder + hosts = ["maya"] + families = ["review"] + label = "Validate Review Subset Unique" + + def process(self, context): + subset_names = [] + + for instance in context: + self.log.info("instance:: {}".format(instance.data)) + if instance.data.get('publish'): + subset_names.append(instance.data.get('subset')) + + non_unique = \ + [item + for item, count in collections.Counter(subset_names).items() + if count > 1] + msg = ("Instance subset names {} are not unique. ".format(non_unique) + + "Ask admin to remove subset from DB for multiple reviews.") + formatting_data = { + "non_unique": ",".join(non_unique) + } + + if non_unique: + raise PublishXmlValidationError(self, msg, + formatting_data=formatting_data) From 6a5fa89348bb822e1f2c8748fa867f19e2f70a8d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 1 Jun 2022 14:27:55 +0200 Subject: [PATCH 7/8] Fix - change default of use_env_var_as_root True was there only for testing, false is more sane default. --- openpype/settings/defaults/project_settings/maya.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index a42f889e85..efd22e13c8 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -8,7 +8,7 @@ "yetiRig": "ma" }, "maya-dirmap": { - "use_env_var_as_root": true, + "use_env_var_as_root": false, "enabled": false, "paths": { "source-path": [], From a9fdcd80aaee0db6dddc0e777e9dd021459f04c2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 3 Jun 2022 14:44:11 +0200 Subject: [PATCH 8/8] OP-3231 - return only active projects in webpublisher ProjectsEndpoing --- .../webserver_service/webpublish_routes.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/openpype/hosts/webpublisher/webserver_service/webpublish_routes.py b/openpype/hosts/webpublisher/webserver_service/webpublish_routes.py index e82ba7f2b8..70324fc39c 100644 --- a/openpype/hosts/webpublisher/webserver_service/webpublish_routes.py +++ b/openpype/hosts/webpublisher/webserver_service/webpublish_routes.py @@ -71,16 +71,12 @@ class ProjectsEndpoint(_RestApiEndpoint): """Returns list of dict with project info (id, name).""" async def get(self) -> Response: output = [] - for project_name in self.dbcon.database.collection_names(): - project_doc = self.dbcon.database[project_name].find_one({ - "type": "project" - }) - if project_doc: - ret_val = { - "id": project_doc["_id"], - "name": project_doc["name"] - } - output.append(ret_val) + for project_doc in self.dbcon.projects(): + ret_val = { + "id": project_doc["_id"], + "name": project_doc["name"] + } + output.append(ret_val) return Response( status=200, body=self.resource.encode(output),