From 65db6d34639e9ebf22b477bbaca9c3cd87f8c077 Mon Sep 17 00:00:00 2001 From: Fabia Serra Arrizabalaga Date: Wed, 21 Aug 2024 16:49:47 -0400 Subject: [PATCH 1/4] Add support to run the workfile template builder on startup --- client/ayon_houdini/api/lib.py | 15 +++++++++++++++ client/ayon_houdini/api/pipeline.py | 6 ++++++ .../ayon_houdini/api/workfile_template_builder.py | 4 ++-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/client/ayon_houdini/api/lib.py b/client/ayon_houdini/api/lib.py index 3c2520250d..aea877f353 100644 --- a/client/ayon_houdini/api/lib.py +++ b/client/ayon_houdini/api/lib.py @@ -21,6 +21,9 @@ from ayon_core.pipeline.create import CreateContext from ayon_core.pipeline.template_data import get_template_data from ayon_core.pipeline.context_tools import get_current_task_entity +from ayon_core.pipeline.workfile.workfile_template_builder import ( + TemplateProfileNotFound +) from ayon_core.tools.utils import PopupUpdateKeys, SimplePopup from ayon_core.tools.utils.host_tools import get_tool_by_name @@ -1360,3 +1363,15 @@ def prompt_reset_context(): update_content_on_context_change() dialog.deleteLater() + + +def start_workfile_template_builder(): + from .workfile_template_builder import ( + build_workfile_template + ) + + log.info("Starting workfile template builder...") + try: + build_workfile_template(workfile_creation_enabled=True) + except TemplateProfileNotFound: + log.warning("Template profile not found. Skipping...") diff --git a/client/ayon_houdini/api/pipeline.py b/client/ayon_houdini/api/pipeline.py index 3f2fe17f18..5b7e627524 100644 --- a/client/ayon_houdini/api/pipeline.py +++ b/client/ayon_houdini/api/pipeline.py @@ -86,6 +86,11 @@ def install(self): # opening with last workfile. _set_context_settings() + # Manually call on_new callback as it doesn't get called when AYON + # launches for the first time on a context, only when going to + # File -> New + on_new() + if not IS_HEADLESS: import hdefereval # noqa, hdefereval is only available in ui mode # Defer generation of shelves due to issue on Windows where shelf @@ -414,6 +419,7 @@ def _enforce_start_frame(): if hou.isUIAvailable(): import hdefereval + hdefereval.executeDeferred(lib.start_workfile_template_builder) hdefereval.executeDeferred(_enforce_start_frame) else: # Run without execute deferred when no UI is available because diff --git a/client/ayon_houdini/api/workfile_template_builder.py b/client/ayon_houdini/api/workfile_template_builder.py index a3f95f16cf..252f175f13 100644 --- a/client/ayon_houdini/api/workfile_template_builder.py +++ b/client/ayon_houdini/api/workfile_template_builder.py @@ -239,10 +239,10 @@ def delete_placeholder(self, placeholder): placeholder_node.destroy() -def build_workfile_template(*args): +def build_workfile_template(*args, **kwargs): # NOTE Should we inform users that they'll lose unsaved changes ? builder = HoudiniTemplateBuilder(registered_host()) - builder.build_template() + builder.build_template(*args, **kwargs) def update_workfile_template(*args): From 9c8c60c3251251c8dd0c04a9a76b02a86b18c2fc Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 6 Sep 2024 17:12:23 +0200 Subject: [PATCH 2/4] Do not call `_set_context_settings` because `on_new` already triggers that --- client/ayon_houdini/api/pipeline.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/ayon_houdini/api/pipeline.py b/client/ayon_houdini/api/pipeline.py index 5b7e627524..b0d1c388e6 100644 --- a/client/ayon_houdini/api/pipeline.py +++ b/client/ayon_houdini/api/pipeline.py @@ -79,13 +79,6 @@ def install(self): self._has_been_setup = True - # Set folder settings for the empty scene directly after launch of - # Houdini so it initializes into the correct scene FPS, - # Frame Range, etc. - # TODO: make sure this doesn't trigger when - # opening with last workfile. - _set_context_settings() - # Manually call on_new callback as it doesn't get called when AYON # launches for the first time on a context, only when going to # File -> New From c5784bb456840ccc4bc583fdd4f81d83521abf38 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Fri, 6 Sep 2024 17:13:54 +0200 Subject: [PATCH 3/4] Refactor the Houdini-specific resolve logic to `resolve_template_path` in favor of an upcoming feature in ayon-core --- .../api/workfile_template_builder.py | 131 ++---------------- 1 file changed, 9 insertions(+), 122 deletions(-) diff --git a/client/ayon_houdini/api/workfile_template_builder.py b/client/ayon_houdini/api/workfile_template_builder.py index 252f175f13..59fa4aa271 100644 --- a/client/ayon_houdini/api/workfile_template_builder.py +++ b/client/ayon_houdini/api/workfile_template_builder.py @@ -1,18 +1,9 @@ -import os - import hou -from ayon_core.lib import ( - StringTemplate, - filter_profiles, -) -from ayon_core.pipeline import registered_host, Anatomy +from ayon_core.pipeline import registered_host from ayon_core.pipeline.workfile.workfile_template_builder import ( AbstractTemplateBuilder, - PlaceholderPlugin, - TemplateProfileNotFound, - TemplateLoadFailed, - TemplateNotFound + PlaceholderPlugin ) from ayon_core.tools.workfile_template_build import ( WorkfileBuildPlaceholderDialog, @@ -29,121 +20,17 @@ class HoudiniTemplateBuilder(AbstractTemplateBuilder): """Concrete implementation of AbstractTemplateBuilder for Houdini""" - - def get_template_preset(self): - """Unified way how template preset is received using settings. - Method is dependent on '_get_build_profiles' which should return filter - profiles to resolve path to a template. Default implementation looks - into host settings: - - 'project_settings/{host name}/templated_workfile_build/profiles' + def resolve_template_path(self, path: str) -> str: + """Allows additional resolving over the template path using custom + integration methods, like Houdini's expand string functionality. - Returns: - dict: Dictionary with `path`, `keep_placeholder` and - `create_first_version` settings from the template preset - for current context. - - Raises: - TemplateProfileNotFound: When profiles are not filled. - TemplateLoadFailed: Profile was found but path is not set. - TemplateNotFound: Path was set but file does not exist. + This only works with ayon-core 0.4.5+ """ - - host_name = self.host_name - project_name = self.project_name - task_name = self.current_task_name - task_type = self.current_task_type - - build_profiles = self._get_build_profiles() - profile = filter_profiles( - build_profiles, - { - "task_types": task_type, - "task_names": task_name - } - ) - - if not profile: - raise TemplateProfileNotFound(( - "No matching profile found for task '{}' of type '{}' " - "with host '{}'" - ).format(task_name, task_type, host_name)) - - path = profile["path"] - - # switch to remove placeholders after they are used - keep_placeholder = profile.get("keep_placeholder") - create_first_version = profile.get("create_first_version") - - # backward compatibility, since default is True - if keep_placeholder is None: - keep_placeholder = True - - if not path: - raise TemplateLoadFailed(( - "Template path is not set.\n" - "Path need to be set in {}\\Template Workfile Build " - "Settings\\Profiles" - ).format(host_name.title())) - - # Try fill path with environments and anatomy roots - anatomy = Anatomy(project_name) - fill_data = { - key: value - for key, value in os.environ.items() - } - - fill_data["root"] = anatomy.roots - fill_data["project"] = { - "name": project_name, - "code": anatomy.project_code, - } - - result = StringTemplate.format_template(path, fill_data) - if result.solved: - path = result.normalized() - - # I copied the whole thing because I wanted to add some - # Houdini specific code here + # escape backslashes for `expandString` + path = path.replace("\\", "\\\\") path = hou.text.expandString(path) - - if path and os.path.exists(path): - self.log.info("Found template at: '{}'".format(path)) - return { - "path": path, - "keep_placeholder": keep_placeholder, - "create_first_version": create_first_version - } - - solved_path = None - while True: - try: - solved_path = anatomy.path_remapper(path) - except KeyError as missing_key: - raise KeyError( - "Could not solve key '{}' in template path '{}'".format( - missing_key, path)) - - if solved_path is None: - solved_path = path - if solved_path == path: - break - path = solved_path - - solved_path = os.path.normpath(solved_path) - if not os.path.exists(solved_path): - raise TemplateNotFound( - "Template found in AYON settings for task '{}' with host " - "'{}' does not exists. (Not found : {})".format( - task_name, host_name, solved_path)) - - self.log.info("Found template at: '{}'".format(solved_path)) - - return { - "path": solved_path, - "keep_placeholder": keep_placeholder, - "create_first_version": create_first_version - } + return path def import_template(self, path): """Import template into current scene. From 198cb40657a985ce7e932eecea1c17ad90c394c2 Mon Sep 17 00:00:00 2001 From: Roy Nieterau Date: Mon, 9 Sep 2024 16:25:35 +0200 Subject: [PATCH 4/4] Update to changes in https://github.com/ynput/ayon-core/pull/875 --- client/ayon_houdini/api/workfile_template_builder.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/ayon_houdini/api/workfile_template_builder.py b/client/ayon_houdini/api/workfile_template_builder.py index 59fa4aa271..678cd47d5e 100644 --- a/client/ayon_houdini/api/workfile_template_builder.py +++ b/client/ayon_houdini/api/workfile_template_builder.py @@ -21,13 +21,16 @@ class HoudiniTemplateBuilder(AbstractTemplateBuilder): """Concrete implementation of AbstractTemplateBuilder for Houdini""" - def resolve_template_path(self, path: str) -> str: + def resolve_template_path(self, path, fill_data): """Allows additional resolving over the template path using custom integration methods, like Houdini's expand string functionality. This only works with ayon-core 0.4.5+ """ - # escape backslashes for `expandString` + # use default template data formatting + path = super().resolve_template_path(path, fill_data) + + # escape backslashes for `expandString` and expand houdini vars path = path.replace("\\", "\\\\") path = hou.text.expandString(path) return path