From c6e424bc87d0a6606fbae7b48d4e80ae032ccec3 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 2 Nov 2021 12:05:37 +0100 Subject: [PATCH 1/9] OP-1923 - abstracted dirmap for reuse in hosts Implemented for Maya (refactored current implementation) --- openpype/hosts/maya/api/__init__.py | 117 +++-------------------- openpype/lib/path_tools.py | 140 ++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 105 deletions(-) diff --git a/openpype/hosts/maya/api/__init__.py b/openpype/hosts/maya/api/__init__.py index 0a8370eafc3..e330904abf0 100644 --- a/openpype/hosts/maya/api/__init__.py +++ b/openpype/hosts/maya/api/__init__.py @@ -13,6 +13,7 @@ from openpype.lib import any_outdated import openpype.hosts.maya from openpype.hosts.maya.lib import copy_workspace_mel +from openpype.lib.path_tools import HostDirmap from . import menu, lib log = logging.getLogger("openpype.hosts.maya") @@ -30,7 +31,8 @@ def install(): project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) # process path mapping - process_dirmap(project_settings) + dirmap_processor = MayaDirmap("maya", project_settings) + dirmap_processor.process_dirmap() pyblish.register_plugin_path(PUBLISH_PATH) avalon.register_plugin_path(avalon.Loader, LOAD_PATH) @@ -60,110 +62,6 @@ def install(): avalon.data["familiesStateToggled"] = ["imagesequence"] -def process_dirmap(project_settings): - # type: (dict) -> None - """Go through all paths in Settings and set them using `dirmap`. - - If artists has Site Sync enabled, take dirmap mapping directly from - Local Settings when artist is syncing workfile locally. - - Args: - project_settings (dict): Settings for current project. - - """ - local_mapping = _get_local_sync_dirmap(project_settings) - if not project_settings["maya"].get("maya-dirmap") and not local_mapping: - return - - mapping = local_mapping or \ - project_settings["maya"]["maya-dirmap"]["paths"] \ - or {} - mapping_enabled = project_settings["maya"]["maya-dirmap"]["enabled"] \ - or bool(local_mapping) - - if not mapping or not mapping_enabled: - return - if mapping.get("source-path") and mapping_enabled is True: - log.info("Processing directory mapping ...") - cmds.dirmap(en=True) - for k, sp in enumerate(mapping["source-path"]): - try: - print("{} -> {}".format(sp, mapping["destination-path"][k])) - cmds.dirmap(m=(sp, mapping["destination-path"][k])) - cmds.dirmap(m=(mapping["destination-path"][k], sp)) - except IndexError: - # missing corresponding destination path - log.error(("invalid dirmap mapping, missing corresponding" - " destination directory.")) - break - except RuntimeError: - log.error("invalid path {} -> {}, mapping not registered".format( - sp, mapping["destination-path"][k] - )) - continue - - -def _get_local_sync_dirmap(project_settings): - """ - Returns dirmap if synch to local project is enabled. - - Only valid mapping is from roots of remote site to local site set in - Local Settings. - - Args: - project_settings (dict) - Returns: - dict : { "source-path": [XXX], "destination-path": [YYYY]} - """ - import json - mapping = {} - - if not project_settings["global"]["sync_server"]["enabled"]: - log.debug("Site Sync not enabled") - return mapping - - from openpype.settings.lib import get_site_local_overrides - from openpype.modules import ModulesManager - - manager = ModulesManager() - sync_module = manager.modules_by_name["sync_server"] - - project_name = os.getenv("AVALON_PROJECT") - sync_settings = sync_module.get_sync_project_setting( - os.getenv("AVALON_PROJECT"), exclude_locals=False, cached=False) - log.debug(json.dumps(sync_settings, indent=4)) - - active_site = sync_module.get_local_normalized_site( - sync_module.get_active_site(project_name)) - remote_site = sync_module.get_local_normalized_site( - sync_module.get_remote_site(project_name)) - log.debug("active {} - remote {}".format(active_site, remote_site)) - - if active_site == "local" \ - and project_name in sync_module.get_enabled_projects()\ - and active_site != remote_site: - overrides = get_site_local_overrides(os.getenv("AVALON_PROJECT"), - active_site) - for root_name, value in overrides.items(): - if os.path.isdir(value): - try: - mapping["destination-path"] = [value] - mapping["source-path"] = [sync_settings["sites"]\ - [remote_site]\ - ["root"]\ - [root_name]] - except IndexError: - # missing corresponding destination path - log.debug("overrides".format(overrides)) - log.error( - ("invalid dirmap mapping, missing corresponding" - " destination directory.")) - break - - log.debug("local sync mapping:: {}".format(mapping)) - return mapping - - def uninstall(): pyblish.deregister_plugin_path(PUBLISH_PATH) avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH) @@ -326,3 +224,12 @@ def before_workfile_save(workfile_path): workdir = os.path.dirname(workfile_path) copy_workspace_mel(workdir) + + +class MayaDirmap(HostDirmap): + def on_enable_dirmap(self): + cmds.dirmap(en=True) + + def dirmap_routine(self, source_path, destination_path): + cmds.dirmap(m=(source_path, destination_path)) + cmds.dirmap(m=(destination_path, source_path)) diff --git a/openpype/lib/path_tools.py b/openpype/lib/path_tools.py index 048bf0eda09..f4385ec66ec 100644 --- a/openpype/lib/path_tools.py +++ b/openpype/lib/path_tools.py @@ -2,6 +2,8 @@ import logging import os import re +import abc +import six from .anatomy import Anatomy @@ -196,3 +198,141 @@ def get_project_basic_paths(project_name): if isinstance(folder_structure, str): folder_structure = json.loads(folder_structure) return _list_path_items(folder_structure) + + +@six.add_metaclass(abc.ABCMeta) +class HostDirmap: + """ + Abstract class for running dirmap on a workfile in a host. + + Dirmap is used to translate paths inside of host workfile from one + OS to another. (Eg. arstist created workfile on Win, different artists + opens same file on Linux.) + + Expects methods to be implemented inside of host: + on_dirmap_enabled: run host code for enabling dirmap + do_dirmap: run host code to do actual remapping + """ + def __init__(self, host_name, project_settings): + self.host_name = host_name + self.project_settings = project_settings + + @abc.abstractmethod + def on_enable_dirmap(self): + """ + Run host dependent operation for enabling dirmap if necessary. + """ + + @abc.abstractmethod + def dirmap_routine(self, source_path, destination_path): + """ + Run host dependent remapping from source_path to destination_path + """ + + def process_dirmap(self): + # type: (dict) -> None + """Go through all paths in Settings and set them using `dirmap`. + + If artists has Site Sync enabled, take dirmap mapping directly from + Local Settings when artist is syncing workfile locally. + + Args: + project_settings (dict): Settings for current project. + + """ + local_mapping = self._get_local_sync_dirmap(self.project_settings) + dirmap_label = "{}-dirmap".format(self.host_name) + if not self.project_settings[self.host_name].get(dirmap_label) and \ + not local_mapping: + return + + mapping = local_mapping or \ + self.project_settings[self.host_name][dirmap_label]["paths"] or {} + mapping_enabled = self.project_settings[self.host_name]\ + [dirmap_label]\ + ["enabled"] \ + or bool(local_mapping) + + if not mapping or not mapping_enabled: + return + if mapping.get("source-path") and mapping_enabled is True: + log.info("Processing directory mapping ...") + self.on_enable_dirmap() + + for k, sp in enumerate(mapping["source-path"]): + try: + print("{} -> {}".format(sp, mapping["destination-path"][k])) + self.dirmap_routine(sp, mapping["destination-path"][k]) + except IndexError: + # missing corresponding destination path + log.error(("invalid dirmap mapping, missing corresponding" + " destination directory.")) + break + except RuntimeError: + log.error("invalid path {} -> {}, mapping not registered".format( #noqa + sp, mapping["destination-path"][k] + )) + continue + + def _get_local_sync_dirmap(self, project_settings): + """ + Returns dirmap if synch to local project is enabled. + + Only valid mapping is from roots of remote site to local site set + in Local Settings. + + Args: + project_settings (dict) + Returns: + dict : { "source-path": [XXX], "destination-path": [YYYY]} + """ + import json + mapping = {} + + if not project_settings["global"]["sync_server"]["enabled"]: + log.debug("Site Sync not enabled") + return mapping + + from openpype.settings.lib import get_site_local_overrides + from openpype.modules import ModulesManager + + manager = ModulesManager() + sync_module = manager.modules_by_name["sync_server"] + + project_name = os.getenv("AVALON_PROJECT") + + active_site = sync_module.get_local_normalized_site( + sync_module.get_active_site(project_name)) + remote_site = sync_module.get_local_normalized_site( + sync_module.get_remote_site(project_name)) + log.debug("active {} - remote {}".format(active_site, remote_site)) + + if active_site == "local" \ + and project_name in sync_module.get_enabled_projects()\ + and active_site != remote_site: + + sync_settings = sync_module.get_sync_project_setting( + os.getenv("AVALON_PROJECT"), exclude_locals=False, + cached=False) + log.debug(json.dumps(sync_settings, indent=4)) + + overrides = get_site_local_overrides(os.getenv("AVALON_PROJECT"), + active_site) + for root_name, value in overrides.items(): + if os.path.isdir(value): + try: + mapping["destination-path"] = [value] + mapping["source-path"] = [sync_settings["sites"]\ + [remote_site]\ + ["root"]\ + [root_name]] + except IndexError: + # missing corresponding destination path + log.debug("overrides".format(overrides)) + log.error( + ("invalid dirmap mapping, missing corresponding" + " destination directory.")) + break + + log.debug("local sync mapping:: {}".format(mapping)) + return mapping From 1bfa8c7daed2021d4e3072080c6ef9ab6e625e8e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 2 Nov 2021 15:33:35 +0100 Subject: [PATCH 2/9] OP-1923 - implemented dirmap for Nuke --- openpype/hosts/nuke/startup/menu.py | 42 +++++++++++++ openpype/lib/path_tools.py | 60 +++++++++++-------- .../defaults/project_settings/nuke.json | 10 +++- .../projects_schema/schema_project_nuke.json | 33 ++++++++++ 4 files changed, 117 insertions(+), 28 deletions(-) diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index c452acb7091..bdbc818ae68 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -1,8 +1,12 @@ +import os from openpype.hosts.nuke.api.lib import ( on_script_load, check_inventory_versions, WorkfileSettings ) +from openpype.lib.path_tools import HostDirmap +from openpype.settings import get_project_settings +from openpype.modules import ModulesManager import nuke from openpype.api import Logger @@ -10,6 +14,29 @@ log = Logger().get_logger(__name__) +class NukeDirmap(HostDirmap): + def __init__(self, host_name, project_settings, sync_module, file_name): + """ + Args: + host_name (str): Nuke + project_settings (dict): settings of current project + sync_module (SyncServerModule): to limit reinitialization + file_name (str): full path of referenced file from workfiles + """ + self.host_name = host_name + self.project_settings = project_settings + self.file_name = file_name + self.sync_module = sync_module + + def on_enable_dirmap(self): + pass + + def dirmap_routine(self, source_path, destination_path): + log.debug("{}: {}->{}".format(self.file_name, + source_path, destination_path)) + self.file_name = self.file_name.replace(source_path, destination_path) + + # fix ffmpeg settings on script nuke.addOnScriptLoad(on_script_load) @@ -20,4 +47,19 @@ # # set apply all workfile settings on script load and save nuke.addOnScriptLoad(WorkfileSettings().set_context_settings) + +project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) +manager = ModulesManager() +sync_module = manager.modules_by_name["sync_server"] + + +def myFilenameFilter(file_name): + dirmap_processor = NukeDirmap("nuke", project_settings, sync_module, + file_name) + dirmap_processor.process_dirmap() + return dirmap_processor.file_name + + +nuke.addFilenameFilter(myFilenameFilter) + log.info('Automatic syncing of write file knob to script version') diff --git a/openpype/lib/path_tools.py b/openpype/lib/path_tools.py index f4385ec66ec..a03f9e862ec 100644 --- a/openpype/lib/path_tools.py +++ b/openpype/lib/path_tools.py @@ -213,9 +213,10 @@ class HostDirmap: on_dirmap_enabled: run host code for enabling dirmap do_dirmap: run host code to do actual remapping """ - def __init__(self, host_name, project_settings): + def __init__(self, host_name, project_settings, sync_module=None): self.host_name = host_name self.project_settings = project_settings + self.sync_module = sync_module # to limit reinit of Modules @abc.abstractmethod def on_enable_dirmap(self): @@ -240,24 +241,12 @@ def process_dirmap(self): project_settings (dict): Settings for current project. """ - local_mapping = self._get_local_sync_dirmap(self.project_settings) - dirmap_label = "{}-dirmap".format(self.host_name) - if not self.project_settings[self.host_name].get(dirmap_label) and \ - not local_mapping: + mapping = self.get_mappings(self.project_settings) + if not mapping: return - mapping = local_mapping or \ - self.project_settings[self.host_name][dirmap_label]["paths"] or {} - mapping_enabled = self.project_settings[self.host_name]\ - [dirmap_label]\ - ["enabled"] \ - or bool(local_mapping) - - if not mapping or not mapping_enabled: - return - if mapping.get("source-path") and mapping_enabled is True: - log.info("Processing directory mapping ...") - self.on_enable_dirmap() + log.info("Processing directory mapping ...") + self.on_enable_dirmap() for k, sp in enumerate(mapping["source-path"]): try: @@ -274,6 +263,24 @@ def process_dirmap(self): )) continue + def get_mappings(self, project_settings): + local_mapping = self._get_local_sync_dirmap(project_settings) + dirmap_label = "{}-dirmap".format(self.host_name) + if not self.project_settings[self.host_name].get(dirmap_label) and \ + not local_mapping: + return [] + + mapping = local_mapping or \ + self.project_settings[self.host_name][dirmap_label]["paths"] or {} + mapping_enabled = self.project_settings[self.host_name]\ + [dirmap_label]\ + ["enabled"] \ + or bool(local_mapping) + + if not mapping or not mapping_enabled: + return [] + return mapping + def _get_local_sync_dirmap(self, project_settings): """ Returns dirmap if synch to local project is enabled. @@ -294,24 +301,25 @@ def _get_local_sync_dirmap(self, project_settings): return mapping from openpype.settings.lib import get_site_local_overrides - from openpype.modules import ModulesManager - manager = ModulesManager() - sync_module = manager.modules_by_name["sync_server"] + if not self.sync_module: + from openpype.modules import ModulesManager + manager = ModulesManager() + self.sync_module = manager.modules_by_name["sync_server"] project_name = os.getenv("AVALON_PROJECT") - active_site = sync_module.get_local_normalized_site( - sync_module.get_active_site(project_name)) - remote_site = sync_module.get_local_normalized_site( - sync_module.get_remote_site(project_name)) + active_site = self.sync_module.get_local_normalized_site( + self.sync_module.get_active_site(project_name)) + remote_site = self.sync_module.get_local_normalized_site( + self.sync_module.get_remote_site(project_name)) log.debug("active {} - remote {}".format(active_site, remote_site)) if active_site == "local" \ - and project_name in sync_module.get_enabled_projects()\ + and project_name in self.sync_module.get_enabled_projects()\ and active_site != remote_site: - sync_settings = sync_module.get_sync_project_setting( + sync_settings = self.sync_module.get_sync_project_setting( os.getenv("AVALON_PROJECT"), exclude_locals=False, cached=False) log.debug(json.dumps(sync_settings, indent=4)) diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index e3c7834e4a5..9741e5277bd 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -8,6 +8,13 @@ "build_workfile": "ctrl+alt+b" } }, + "nuke-dirmap": { + "enabled": true, + "paths": { + "source-path": [], + "destination-path": [] + } + }, "create": { "CreateWriteRender": { "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}", @@ -130,8 +137,7 @@ }, "LoadClip": { "enabled": true, - "_representations": [ - ], + "_representations": [], "node_name_template": "{class_name}_{ext}" } }, diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json index e0b21f4037a..22cb8a4ea3e 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_nuke.json @@ -46,6 +46,39 @@ } ] }, + { + "type": "dict", + "collapsible": true, + "checkbox_key": "enabled", + "key": "nuke-dirmap", + "label": "Nuke Directory Mapping", + "is_group": true, + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "dict", + "key": "paths", + "children": [ + { + "type": "list", + "object_type": "text", + "key": "source-path", + "label": "Source Path" + }, + { + "type": "list", + "object_type": "text", + "key": "destination-path", + "label": "Destination Path" + } + ] + } + ] + }, { "type": "dict", "collapsible": true, From 852cea7714f56143ede2a2e78c98f2198133f7db Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 2 Nov 2021 17:35:09 +0100 Subject: [PATCH 3/9] Hound --- openpype/lib/path_tools.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/openpype/lib/path_tools.py b/openpype/lib/path_tools.py index a03f9e862ec..755be7cbe5d 100644 --- a/openpype/lib/path_tools.py +++ b/openpype/lib/path_tools.py @@ -258,7 +258,7 @@ def process_dirmap(self): " destination directory.")) break except RuntimeError: - log.error("invalid path {} -> {}, mapping not registered".format( #noqa + log.error("invalid path {} -> {}, mapping not registered".format( # noqa: E501 sp, mapping["destination-path"][k] )) continue @@ -272,10 +272,8 @@ def get_mappings(self, project_settings): mapping = local_mapping or \ self.project_settings[self.host_name][dirmap_label]["paths"] or {} - mapping_enabled = self.project_settings[self.host_name]\ - [dirmap_label]\ - ["enabled"] \ - or bool(local_mapping) + enbled = self.project_settings[self.host_name][dirmap_label]["enabled"] + mapping_enabled = enbled or bool(local_mapping) if not mapping or not mapping_enabled: return [] @@ -330,9 +328,9 @@ def _get_local_sync_dirmap(self, project_settings): if os.path.isdir(value): try: mapping["destination-path"] = [value] - mapping["source-path"] = [sync_settings["sites"]\ - [remote_site]\ - ["root"]\ + mapping["source-path"] = [sync_settings["sites"] + [remote_site] + ["root"] [root_name]] except IndexError: # missing corresponding destination path From 863b353eef7b83b7a85b662fe94215039e3928a1 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 3 Nov 2021 12:52:44 +0100 Subject: [PATCH 4/9] OP-1932 - remove wrong defaults for dirmaps --- .../settings/defaults/project_settings/maya.json | 12 +++--------- .../settings/defaults/project_settings/nuke.json | 2 +- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/openpype/settings/defaults/project_settings/maya.json b/openpype/settings/defaults/project_settings/maya.json index f8f3432d0f9..ae1ce9ef137 100644 --- a/openpype/settings/defaults/project_settings/maya.json +++ b/openpype/settings/defaults/project_settings/maya.json @@ -8,16 +8,10 @@ "yetiRig": "ma" }, "maya-dirmap": { - "enabled": true, + "enabled": false, "paths": { - "source-path": [ - "foo1", - "foo2" - ], - "destination-path": [ - "bar1", - "bar2" - ] + "source-path": [], + "destination-path": [] } }, "scriptsmenu": { diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json index 9741e5277bd..069994d0e82 100644 --- a/openpype/settings/defaults/project_settings/nuke.json +++ b/openpype/settings/defaults/project_settings/nuke.json @@ -9,7 +9,7 @@ } }, "nuke-dirmap": { - "enabled": true, + "enabled": false, "paths": { "source-path": [], "destination-path": [] From 93953e65c8b24f424106677e81d6ac7953414b82 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 3 Nov 2021 13:07:17 +0100 Subject: [PATCH 5/9] OP-1932 - refactoring - moved everything to lib Added caching class for expensive operations --- openpype/hosts/nuke/api/lib.py | 61 +++++++++++++++++++++++++++++ openpype/hosts/nuke/startup/menu.py | 44 +-------------------- openpype/lib/path_tools.py | 28 +++++++++---- 3 files changed, 84 insertions(+), 49 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index 9ee3a4464b6..bfbb19ddcb7 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -24,6 +24,10 @@ ApplicationManager ) from openpype.tools.utils import host_tools +from openpype.lib.path_tools import HostDirmap +from openpype.settings import get_project_settings +from openpype.modules import ModulesManager + import nuke from .utils import set_context_favorites @@ -1795,3 +1799,60 @@ def recreate_instance(origin_node, avalon_data=None): dn.setInput(0, new_node) return new_node + + +class NukeDirmap(HostDirmap): + def __init__(self, host_name, project_settings, sync_module, file_name): + """ + Args: + host_name (str): Nuke + project_settings (dict): settings of current project + sync_module (SyncServerModule): to limit reinitialization + file_name (str): full path of referenced file from workfiles + """ + self.host_name = host_name + self.project_settings = project_settings + self.file_name = file_name + self.sync_module = sync_module + + self._mapping = None # cache mapping + + def on_enable_dirmap(self): + pass + + def dirmap_routine(self, source_path, destination_path): + log.debug("{}: {}->{}".format(self.file_name, + source_path, destination_path)) + self.file_name = self.file_name.replace(source_path, destination_path) + + +class DirmapCache: + """Caching class to get settings and sync_module easily and only once.""" + _project_settings = None + _sync_module = None + + @classmethod + def project_settings(cls): + if cls._project_settings is None: + cls._project_settings = get_project_settings( + os.getenv("AVALON_PROJECT")) + return cls._project_settings + + @classmethod + def sync_module(cls): + if cls._sync_module is None: + cls._sync_module = ModulesManager().modules_by_name["sync_server"] + return cls._sync_module + + +def dirmap_file_name_filter(file_name): + """Nuke callback function with single full path argument. + + Checks project settings for potential mapping from source to dest. + """ + dirmap_processor = NukeDirmap("nuke", + DirmapCache.project_settings(), + DirmapCache.sync_module(), + file_name) + dirmap_processor.process_dirmap() + return dirmap_processor.file_name diff --git a/openpype/hosts/nuke/startup/menu.py b/openpype/hosts/nuke/startup/menu.py index bdbc818ae68..b7ed35b3b48 100644 --- a/openpype/hosts/nuke/startup/menu.py +++ b/openpype/hosts/nuke/startup/menu.py @@ -1,42 +1,15 @@ -import os from openpype.hosts.nuke.api.lib import ( on_script_load, check_inventory_versions, WorkfileSettings ) -from openpype.lib.path_tools import HostDirmap -from openpype.settings import get_project_settings -from openpype.modules import ModulesManager import nuke from openpype.api import Logger +from openpype.hosts.nuke.api.lib import dirmap_file_name_filter log = Logger().get_logger(__name__) - -class NukeDirmap(HostDirmap): - def __init__(self, host_name, project_settings, sync_module, file_name): - """ - Args: - host_name (str): Nuke - project_settings (dict): settings of current project - sync_module (SyncServerModule): to limit reinitialization - file_name (str): full path of referenced file from workfiles - """ - self.host_name = host_name - self.project_settings = project_settings - self.file_name = file_name - self.sync_module = sync_module - - def on_enable_dirmap(self): - pass - - def dirmap_routine(self, source_path, destination_path): - log.debug("{}: {}->{}".format(self.file_name, - source_path, destination_path)) - self.file_name = self.file_name.replace(source_path, destination_path) - - # fix ffmpeg settings on script nuke.addOnScriptLoad(on_script_load) @@ -47,19 +20,6 @@ def dirmap_routine(self, source_path, destination_path): # # set apply all workfile settings on script load and save nuke.addOnScriptLoad(WorkfileSettings().set_context_settings) - -project_settings = get_project_settings(os.getenv("AVALON_PROJECT")) -manager = ModulesManager() -sync_module = manager.modules_by_name["sync_server"] - - -def myFilenameFilter(file_name): - dirmap_processor = NukeDirmap("nuke", project_settings, sync_module, - file_name) - dirmap_processor.process_dirmap() - return dirmap_processor.file_name - - -nuke.addFilenameFilter(myFilenameFilter) +nuke.addFilenameFilter(dirmap_file_name_filter) log.info('Automatic syncing of write file knob to script version') diff --git a/openpype/lib/path_tools.py b/openpype/lib/path_tools.py index 755be7cbe5d..193878c9aa6 100644 --- a/openpype/lib/path_tools.py +++ b/openpype/lib/path_tools.py @@ -218,6 +218,8 @@ def __init__(self, host_name, project_settings, sync_module=None): self.project_settings = project_settings self.sync_module = sync_module # to limit reinit of Modules + self._mapping = None # cache mapping + @abc.abstractmethod def on_enable_dirmap(self): """ @@ -241,17 +243,21 @@ def process_dirmap(self): project_settings (dict): Settings for current project. """ - mapping = self.get_mappings(self.project_settings) - if not mapping: + if not self._mapping: + self._mapping = self.get_mappings(self.project_settings) + if not self._mapping: return log.info("Processing directory mapping ...") self.on_enable_dirmap() + log.info("mapping:: {}".format(self._mapping)) - for k, sp in enumerate(mapping["source-path"]): + for k, sp in enumerate(self._mapping["source-path"]): try: - print("{} -> {}".format(sp, mapping["destination-path"][k])) - self.dirmap_routine(sp, mapping["destination-path"][k]) + print("{} -> {}".format(sp, + self._mapping["destination-path"][k])) + self.dirmap_routine(sp, + self._mapping["destination-path"][k]) except IndexError: # missing corresponding destination path log.error(("invalid dirmap mapping, missing corresponding" @@ -259,11 +265,16 @@ def process_dirmap(self): break except RuntimeError: log.error("invalid path {} -> {}, mapping not registered".format( # noqa: E501 - sp, mapping["destination-path"][k] + sp, self._mapping["destination-path"][k] )) continue def get_mappings(self, project_settings): + """Get translation from source-path to destination-path. + + It checks if Site Sync is enabled and user chose to use local + site, in that case configuration in Local Settings takes precedence + """ local_mapping = self._get_local_sync_dirmap(project_settings) dirmap_label = "{}-dirmap".format(self.host_name) if not self.project_settings[self.host_name].get(dirmap_label) and \ @@ -275,8 +286,11 @@ def get_mappings(self, project_settings): enbled = self.project_settings[self.host_name][dirmap_label]["enabled"] mapping_enabled = enbled or bool(local_mapping) - if not mapping or not mapping_enabled: + if not mapping or not mapping_enabled or \ + not mapping.get("destination-path") or \ + not mapping.get("source-path"): return [] + return mapping def _get_local_sync_dirmap(self, project_settings): From 052366c608258bbcff1707eb95e69557e93d5ec7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 3 Nov 2021 15:05:44 +0100 Subject: [PATCH 6/9] OP-1932 - fix - source-path and destination path were switched for local sync --- openpype/lib/path_tools.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openpype/lib/path_tools.py b/openpype/lib/path_tools.py index 193878c9aa6..3dc142c11b4 100644 --- a/openpype/lib/path_tools.py +++ b/openpype/lib/path_tools.py @@ -339,13 +339,12 @@ def _get_local_sync_dirmap(self, project_settings): overrides = get_site_local_overrides(os.getenv("AVALON_PROJECT"), active_site) for root_name, value in overrides.items(): + remote_site_dir = \ + sync_settings["sites"][remote_site]["root"][root_name] if os.path.isdir(value): try: mapping["destination-path"] = [value] - mapping["source-path"] = [sync_settings["sites"] - [remote_site] - ["root"] - [root_name]] + mapping["source-path"] = [remote_site_dir] except IndexError: # missing corresponding destination path log.debug("overrides".format(overrides)) From b0b695159ca21875ffe2dc110ae344b9df60c662 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 4 Nov 2021 19:30:52 +0100 Subject: [PATCH 7/9] OP-1923 - fix - correct choosing of Local Settings overrides --- openpype/lib/path_tools.py | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/openpype/lib/path_tools.py b/openpype/lib/path_tools.py index 3dc142c11b4..6fd0ad0dfe2 100644 --- a/openpype/lib/path_tools.py +++ b/openpype/lib/path_tools.py @@ -280,7 +280,6 @@ def get_mappings(self, project_settings): if not self.project_settings[self.host_name].get(dirmap_label) and \ not local_mapping: return [] - mapping = local_mapping or \ self.project_settings[self.host_name][dirmap_label]["paths"] or {} enbled = self.project_settings[self.host_name][dirmap_label]["enabled"] @@ -290,7 +289,6 @@ def get_mappings(self, project_settings): not mapping.get("destination-path") or \ not mapping.get("source-path"): return [] - return mapping def _get_local_sync_dirmap(self, project_settings): @@ -334,24 +332,25 @@ def _get_local_sync_dirmap(self, project_settings): sync_settings = self.sync_module.get_sync_project_setting( os.getenv("AVALON_PROJECT"), exclude_locals=False, cached=False) - log.debug(json.dumps(sync_settings, indent=4)) - overrides = get_site_local_overrides(os.getenv("AVALON_PROJECT"), - active_site) - for root_name, value in overrides.items(): - remote_site_dir = \ + active_overrides = get_site_local_overrides( + os.getenv("AVALON_PROJECT"), active_site) + remote_overrides = get_site_local_overrides( + os.getenv("AVALON_PROJECT"), remote_site) + + log.debug("local overrides".format(active_overrides)) + log.debug("remote overrides".format(remote_overrides)) + for root_name, active_site_dir in active_overrides.items(): + remote_site_dir = remote_overrides.get(root_name) or\ sync_settings["sites"][remote_site]["root"][root_name] - if os.path.isdir(value): - try: - mapping["destination-path"] = [value] - mapping["source-path"] = [remote_site_dir] - except IndexError: - # missing corresponding destination path - log.debug("overrides".format(overrides)) - log.error( - ("invalid dirmap mapping, missing corresponding" - " destination directory.")) - break + if os.path.isdir(active_site_dir): + if not mapping.get("destination-path"): + mapping["destination-path"] = [] + mapping["destination-path"].append(active_site_dir) + + if not mapping.get("source-path"): + mapping["source-path"] = [] + mapping["source-path"].append(remote_site_dir) log.debug("local sync mapping:: {}".format(mapping)) return mapping From 565489db39c4f6a8e29111e0421db6cdbc1411b5 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 9 Nov 2021 19:01:16 +0100 Subject: [PATCH 8/9] OP-1923 - handle different case for Windows --- openpype/hosts/nuke/api/lib.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index bfbb19ddcb7..d88d7901fec 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1823,7 +1823,12 @@ def on_enable_dirmap(self): def dirmap_routine(self, source_path, destination_path): log.debug("{}: {}->{}".format(self.file_name, source_path, destination_path)) - self.file_name = self.file_name.replace(source_path, destination_path) + if platform.system().lower() == "windows": + self.file_name = self.file_name.lower().replace( + source_path.lower(), destination_path.lower()) + else: + self.file_name = self.file_name.replace( + source_path, destination_path) class DirmapCache: From b87d3e3c6733a278d1ac71e2b00ddd720800dd8a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 10 Nov 2021 12:56:36 +0100 Subject: [PATCH 9/9] OP-1923 - handle back slashes in Settings Replace only when target file exists. --- openpype/hosts/nuke/api/lib.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py index d88d7901fec..6d593ca588f 100644 --- a/openpype/hosts/nuke/api/lib.py +++ b/openpype/hosts/nuke/api/lib.py @@ -1823,9 +1823,11 @@ def on_enable_dirmap(self): def dirmap_routine(self, source_path, destination_path): log.debug("{}: {}->{}".format(self.file_name, source_path, destination_path)) + source_path = source_path.lower().replace(os.sep, '/') + destination_path = destination_path.lower().replace(os.sep, '/') if platform.system().lower() == "windows": self.file_name = self.file_name.lower().replace( - source_path.lower(), destination_path.lower()) + source_path, destination_path) else: self.file_name = self.file_name.replace( source_path, destination_path) @@ -1860,4 +1862,6 @@ def dirmap_file_name_filter(file_name): DirmapCache.sync_module(), file_name) dirmap_processor.process_dirmap() - return dirmap_processor.file_name + if os.path.exists(dirmap_processor.file_name): + return dirmap_processor.file_name + return file_name