From d9ace72072b6c4cff625f8fe93a3c383773d0256 Mon Sep 17 00:00:00 2001 From: Luma Date: Wed, 18 Feb 2026 13:33:00 +0200 Subject: [PATCH 1/4] updated from develop instead of tag --- client/ayon_usd/ayon_bin_client | 2 +- client/ayon_usd/version.py | 2 +- package.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_usd/ayon_bin_client b/client/ayon_usd/ayon_bin_client index 36c6af1..e993a87 160000 --- a/client/ayon_usd/ayon_bin_client +++ b/client/ayon_usd/ayon_bin_client @@ -1 +1 @@ -Subproject commit 36c6af1fecedb0feedead7ab363cc0c2573a5d8b +Subproject commit e993a87f6973147bf8e42f81051575d3f7a97be6 diff --git a/client/ayon_usd/version.py b/client/ayon_usd/version.py index bf23bd9..fe8aad3 100644 --- a/client/ayon_usd/version.py +++ b/client/ayon_usd/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON addon 'usd' version.""" -__version__ = "0.1.4+dev" +__version__ = "0.1.4-ls.0.0.4" diff --git a/package.py b/package.py index 76340c2..1b0d7e9 100644 --- a/package.py +++ b/package.py @@ -2,7 +2,7 @@ name = "usd" title = "USD" -version = "0.1.4+dev" +version = "0.1.4-ls.0.0.4" client_dir = "ayon_usd" services = {} From 5eb8b049c7a5c4871127c74c15633ad37bcf3ad1 Mon Sep 17 00:00:00 2001 From: Neill Vermaak Date: Wed, 18 Feb 2026 16:42:15 +0200 Subject: [PATCH 2/4] updates to local resolver --- client/ayon_usd/hooks/pre_resolver_init.py | 39 ++++++++++++++++++---- client/ayon_usd/utils.py | 26 +++++++++++++++ server/settings/main.py | 38 +++++++++++++++++++++ 3 files changed, 96 insertions(+), 7 deletions(-) diff --git a/client/ayon_usd/hooks/pre_resolver_init.py b/client/ayon_usd/hooks/pre_resolver_init.py index 2b0171e..92fa9e6 100644 --- a/client/ayon_usd/hooks/pre_resolver_init.py +++ b/client/ayon_usd/hooks/pre_resolver_init.py @@ -2,7 +2,7 @@ import json import os -from ayon_applications import LaunchTypes, PreLaunchHook +from ayon_applications import PreLaunchHook from ayon_usd import config, utils from ayon_usd.addon import ADDON_DATA_JSON_PATH @@ -14,10 +14,6 @@ class InitializeAssetResolver(PreLaunchHook): """ app_groups = {"maya", "houdini", "unreal"} - # TODO Use `farm_render` instead of `farm_publish` - # once this issue is resolved - # https://github.com/ynput/ayon-applications/issues/2 - launch_types = {LaunchTypes.local, LaunchTypes.farm_publish} def execute(self): """Pre-launch hook entry method.""" @@ -28,6 +24,23 @@ def execute(self): " disabled.") return + # Check for a locally-configured resolver path first + local_path = utils.get_local_resolver_path( + project_settings, self.app_name + ) + if local_path: + if not os.path.isdir(local_path): + self.log.error( + f"Local resolver path does not exist: {local_path}" + ) + return + self.log.info( + f"Using local resolver path for {self.app_name}: {local_path}" + ) + self._setup_resolver(local_path, project_settings) + return + + # Fall through to lakeFS-based resolver download resolver_lake_fs_path = utils.get_resolver_to_download( project_settings, self.app_name) if not resolver_lake_fs_path: @@ -52,8 +65,20 @@ def execute(self): return # Check for existing local resolver that matches the lakefs timestamp - with open(ADDON_DATA_JSON_PATH, "r") as data_json: - addon_data_json = json.load(data_json) + addon_data_json = {} + if os.path.exists(ADDON_DATA_JSON_PATH): + try: + with open(ADDON_DATA_JSON_PATH, "r") as data_json: + addon_data_json = json.load(data_json) + except (json.JSONDecodeError, OSError): + self.log.warning( + "Could not read addon data JSON, starting fresh." + ) + addon_data_json = {} + + if not addon_data_json: + # Ensure the downloads directory exists + os.makedirs(os.path.dirname(ADDON_DATA_JSON_PATH), exist_ok=True) key = str(self.app_name).replace("/", "_") local_resolver_key = f"resolver_data_{key}" diff --git a/client/ayon_usd/utils.py b/client/ayon_usd/utils.py index ad85c49..26a24a7 100644 --- a/client/ayon_usd/utils.py +++ b/client/ayon_usd/utils.py @@ -110,6 +110,32 @@ def lakefs_download_and_extract(resolver_lake_fs_path: str, return str(extract_zip_item.func_return) +def get_local_resolver_path(settings, app_name: str): + """Check local_resolver_paths for a matching app + platform entry. + + Args: + settings (dict): Project settings. + app_name (str): Application name, e.g. "houdini/20-5". + + Returns: + str | None: Local filesystem path to the resolver directory, + or None if no match found. + + """ + local_paths = ( + settings["usd"]["distribution"].get("local_resolver_paths", []) + ) + current_platform = platform.system().lower() + for entry in local_paths: + if entry["platform"] != current_platform: + continue + if entry["name"] == app_name or app_name in entry.get( + "app_alias_list", [] + ): + return entry["path"] + return None + + def get_resolver_to_download(settings, app_name: str) -> str: """ Gets LakeFs path that can be used with copy element to download diff --git a/server/settings/main.py b/server/settings/main.py index d5f2e08..bd8a08b 100644 --- a/server/settings/main.py +++ b/server/settings/main.py @@ -98,6 +98,34 @@ class AppPlatformURIModel(BaseSettingsModel): ) +class LocalResolverPathModel(BaseSettingsModel): + """Local filesystem path to a pre-installed resolver.""" + + _layout = "collapsed" + name: str = SettingsField( + title="App Name", + description="Application name, e.g. houdini/20-5", + ) + app_alias_list: list[str] = SettingsField( + title="Application Alias", + description="Define a list of App Names that use the same " + "resolver as the parent application", + default_factory=list, + ) + platform: str = SettingsField( + title="Platform", + enum_resolver=platform_enum, + description="windows / linux / darwin", + ) + path: str = SettingsField( + title="Resolver Directory Path", + description=( + "Local filesystem path to the resolver directory " + "(the directory containing `ayonUsdResolver/`)" + ), + ) + + class BinaryDistributionSettings(BaseSettingsModel): """Binary distribution of USD and AYON USD Resolver""" @@ -105,6 +133,16 @@ class BinaryDistributionSettings(BaseSettingsModel): enabled: bool = SettingsField(False) + local_resolver_paths: list[LocalResolverPathModel] = SettingsField( + title="Local Resolver Paths", + description=( + "Local filesystem paths to pre-installed resolver binaries. " + "When a match is found for the current app and platform, " + "the resolver is loaded directly without downloading from lakeFS." + ), + default_factory=list, + ) + server_uri: str = SettingsField( "https://lake.ayon.cloud", title="Server URL", From c0f23ae9c1d653ba1138502135c3734053e57a31 Mon Sep 17 00:00:00 2001 From: Christophe Leyder Date: Fri, 20 Feb 2026 15:26:53 +0200 Subject: [PATCH 3/4] - Add LocalResolverPathModel settings to configure pre-installed resolver paths per app and platform, bypassing lakeFS downloads - Add get_local_resolver_path utility to match resolver by app name, alias, and platform - Update pre_resolver_init hook to prefer local resolver paths, support farm_publish launch type, and skip lakeFS on farm workers - Harden addon data JSON reading with error handling for missing/corrupt files - Add CollectResolverEnvVars publish plugin to forward resolver config vars (TF_DEBUG, logger settings) to farm job environments --- client/ayon_usd/hooks/pre_resolver_init.py | 16 +++++ .../publish/collect_resolver_env_vars.py | 70 +++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 client/ayon_usd/plugins/publish/collect_resolver_env_vars.py diff --git a/client/ayon_usd/hooks/pre_resolver_init.py b/client/ayon_usd/hooks/pre_resolver_init.py index 92fa9e6..f314cd1 100644 --- a/client/ayon_usd/hooks/pre_resolver_init.py +++ b/client/ayon_usd/hooks/pre_resolver_init.py @@ -3,6 +3,7 @@ import json import os from ayon_applications import PreLaunchHook +from ayon_applications.defs import LaunchTypes from ayon_usd import config, utils from ayon_usd.addon import ADDON_DATA_JSON_PATH @@ -14,6 +15,7 @@ class InitializeAssetResolver(PreLaunchHook): """ app_groups = {"maya", "houdini", "unreal"} + launch_types = {LaunchTypes.local, LaunchTypes.farm_publish} def execute(self): """Pre-launch hook entry method.""" @@ -24,6 +26,11 @@ def execute(self): " disabled.") return + is_farm = ( + hasattr(self, "launch_type") + and self.launch_type == LaunchTypes.farm_publish + ) + # Check for a locally-configured resolver path first local_path = utils.get_local_resolver_path( project_settings, self.app_name @@ -40,6 +47,15 @@ def execute(self): self._setup_resolver(local_path, project_settings) return + # On the farm, skip the lakeFS download — workers may not have access + if is_farm: + self.log.warning( + "No local resolver path configured for " + f"'{self.app_name}' on this platform. " + "Skipping lakeFS download on farm worker." + ) + return + # Fall through to lakeFS-based resolver download resolver_lake_fs_path = utils.get_resolver_to_download( project_settings, self.app_name) diff --git a/client/ayon_usd/plugins/publish/collect_resolver_env_vars.py b/client/ayon_usd/plugins/publish/collect_resolver_env_vars.py new file mode 100644 index 0000000..40666ba --- /dev/null +++ b/client/ayon_usd/plugins/publish/collect_resolver_env_vars.py @@ -0,0 +1,70 @@ +"""Collect USD resolver environment variables for farm job submission. + +Emits platform-independent config vars (TF_DEBUG, logger settings) into +the farm job environment. Path-based vars (PXR_PLUGINPATH_NAME, PYTHONPATH, +LD_LIBRARY_PATH) are NOT set here — they are injected by the +``pre_resolver_init`` hook which runs during ``extractenvironments`` on each +worker, producing paths correct for that worker's OS. +""" + +import os + +import pyblish.api + +from ayon_core.pipeline.publish import FARM_JOB_ENV_DATA_KEY + + +class CollectResolverEnvVars(pyblish.api.InstancePlugin): + """Collect USD resolver env vars for farm jobs. + + Non-path settings (``TF_DEBUG``, logger config) are read directly + from the USD addon settings and added to the farm job environment. + """ + + order = pyblish.api.CollectorOrder + 0.251 + label = "Collect USD Resolver Env Vars (Farm Job)" + + families = [ + # Maya + "renderlayer", + # Houdini + "usdrender", + "publish.hou", + "remote_publish_on_farm", + "redshift_rop", + "arnold_rop", + "mantra_rop", + "karma_rop", + "vray_rop", + ] + targets = ["local"] + hosts = ["maya", "houdini"] + + def process(self, instance): + if not instance.data.get("farm"): + self.log.debug("Not a farm instance, skipping.") + return + + settings = instance.context.data["project_settings"] + job_env = instance.data.setdefault(FARM_JOB_ENV_DATA_KEY, {}) + + # --- Non-path config (from USD addon settings) ------------------- + usd_settings = settings.get("usd", {}) + resolver_cfg = usd_settings.get("ayon_usd_resolver", {}) + config_vars = { + "TF_DEBUG": usd_settings.get("usd", {}).get("usd_tf_debug", ""), + "AYONLOGGERLOGLVL": resolver_cfg.get("ayon_log_lvl", ""), + "AYONLOGGERSFILELOGGING": resolver_cfg.get( + "ayon_file_logger_enabled", "" + ), + "AYONLOGGERSFILEPOS": resolver_cfg.get( + "file_logger_file_path", "" + ), + "AYON_LOGGIN_LOGGIN_KEYS": resolver_cfg.get( + "ayon_logger_logging_keys", "" + ), + } + for key, value in config_vars.items(): + if value: + self.log.debug(f"Setting job env (config): {key}: {value}") + job_env[key] = str(value) From 375da44ebec770b0df0e1f65822b9c5811f2376f Mon Sep 17 00:00:00 2001 From: Christophe Leyder Date: Wed, 8 Apr 2026 06:12:41 +0200 Subject: [PATCH 4/4] Bump version to 0.1.6+ls.0.0.1 --- client/ayon_usd/version.py | 2 +- package.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_usd/version.py b/client/ayon_usd/version.py index e2e94d7..ed19cc0 100644 --- a/client/ayon_usd/version.py +++ b/client/ayon_usd/version.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- """Package declaring AYON addon 'usd' version.""" -__version__ = "0.1.6+dev" +__version__ = "0.1.6+ls.0.0.1" diff --git a/package.py b/package.py index 686d056..f1e95d7 100644 --- a/package.py +++ b/package.py @@ -2,7 +2,7 @@ name = "usd" title = "USD" -version = "0.1.6+dev" +version = "0.1.6+ls.0.0.1" client_dir = "ayon_usd" services = {}