Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore: Applications settings #16

Merged
merged 40 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
52f303b
removed use python 2
iLLiCiTiT Jul 22, 2024
203c0b0
removed 'use_python_2' from settings
iLLiCiTiT Jul 22, 2024
8a55436
don't use 'AppVariantWithPython' for additional applications
iLLiCiTiT Jul 22, 2024
77f072f
remove mayapy from default settings
iLLiCiTiT Jul 22, 2024
d499f67
don't update attributes anymore
iLLiCiTiT Jul 22, 2024
b6ff7a6
labels and icons of default applications are not defined by settings
iLLiCiTiT Jul 22, 2024
eb4a002
load default values only once
iLLiCiTiT Jul 22, 2024
b6832e7
added enumerators for applications and tools
iLLiCiTiT Jul 22, 2024
5d03443
Merge branch 'develop' into enhancement/AY-1301_Applications-per-task…
iLLiCiTiT Aug 5, 2024
1005b5f
handle backwards compatibility
iLLiCiTiT Aug 5, 2024
5667eb5
fix backwards compatibility
iLLiCiTiT Aug 5, 2024
3c458b1
use settings instead of attributes
iLLiCiTiT Aug 5, 2024
2190bd1
changed order of settings
iLLiCiTiT Aug 5, 2024
6142f5e
added option to switch between new and old sources
iLLiCiTiT Aug 5, 2024
f60a9ba
keep attributes login in addon
iLLiCiTiT Aug 5, 2024
dca4033
add missing imports
iLLiCiTiT Aug 5, 2024
4755413
kept _backwards.py in the codebase unused for now
iLLiCiTiT Aug 5, 2024
9297b57
client codebase is using the settings
iLLiCiTiT Aug 5, 2024
f266eba
use json module to reformat default settings
iLLiCiTiT Aug 5, 2024
358a2e1
fix used variable
iLLiCiTiT Aug 5, 2024
e3e4cc3
added some comments
iLLiCiTiT Aug 5, 2024
e612605
remove 'icons_enum' for additional apps
iLLiCiTiT Aug 5, 2024
8d70552
fix tools enum
iLLiCiTiT Aug 5, 2024
51d2621
remove line section
iLLiCiTiT Aug 5, 2024
ffeb07b
added 'applications_enum' to tools filtering
iLLiCiTiT Aug 5, 2024
bc9d004
fix addon has attribute method
iLLiCiTiT Aug 5, 2024
799291f
reduce milestone version to major and minor
iLLiCiTiT Aug 5, 2024
48f2e87
reverse version check
iLLiCiTiT Aug 5, 2024
5202561
add constant for labels to applications addon
iLLiCiTiT Aug 5, 2024
a0be6a7
remove company from app group labels
iLLiCiTiT Aug 6, 2024
b88a473
added allow type so it is possible to allow all applications by default
iLLiCiTiT Aug 6, 2024
621e46b
added task path regex to settings
iLLiCiTiT Aug 6, 2024
fc1ab8a
remove folder types
iLLiCiTiT Aug 12, 2024
11e41c7
applications and tools settings can be enabled separatelly
iLLiCiTiT Aug 12, 2024
a9560c7
change settings usage
iLLiCiTiT Aug 12, 2024
03c3bfe
removed descriptions from profiles
iLLiCiTiT Aug 12, 2024
cbd385d
replace task paths with folder paths and task names filter
iLLiCiTiT Aug 15, 2024
0b5c9ba
disable attributes usage by default
iLLiCiTiT Aug 15, 2024
39781c6
change milestone to 1.0.0
iLLiCiTiT Aug 15, 2024
b7a1d92
bump version to '1.0.0-dev.1'
iLLiCiTiT Aug 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 10 additions & 23 deletions client/ayon_applications/action.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import copy

import ayon_api

from ayon_core import resources
from ayon_core.lib import Logger, NestedCacheItem
from ayon_core.settings import get_studio_settings, get_project_settings
Expand All @@ -11,6 +9,7 @@
ApplicationExecutableNotFound,
ApplicationLaunchFailed,
)
from .utils import get_applications_for_context


class ApplicationAction(LauncherAction):
Expand Down Expand Up @@ -68,23 +67,6 @@ def _app_get_project_settings(cls, selection):
cache.update_data(settings)
return copy.deepcopy(cache.get_data())

@classmethod
def _app_get_project_entity(cls, selection):
project_name = selection.project_name
if project_name in ApplicationAction.project_entities:
return ApplicationAction.project_entities[project_name]

if hasattr(selection, "get_project_settings"):
return selection.get_project_entity()

