Merge pull request #1148 from ynput/feature/envs-in-roots

Chore: Environment variables in roots
This commit is contained in:
Jakub Trllo 2025-04-07 15:39:13 +02:00 committed by GitHub
commit a1e2efc51b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 47 additions and 14 deletions

View file

@ -1,12 +1,15 @@
from ayon_api import get_project, get_folder_by_path, get_task_by_name from ayon_api import get_project, get_folder_by_path, get_task_by_name
from ayon_core.pipeline import Anatomy
from ayon_core.pipeline.anatomy import RootMissingEnv
from ayon_applications import PreLaunchHook from ayon_applications import PreLaunchHook
from ayon_applications.exceptions import ApplicationLaunchFailed
from ayon_applications.utils import ( from ayon_applications.utils import (
EnvironmentPrepData, EnvironmentPrepData,
prepare_app_environments, prepare_app_environments,
prepare_context_environments prepare_context_environments
) )
from ayon_core.pipeline import Anatomy
class GlobalHostDataHook(PreLaunchHook): class GlobalHostDataHook(PreLaunchHook):
@ -67,9 +70,12 @@ class GlobalHostDataHook(PreLaunchHook):
self.data["project_entity"] = project_entity self.data["project_entity"] = project_entity
# Anatomy # Anatomy
self.data["anatomy"] = Anatomy( try:
project_name, project_entity=project_entity self.data["anatomy"] = Anatomy(
) project_name, project_entity=project_entity
)
except RootMissingEnv as exc:
raise ApplicationLaunchFailed(str(exc))
folder_path = self.data.get("folder_path") folder_path = self.data.get("folder_path")
if not folder_path: if not folder_path:

View file

@ -1,5 +1,6 @@
from .exceptions import ( from .exceptions import (
ProjectNotSet, ProjectNotSet,
RootMissingEnv,
RootCombinationError, RootCombinationError,
TemplateMissingKey, TemplateMissingKey,
AnatomyTemplateUnsolved, AnatomyTemplateUnsolved,
@ -9,6 +10,7 @@ from .anatomy import Anatomy
__all__ = ( __all__ = (
"ProjectNotSet", "ProjectNotSet",
"RootMissingEnv",
"RootCombinationError", "RootCombinationError",
"TemplateMissingKey", "TemplateMissingKey",
"AnatomyTemplateUnsolved", "AnatomyTemplateUnsolved",

View file

@ -5,6 +5,11 @@ class ProjectNotSet(Exception):
"""Exception raised when is created Anatomy without project name.""" """Exception raised when is created Anatomy without project name."""
class RootMissingEnv(KeyError):
"""Raised when root requires environment variables which is not filled."""
pass
class RootCombinationError(Exception): class RootCombinationError(Exception):
"""This exception is raised when templates has combined root types.""" """This exception is raised when templates has combined root types."""

View file

@ -2,9 +2,11 @@ import os
import platform import platform
import numbers import numbers
from ayon_core.lib import Logger from ayon_core.lib import Logger, StringTemplate
from ayon_core.lib.path_templates import FormatObject from ayon_core.lib.path_templates import FormatObject
from .exceptions import RootMissingEnv
class RootItem(FormatObject): class RootItem(FormatObject):
"""Represents one item or roots. """Represents one item or roots.
@ -21,18 +23,36 @@ class RootItem(FormatObject):
multi root setup otherwise None value is expected. multi root setup otherwise None value is expected.
""" """
def __init__(self, parent, root_raw_data, name): def __init__(self, parent, root_raw_data, name):
super(RootItem, self).__init__() super().__init__()
self._log = None self._log = None
lowered_platform_keys = {} lowered_platform_keys = {
for key, value in root_raw_data.items(): key.lower(): value
lowered_platform_keys[key.lower()] = value for key, value in root_raw_data.items()
}
self.raw_data = lowered_platform_keys self.raw_data = lowered_platform_keys
self.cleaned_data = self._clean_roots(lowered_platform_keys) self.cleaned_data = self._clean_roots(lowered_platform_keys)
self.name = name self.name = name
self.parent = parent self.parent = parent
self.available_platforms = set(lowered_platform_keys.keys()) self.available_platforms = set(lowered_platform_keys.keys())
self.value = lowered_platform_keys.get(platform.system().lower())
current_platform = platform.system().lower()
# WARNING: Using environment variables in roots is not considered
# as production safe. Some features may not work as expected, for
# example USD resolver or site sync.
try:
self.value = lowered_platform_keys[current_platform].format_map(
os.environ
)
except KeyError:
result = StringTemplate(self.value).format(os.environ.copy())
is_are = "is" if len(result.missing_keys) == 1 else "are"
missing_keys = ", ".join(result.missing_keys)
raise RootMissingEnv(
f"Root \"{name}\" requires environment variable/s"
f" {missing_keys} which {is_are} not available."
)
self.clean_value = self._clean_root(self.value) self.clean_value = self._clean_root(self.value)
def __format__(self, *args, **kwargs): def __format__(self, *args, **kwargs):
@ -105,10 +125,10 @@ class RootItem(FormatObject):
def _clean_roots(self, raw_data): def _clean_roots(self, raw_data):
"""Clean all values of raw root item values.""" """Clean all values of raw root item values."""
cleaned = {} return {
for key, value in raw_data.items(): key: self._clean_root(value)
cleaned[key] = self._clean_root(value) for key, value in raw_data.items()
return cleaned }
def path_remapper(self, path, dst_platform=None, src_platform=None): def path_remapper(self, path, dst_platform=None, src_platform=None):
"""Remap path for specific platform. """Remap path for specific platform.