Merge pull request #2967 from pypeclub/enhancement/OP-2903_Hero-versions-custom-templates

Hero versions: Use custom templates
This commit is contained in:
Jakub Trllo 2022-03-31 11:46:29 +02:00 committed by GitHub
commit bda6ae7236
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 171 additions and 110 deletions

View file

@ -7,8 +7,12 @@ import shutil
from bson.objectid import ObjectId
from pymongo import InsertOne, ReplaceOne
import pyblish.api
from avalon import api, io, schema
from openpype.lib import create_hard_link
from openpype.lib import (
create_hard_link,
filter_profiles
)
class IntegrateHeroVersion(pyblish.api.InstancePlugin):
@ -17,7 +21,9 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
order = pyblish.api.IntegratorOrder + 0.1
optional = True
active = True
# Families are modified using settings
families = [
"model",
"rig",
@ -33,11 +39,13 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
"project", "asset", "task", "subset", "representation",
"family", "hierarchy", "task", "username"
]
# TODO add family filtering
# QUESTION/TODO this process should happen on server if crashed due to
# permissions error on files (files were used or user didn't have perms)
# *but all other plugins must be sucessfully completed
template_name_profiles = []
_default_template_name = "hero"
def process(self, instance):
self.log.debug(
"--- Integration of Hero version for subset `{}` begins.".format(
@ -51,27 +59,35 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
)
return
project_name = api.Session["AVALON_PROJECT"]
template_key = self._get_template_key(instance)
# TODO raise error if Hero not set?
anatomy = instance.context.data["anatomy"]
if "hero" not in anatomy.templates:
self.log.warning("!!! Anatomy does not have set `hero` key!")
return
if "path" not in anatomy.templates["hero"]:
project_name = api.Session["AVALON_PROJECT"]
if template_key not in anatomy.templates:
self.log.warning((
"!!! There is not set `path` template in `hero` anatomy"
" for project \"{}\"."
).format(project_name))
"!!! Anatomy of project \"{}\" does not have set"
" \"{}\" template key!"
).format(project_name, template_key))
return
hero_template = anatomy.templates["hero"]["path"]
if "path" not in anatomy.templates[template_key]:
self.log.warning((
"!!! There is not set \"path\" template in \"{}\" anatomy"
" for project \"{}\"."
).format(template_key, project_name))
return
hero_template = anatomy.templates[template_key]["path"]
self.log.debug("`hero` template check was successful. `{}`".format(
hero_template
))
hero_publish_dir = self.get_publish_dir(instance)
self.integrate_instance(instance, template_key, hero_template)
def integrate_instance(self, instance, template_key, hero_template):
anatomy = instance.context.data["anatomy"]
published_repres = instance.data["published_representations"]
hero_publish_dir = self.get_publish_dir(instance, template_key)
src_version_entity = instance.data.get("versionEntity")
filtered_repre_ids = []
@ -271,12 +287,12 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
continue
# Prepare anatomy data
anatomy_data = repre_info["anatomy_data"]
anatomy_data = copy.deepcopy(repre_info["anatomy_data"])
anatomy_data.pop("version", None)
# Get filled path to repre context
anatomy_filled = anatomy.format(anatomy_data)
template_filled = anatomy_filled["hero"]["path"]
template_filled = anatomy_filled[template_key]["path"]
repre_data = {
"path": str(template_filled),
@ -308,11 +324,11 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
collections, remainders = clique.assemble(published_files)
if remainders or not collections or len(collections) > 1:
raise Exception((
"Integrity error. Files of published representation "
"is combination of frame collections and single files."
"Collections: `{}` Single files: `{}`"
).format(str(collections),
str(remainders)))
"Integrity error. Files of published"
" representation is combination of frame"
" collections and single files. Collections:"
" `{}` Single files: `{}`"
).format(str(collections), str(remainders)))
src_col = collections[0]
@ -320,13 +336,10 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
frame_splitter = "_-_FRAME_SPLIT_-_"
anatomy_data["frame"] = frame_splitter
_anatomy_filled = anatomy.format(anatomy_data)
_template_filled = _anatomy_filled["hero"]["path"]
_template_filled = _anatomy_filled[template_key]["path"]
head, tail = _template_filled.split(frame_splitter)
padding = int(
anatomy.templates["render"].get(
"frame_padding",
anatomy.templates["render"].get("padding")
)
anatomy.templates[template_key]["frame_padding"]
)
dst_col = clique.Collection(
@ -444,6 +457,8 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
backup_hero_publish_dir is not None and
os.path.exists(backup_hero_publish_dir)
):
if os.path.exists(hero_publish_dir):
shutil.rmtree(hero_publish_dir)
os.rename(backup_hero_publish_dir, hero_publish_dir)
self.log.error((
"!!! Creating of hero version failed."
@ -466,13 +481,13 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
files.append(_path)
return files
def get_publish_dir(self, instance):
def get_publish_dir(self, instance, template_key):
anatomy = instance.context.data["anatomy"]
template_data = copy.deepcopy(instance.data["anatomyData"])
if "folder" in anatomy.templates["hero"]:
if "folder" in anatomy.templates[template_key]:
anatomy_filled = anatomy.format(template_data)
publish_folder = anatomy_filled["hero"]["folder"]
publish_folder = anatomy_filled[template_key]["folder"]
else:
# This is for cases of Deprecated anatomy without `folder`
# TODO remove when all clients have solved this issue
@ -489,7 +504,7 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
" key underneath `publish` (in global of for project `{}`)."
).format(project_name))
file_path = anatomy_filled["hero"]["path"]
file_path = anatomy_filled[template_key]["path"]
# Directory
publish_folder = os.path.dirname(file_path)
@ -499,6 +514,38 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
return publish_folder
def _get_template_key(self, instance):
anatomy_data = instance.data["anatomyData"]
task_data = anatomy_data.get("task") or {}
task_name = task_data.get("name")
task_type = task_data.get("type")
host_name = instance.context.data["hostName"]
# TODO raise error if Hero not set?
family = self.main_family_from_instance(instance)
key_values = {
"families": family,
"task_names": task_name,
"task_types": task_type,
"hosts": host_name
}
profile = filter_profiles(
self.template_name_profiles,
key_values,
logger=self.log
)
if profile:
template_name = profile["template_name"]
else:
template_name = self._default_template_name
return template_name
def main_family_from_instance(self, instance):
"""Returns main family of entered instance."""
family = instance.data.get("family")
if not family:
family = instance.data["families"][0]
return family
def copy_file(self, src_path, dst_path):
# TODO check drives if are the same to check if cas hardlink
dirname = os.path.dirname(dst_path)
@ -564,22 +611,16 @@ class IntegrateHeroVersion(pyblish.api.InstancePlugin):
src_file (string) - original file path
dst_file (string) - hero file path
"""
_, rootless = anatomy.find_root_template_from_path(
dst_file
)
_, rtls_src = anatomy.find_root_template_from_path(
src_file
)
_, rootless = anatomy.find_root_template_from_path(dst_file)
_, rtls_src = anatomy.find_root_template_from_path(src_file)
return path.replace(rtls_src, rootless)
def _update_hash(self, hash, src_file_name, dst_file):
"""
Updates hash value with proper hero name
"""
src_file_name = self._get_name_without_ext(
src_file_name)
hero_file_name = self._get_name_without_ext(
dst_file)
src_file_name = self._get_name_without_ext(src_file_name)
hero_file_name = self._get_name_without_ext(dst_file)
return hash.replace(src_file_name, hero_file_name)
def _get_name_without_ext(self, value):

View file

@ -33,20 +33,6 @@
"enabled": false,
"profiles": []
},
"IntegrateHeroVersion": {
"enabled": true,
"optional": true,
"families": [
"model",
"rig",
"look",
"pointcache",
"animation",
"setdress",
"layout",
"mayaScene"
]
},
"ExtractJpegEXR": {
"enabled": true,
"ffmpeg_args": {
@ -204,6 +190,22 @@
}
]
},
"IntegrateHeroVersion": {
"enabled": true,
"optional": true,
"active": true,
"families": [
"model",
"rig",
"look",
"pointcache",
"animation",
"setdress",
"layout",
"mayaScene"
],
"template_name_profiles": []
},
"CleanUp": {
"paterns": [],
"remove_temp_renders": false

View file

@ -122,32 +122,6 @@
}
]
},
{
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"key": "IntegrateHeroVersion",
"label": "IntegrateHeroVersion",
"is_group": true,
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "boolean",
"key": "optional",
"label": "Optional"
},
{
"key": "families",
"label": "Families",
"type": "list",
"object_type": "text"
}
]
},
{
"type": "dict",
"collapsible": true,
@ -652,6 +626,80 @@
}
]
},
{
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"key": "IntegrateHeroVersion",
"label": "IntegrateHeroVersion",
"is_group": true,
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "boolean",
"key": "optional",
"label": "Optional"
},
{
"type": "boolean",
"key": "active",
"label": "Active"
},
{
"key": "families",
"label": "Families",
"type": "list",
"object_type": "text"
},
{
"type": "list",
"key": "template_name_profiles",
"label": "Template name profiles",
"use_label_wrap": true,
"object_type": {
"type": "dict",
"children": [
{
"key": "families",
"label": "Families",
"type": "list",
"object_type": "text"
},
{
"type": "hosts-enum",
"key": "hosts",
"label": "Hosts",
"multiselection": true
},
{
"key": "task_types",
"label": "Task types",
"type": "task-types-enum"
},
{
"key": "task_names",
"label": "Task names",
"type": "list",
"object_type": "text"
},
{
"type": "separator"
},
{
"type": "text",
"key": "template_name",
"label": "Template name",
"tooltip": "Name of template from Anatomy templates"
}
]
}
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -1,30 +0,0 @@
[
{
"type": "list-strict",
"key": "{name}",
"label": "{label}",
"object_types": [
{
"label": "Red",
"type": "number",
"minimum": 0,
"maximum": 1,
"decimal": 3
},
{
"label": "Green",
"type": "number",
"minimum": 0,
"maximum": 1,
"decimal": 3
},
{
"label": "Blue",
"type": "number",
"minimum": 0,
"maximum": 1,
"decimal": 3
}
]
}
]