cache = ApplicationAction.project_entities_cache[project_name]
if not cache.is_valid:
project_entity = None
if project_name:
project_entity = ayon_api.get_project(project_name)
cache.update_data(project_entity)
return copy.deepcopy(cache.get_data())

@property
def log(self):
if self._log is None:
Expand All @@ -95,12 +77,17 @@ def is_compatible(self, selection):
if not selection.is_task_selected:
return False

project_entity = self._app_get_project_entity(selection)
apps = project_entity["attrib"].get("applications")
if not apps or self.application.full_name not in apps:
project_settings = self._app_get_project_settings(selection)
apps = get_applications_for_context(
selection.project_name,
selection.get_folder_entity(),
selection.get_task_entity(),
project_settings=project_settings,
project_entity=selection.get_project_entity(),
)
if self.application.full_name not in apps:
return False

project_settings = self._app_get_project_settings(selection)
only_available = project_settings["applications"]["only_available"]
if only_available and not self.application.find_executable():
return False
Expand Down
64 changes: 62 additions & 2 deletions client/ayon_applications/defs.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,75 @@ class ApplicationGroup:
data (dict): Group defying data loaded from settings.
manager (ApplicationManager): Manager that created the group.
"""
icons_by_group = {
"adsk_3dsmax": "3dsmax.png",
"aftereffects": "aftereffects.png",
"blender": "blender.png",
"celaction": "celaction.png",
"equalizer": "3de4.png",
"flame": "flame.png",
"fusion": "fusion.png",
"harmony": "harmony.png",
"hiero": "hiero.png",
"houdini": "houdini.png",
"maya": "maya.png",
"motionbuilder": "motionbuilder.png",
"nuke": "nuke.png",
"nukeassist": "nuke.png",
"nukestudio": "nukestudio.png",
"nukex": "nukex.png",
"openrv": "openrv.png",
"photoshop": "photoshop.png",
"resolve": "resolve.png",
"substancepainter": "substancepainter.png",
"tvpaint": "tvpaint.png",
"unreal": "ue4.png",
"wrap": "wrap.png",
"zbrush": "zbrush.png",
}
labels_by_group = {
"adsk_3dsmax": "3ds Max",
"aftereffects": "After Effects",
"blender": "Blender",
"celaction": "Celaction 2D",
"equalizer": "3DEqualizer",
"flame": "Flame",
"fusion": "Fusion",
"harmony": "Harmony",
"hiero": "Hiero",
"houdini": "Houdini",
"maya": "Maya",
"motionbuilder": "Motion Builder",
"nuke": "Nuke",
"nukeassist": "Nuke Assist",
"nukestudio": "Nuke Studio",
"nukex": "Nuke X",
"openrv": "OpenRV",
"photoshop": "Photoshop",
"resolve": "Resolve",
"substancepainter": "Substance Painter",
"tvpaint": "TVPaint",
"unreal": "Unreal Editor",
"wrap": "Wrap",
"zbrush": "Zbrush",
}

def __init__(self, name, data, manager):
icon = self.icons_by_group.get(name)
if not icon:
icon = data.get("icon")

label = self.labels_by_group.get(name)
if not label:
label = data.get("label")

self.name = name
self.manager = manager
self._data = data

self.enabled = data["enabled"]
self.label = data["label"] or None
self.icon = data["icon"] or None
self.label = label
self.icon = icon
env = {}
try:
env = json.loads(data["environment"])
Expand Down
179 changes: 154 additions & 25 deletions client/ayon_applications/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@

import six
import acre
import ayon_api

from ayon_core import AYON_CORE_ROOT
from ayon_core.settings import get_project_settings
from ayon_core.lib import Logger, get_ayon_username
from ayon_core.lib import Logger, get_ayon_username, filter_profiles
from ayon_core.addon import AddonsManager
from ayon_core.pipeline.template_data import get_template_data
from ayon_core.pipeline.workfile import (
Expand Down Expand Up @@ -235,6 +236,138 @@ def _add_python_version_paths(app, env, logger, addons_manager):
env["PYTHONPATH"] = os.pathsep.join(python_paths)


def _get_app_full_names_from_settings(applications_settings):
"""Get full names of applications from settings.

Args:
applications_settings (dict): Applications settings.

Returns:
List[str]: Full names of applications.

"""
apps = copy.deepcopy(applications_settings["applications"])
additional_apps = apps.pop("additional_apps")

full_names = []
for group_name, group_info in apps.items():
for variant in group_info["variants"]:
variant_name = variant["name"]
full_names.append(f"{group_name}/{variant_name}")

for additional_app in additional_apps:
group_name = additional_app["name"]
for variant in additional_app["variants"]:
variant_name = variant["name"]
full_names.append(f"{group_name}/{variant_name}")

return full_names


def get_applications_for_context(
project_name,
folder_entity,
task_entity,
project_settings=None,
project_entity=None,
):
"""Get applications for context based on project settings.

