From 1531708236cf9f27e459c2b20cd642e5f08905af Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 24 Mar 2023 16:30:46 +0100 Subject: [PATCH] Global: persistent staging directory for renders (#4583) * OP-4258 - Settings for transient template * OP-4258 - added collector for transient staging dir Allows setting profiles to create persistent stagingDir. * OP-4258 - implemented persistent stagingDir in cleanup * OP-4258 - updated logging * OP-4258 - updated settings * OP-4258 - Hound * OP-4258 - renamed class to better name * OP-4258 - changed location of Settings Should be used in create and collecting phase also. * OP-4258 - remove version placeholder from transient template It was discussed that it shouldn't be used for now. * OP-4258 - extracted transient dir query logic This should be used in collection and creation phase for DCCs which are storing staging dir path directly into nodes. * OP-4258 - added use of scene_name placeholder in collector DCC dependent, way how to implement versioning, might not be used. * OP-4258 - fix scene_name * OP-4258 - remove wrong defaults * OP-4258 - added possibility of different template name Studio might want to put renders to different place from caches. * OP-4258 - renamed according to GH comments * OP-4258 - use is active filter * OP-4258 - use is active filter * OP-4793 - added project_settings to signature * OP-4793 - updated logging message * OP-4793 - added documentation * OP-4258 - fix function arguments * OP-4258 - updates to documentation * OP-4258 - added known issues to documentation --------- Co-authored-by: Roy Nieterau --- openpype/pipeline/publish/contants.py | 1 + openpype/pipeline/publish/lib.py | 80 +++++++++++++++++- openpype/plugins/publish/cleanup.py | 4 + openpype/plugins/publish/cleanup_farm.py | 2 +- .../publish/collect_custom_staging_dir.py | 67 +++++++++++++++ .../defaults/project_anatomy/templates.json | 6 +- .../defaults/project_settings/global.json | 3 +- .../schemas/schema_global_tools.json | 65 ++++++++++++++ .../global_tools_custom_staging_dir.png | Bin 0 -> 9940 bytes .../settings_project_global.md | 29 ++++++- 10 files changed, 249 insertions(+), 8 deletions(-) create mode 100644 openpype/plugins/publish/collect_custom_staging_dir.py create mode 100644 website/docs/project_settings/assets/global_tools_custom_staging_dir.png diff --git a/openpype/pipeline/publish/contants.py b/openpype/pipeline/publish/contants.py index 169eca2e5c..c5296afe9a 100644 --- a/openpype/pipeline/publish/contants.py +++ b/openpype/pipeline/publish/contants.py @@ -1,2 +1,3 @@ DEFAULT_PUBLISH_TEMPLATE = "publish" DEFAULT_HERO_PUBLISH_TEMPLATE = "hero" +TRANSIENT_DIR_TEMPLATE = "transient" diff --git a/openpype/pipeline/publish/lib.py b/openpype/pipeline/publish/lib.py index 1ec641bac4..81913bcdd5 100644 --- a/openpype/pipeline/publish/lib.py +++ b/openpype/pipeline/publish/lib.py @@ -20,13 +20,15 @@ from openpype.settings import ( get_system_settings, ) from openpype.pipeline import ( - tempdir + tempdir, + Anatomy ) from openpype.pipeline.plugin_discover import DiscoverResult from .contants import ( DEFAULT_PUBLISH_TEMPLATE, DEFAULT_HERO_PUBLISH_TEMPLATE, + TRANSIENT_DIR_TEMPLATE ) @@ -690,3 +692,79 @@ def get_publish_repre_path(instance, repre, only_published=False): if os.path.exists(src_path): return src_path return None + + +def get_custom_staging_dir_info(project_name, host_name, family, task_name, + task_type, subset_name, + project_settings=None, + anatomy=None, log=None): + """Checks profiles if context should use special custom dir as staging. + + Args: + project_name (str) + host_name (str) + family (str) + task_name (str) + task_type (str) + subset_name (str) + project_settings(Dict[str, Any]): Prepared project settings. + anatomy (Dict[str, Any]) + log (Logger) (optional) + + Returns: + (tuple) + Raises: + ValueError - if misconfigured template should be used + """ + settings = project_settings or get_project_settings(project_name) + custom_staging_dir_profiles = (settings["global"] + ["tools"] + ["publish"] + ["custom_staging_dir_profiles"]) + if not custom_staging_dir_profiles: + return None, None + + if not log: + log = Logger.get_logger("get_custom_staging_dir_info") + + filtering_criteria = { + "hosts": host_name, + "families": family, + "task_names": task_name, + "task_types": task_type, + "subsets": subset_name + } + profile = filter_profiles(custom_staging_dir_profiles, + filtering_criteria, + logger=log) + + if not profile or not profile["active"]: + return None, None + + if not anatomy: + anatomy = Anatomy(project_name) + + template_name = profile["template_name"] or TRANSIENT_DIR_TEMPLATE + _validate_transient_template(project_name, template_name, anatomy) + + custom_staging_dir = anatomy.templates[template_name]["folder"] + is_persistent = profile["custom_staging_dir_persistent"] + + return custom_staging_dir, is_persistent + + +def _validate_transient_template(project_name, template_name, anatomy): + """Check that transient template is correctly configured. + + Raises: + ValueError - if misconfigured template + """ + if template_name not in anatomy.templates: + raise ValueError(("Anatomy of project \"{}\" does not have set" + " \"{}\" template key!" + ).format(project_name, template_name)) + + if "folder" not in anatomy.templates[template_name]: + raise ValueError(("There is not set \"folder\" template in \"{}\" anatomy" # noqa + " for project \"{}\"." + ).format(template_name, project_name)) diff --git a/openpype/plugins/publish/cleanup.py b/openpype/plugins/publish/cleanup.py index ef312e391f..b90c88890d 100644 --- a/openpype/plugins/publish/cleanup.py +++ b/openpype/plugins/publish/cleanup.py @@ -93,6 +93,10 @@ class CleanUp(pyblish.api.InstancePlugin): self.log.info("No staging directory found: %s" % staging_dir) return + if instance.data.get("stagingDir_persistent"): + self.log.info("Staging dir: %s should be persistent" % staging_dir) + return + self.log.info("Removing staging directory {}".format(staging_dir)) shutil.rmtree(staging_dir) diff --git a/openpype/plugins/publish/cleanup_farm.py b/openpype/plugins/publish/cleanup_farm.py index b87d4698a2..8052f13734 100644 --- a/openpype/plugins/publish/cleanup_farm.py +++ b/openpype/plugins/publish/cleanup_farm.py @@ -37,7 +37,7 @@ class CleanUpFarm(pyblish.api.ContextPlugin): dirpaths_to_remove = set() for instance in context: staging_dir = instance.data.get("stagingDir") - if staging_dir: + if staging_dir and not instance.data.get("stagingDir_persistent"): dirpaths_to_remove.add(os.path.normpath(staging_dir)) if "representations" in instance.data: diff --git a/openpype/plugins/publish/collect_custom_staging_dir.py b/openpype/plugins/publish/collect_custom_staging_dir.py new file mode 100644 index 0000000000..72ab0fe34d --- /dev/null +++ b/openpype/plugins/publish/collect_custom_staging_dir.py @@ -0,0 +1,67 @@ +""" +Requires: + anatomy + + +Provides: + instance.data -> stagingDir (folder path) + -> stagingDir_persistent (bool) +""" +import copy +import os.path + +import pyblish.api + +from openpype.pipeline.publish.lib import get_custom_staging_dir_info + + +class CollectCustomStagingDir(pyblish.api.InstancePlugin): + """Looks through profiles if stagingDir should be persistent and in special + location. + + Transient staging dir could be useful in specific use cases where is + desirable to have temporary renders in specific, persistent folders, could + be on disks optimized for speed for example. + + It is studio responsibility to clean up obsolete folders with data. + + Location of the folder is configured in `project_anatomy/templates/others`. + ('transient' key is expected, with 'folder' key) + + Which family/task type/subset is applicable is configured in: + `project_settings/global/tools/publish/custom_staging_dir_profiles` + + """ + label = "Collect Custom Staging Directory" + order = pyblish.api.CollectorOrder + 0.4990 + + template_key = "transient" + + def process(self, instance): + family = instance.data["family"] + subset_name = instance.data["subset"] + host_name = instance.context.data["hostName"] + project_name = instance.context.data["projectName"] + + anatomy = instance.context.data["anatomy"] + anatomy_data = copy.deepcopy(instance.data["anatomyData"]) + task = anatomy_data.get("task", {}) + + transient_tml, is_persistent = get_custom_staging_dir_info( + project_name, host_name, family, task.get("name"), + task.get("type"), subset_name, anatomy=anatomy, log=self.log) + result_str = "Not adding" + if transient_tml: + anatomy_data["root"] = anatomy.roots + scene_name = instance.context.data.get("currentFile") + if scene_name: + anatomy_data["scene_name"] = os.path.basename(scene_name) + transient_dir = transient_tml.format(**anatomy_data) + instance.data["stagingDir"] = transient_dir + + instance.data["stagingDir_persistent"] = is_persistent + result_str = "Adding '{}' as".format(transient_dir) + + self.log.info("{} custom staging dir for instance with '{}'".format( + result_str, family + )) diff --git a/openpype/settings/defaults/project_anatomy/templates.json b/openpype/settings/defaults/project_anatomy/templates.json index 02c0e35377..e5e535bf19 100644 --- a/openpype/settings/defaults/project_anatomy/templates.json +++ b/openpype/settings/defaults/project_anatomy/templates.json @@ -58,12 +58,16 @@ "file": "{originalBasename}.{ext}", "path": "{@folder}/{@file}" }, + "transient": { + "folder": "{root[work]}/{project[name]}/{hierarchy}/{asset}/work/{family}/{subset}" + }, "__dynamic_keys_labels__": { "maya2unreal": "Maya to Unreal", "simpleUnrealTextureHero": "Simple Unreal Texture - Hero", "simpleUnrealTexture": "Simple Unreal Texture", "online": "online", - "source": "source" + "source": "source", + "transient": "transient" } } } diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index aad17d54da..aba840da78 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -591,7 +591,8 @@ "task_names": [], "template_name": "simpleUnrealTextureHero" } - ] + ], + "custom_staging_dir_profiles": [] } }, "project_folder_structure": "{\"__project_root__\": {\"prod\": {}, \"resources\": {\"footage\": {\"plates\": {}, \"offline\": {}}, \"audio\": {}, \"art_dept\": {}}, \"editorial\": {}, \"assets\": {\"characters\": {}, \"locations\": {}}, \"shots\": {}}}", diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_tools.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_tools.json index 962008d476..85ec482e73 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_tools.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_tools.json @@ -408,6 +408,71 @@ } ] } + }, + { + "type": "list", + "key": "custom_staging_dir_profiles", + "label": "Custom Staging Dir Profiles", + "use_label_wrap": true, + "docstring": "Profiles to specify special location and persistence for staging dir. Could be used in Creators and Publish phase!", + "object_type": { + "type": "dict", + "children": [ + { + "type": "boolean", + "key": "active", + "label": "Is active", + "default": true + }, + { + "type": "separator" + }, + { + "key": "hosts", + "label": "Host names", + "type": "hosts-enum", + "multiselection": true + }, + { + "key": "task_types", + "label": "Task types", + "type": "task-types-enum" + }, + { + "key": "task_names", + "label": "Task names", + "type": "list", + "object_type": "text" + }, + { + "key": "families", + "label": "Families", + "type": "list", + "object_type": "text" + }, + { + "key": "subsets", + "label": "Subset names", + "type": "list", + "object_type": "text" + }, + { + "type": "separator" + }, + { + "key": "custom_staging_dir_persistent", + "label": "Custom Staging Folder Persistent", + "type": "boolean", + "default": false + }, + { + "key": "template_name", + "label": "Template Name", + "type": "text", + "placeholder": "transient" + } + ] + } } ] } diff --git a/website/docs/project_settings/assets/global_tools_custom_staging_dir.png b/website/docs/project_settings/assets/global_tools_custom_staging_dir.png new file mode 100644 index 0000000000000000000000000000000000000000..f7e8660a8863239310a1934a49c2811b4e0c031b GIT binary patch literal 9940 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 VmwKMN3A}U$l9y4I&XY9q`!5KAZJhuB literal 0 HcmV?d00001 diff --git a/website/docs/project_settings/settings_project_global.md b/website/docs/project_settings/settings_project_global.md index b6d624caa8..821585ae21 100644 --- a/website/docs/project_settings/settings_project_global.md +++ b/website/docs/project_settings/settings_project_global.md @@ -230,10 +230,10 @@ Applicable context filters: ## Tools Settings for OpenPype tools. -## Creator +### Creator Settings related to [Creator tool](artist_tools_creator). -### Subset name profiles +#### Subset name profiles ![global_tools_creator_subset_template](assets/global_tools_creator_subset_template.png) Subset name helps to identify published content. More specific name helps with organization and avoid mixing of published content. Subset name is defined using one of templates defined in **Subset name profiles settings**. The template is filled with context information at the time of creation. @@ -263,10 +263,31 @@ Template may look like `"{family}{Task}{Variant}"`. Some creators may have other keys as their context may require more information or more specific values. Make sure you've read documentation of host you're using. -## Workfiles +### Publish + +#### Custom Staging Directory Profiles +With this feature, users can specify a custom data folder path based on presets, which can be used during the creation and publishing stages. + +![global_tools_custom_staging_dir](assets/global_tools_custom_staging_dir.png) + +Staging directories are used as a destination for intermediate files (as renders) before they are renamed and copied to proper location during the integration phase. They could be created completely dynamically in the temp folder or for some DCCs in the `work` area. +Example could be Nuke where artist might want to temporarily render pictures into `work` area to check them before they get published with the choice of "Use existing frames" on the write node. + +One of the key advantages of this feature is that it allows users to choose the folder for writing such intermediate files to take advantage of faster storage for rendering, which can help improve workflow efficiency. Additionally, this feature allows users to keep their intermediate extracted data persistent, and use their own infrastructure for regular cleaning. + +In some cases, these DCCs (Nuke, Houdini, Maya) automatically add a rendering path during the creation stage, which is then used in publishing. Creators and extractors of such DCCs need to use these profiles to fill paths in DCC's nodes to use this functionality. + +The custom staging folder uses a path template configured in `project_anatomy/templates/others` with `transient` being a default example path that could be used. The template requires a 'folder' key for it to be usable as custom staging folder. + +##### Known issues +- Any DCC that uses prefilled paths and store them inside of workfile nodes needs to implement resolving these paths with a configured profiles. +- If studio uses Site Sync remote artists need to have access to configured custom staging folder! +- Each node on the rendering farm must have access to configured custom staging folder! + +### Workfiles All settings related to Workfile tool. -### Open last workfile at launch +#### Open last workfile at launch This feature allows you to define a rule for each task/host or toggle the feature globally to all tasks as they are visible in the picture. ![global_tools_workfile_open_last_version](assets/global_tools_workfile_open_last_version.png)