Args:
project_name (str): Name of project.
folder_entity (dict): Folder entity.
task_entity (dict): Task entity.
project_settings (Optional[dict]): Project settings.
project_entity (Optional[dict]): Project entity.

Returns:
List[str]: List of applications that can be used in given context.

"""
if project_settings is None:
project_settings = get_project_settings(project_name)
apps_settings = project_settings["applications"]

# Use attributes to get available applications
# - this is older source of the information, will be deprecated in future
project_applications = apps_settings["project_applications"]
if not project_applications["enabled"]:
if project_entity is None:
project_entity = ayon_api.get_project(project_name)
apps = project_entity["attrib"].get("applications")
return apps or []

task_type = None
if task_entity:
task_type = task_entity["taskType"]

profile = filter_profiles(
project_applications["profiles"],
{"task_types": task_type}
)
if profile:
if profile["allow_type"] == "applications":
return profile["applications"]
return _get_app_full_names_from_settings(apps_settings)
return []


def get_tools_for_context(
project_name,
folder_entity,
task_entity,
project_settings=None,
):
"""Get tools for context based on project settings.

Args:
project_name (str): Name of project.
folder_entity (dict): Folder entity.
task_entity (dict): Task entity.
project_settings (Optional[dict]): Project settings.

Returns:
List[str]: List of applications that can be used in given context.

"""
if project_settings is None:
project_settings = get_project_settings(project_name)
apps_settings = project_settings["applications"]

project_tools = apps_settings["project_tools"]
# Use attributes to get available tools
# - this is older source of the information, will be deprecated in future
if not project_tools["enabled"]:
tools = None
if task_entity:
tools = task_entity["attrib"].get("tools")

if tools is None and folder_entity:
tools = folder_entity["attrib"].get("tools")

return tools or []

folder_path = task_type = task_name = None
if folder_entity:
folder_path = folder_entity["path"]
if task_entity:
task_type = task_entity["taskType"]
task_name = task_entity["name"]

profile = filter_profiles(
project_tools["profiles"],
{
"folder_paths": folder_path,
"task_types": task_type,
"task_names": task_name,
},
keys_order=["folder_paths", "task_names", "task_types"]
)
if profile:
return profile["tools"]
return []


def prepare_app_environments(
data, env_group=None, implementation_envs=True, addons_manager=None
):
Expand Down Expand Up @@ -281,33 +414,29 @@ def prepare_app_environments(
app.environment
]

task_entity = data.get("task_entity")
folder_entity = data.get("folder_entity")
tools = get_tools_for_context(
data.get("project_name"),
data.get("folder_entity"),
data.get("task_entity"),
)

# Add tools environments
groups_by_name = {}
tool_by_group_name = collections.defaultdict(dict)
tools = None
if task_entity:
tools = task_entity["attrib"].get("tools")

if tools is None and folder_entity:
tools = folder_entity["attrib"].get("tools")

if tools:
for key in tools:
tool = app.manager.tools.get(key)
if not tool or not tool.is_valid_for_app(app):
continue
groups_by_name[tool.group.name] = tool.group
tool_by_group_name[tool.group.name][tool.name] = tool

for group_name in sorted(groups_by_name.keys()):
group = groups_by_name[group_name]
environments.append(group.environment)
for tool_name in sorted(tool_by_group_name[group_name].keys()):
tool = tool_by_group_name[group_name][tool_name]
environments.append(tool.environment)
app_and_tool_labels.append(tool.full_name)
for key in tools:
tool = app.manager.tools.get(key)
if not tool or not tool.is_valid_for_app(app):
continue
groups_by_name[tool.group.name] = tool.group
tool_by_group_name[tool.group.name][tool.name] = tool

for group_name in sorted(groups_by_name.keys()):
group = groups_by_name[group_name]
environments.append(group.environment)
for tool_name in sorted(tool_by_group_name[group_name].keys()):
tool = tool_by_group_name[group_name][tool_name]
environments.append(tool.environment)
app_and_tool_labels.append(tool.full_name)

log.debug(
"Will add environments for apps and tools: {}".format(
Expand Down
2 changes: 1 addition & 1 deletion client/ayon_applications/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
"""Package declaring AYON addon 'applications' version."""
__version__ = "0.2.6-dev.1"
__version__ = "1.0.0-dev.1"
2 changes: 1 addition & 1 deletion package.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "applications"
title = "Applications"
version = "0.2.6-dev.1"
version = "1.0.0-dev.1"

client_dir = "ayon_applications"

Expand Down
Loading