mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
refactored publish plugins
This commit is contained in:
parent
ed730c02e6
commit
e0ecc72e49
9 changed files with 225 additions and 67 deletions
|
|
@ -1,10 +1,13 @@
|
|||
# absolute_import is needed to counter the `module has no cmds error` in Maya
|
||||
from __future__ import absolute_import
|
||||
|
||||
import pyblish.api
|
||||
import os
|
||||
import uuid
|
||||
|
||||
from maya import cmds
|
||||
|
||||
import pyblish.api
|
||||
|
||||
|
||||
def get_errored_instances_from_context(context):
|
||||
|
||||
|
|
@ -34,7 +37,7 @@ def get_errored_plugins_from_data(context):
|
|||
plugins = list()
|
||||
results = context.data.get("results", [])
|
||||
for result in results:
|
||||
if result["success"] == True:
|
||||
if result["success"] is True:
|
||||
continue
|
||||
plugins.append(result["plugin"])
|
||||
|
||||
|
|
@ -150,8 +153,6 @@ class GenerateUUIDsOnInvalidAction(pyblish.api.Action):
|
|||
icon = "wrench" # Icon from Awesome Icon
|
||||
|
||||
def process(self, context, plugin):
|
||||
import cbra.lib
|
||||
import cbra.utils.maya.node_uuid as id_utils
|
||||
|
||||
self.log.info("Finding bad nodes..")
|
||||
|
||||
|
|
@ -182,15 +183,73 @@ class GenerateUUIDsOnInvalidAction(pyblish.api.Action):
|
|||
|
||||
# Parse context from current file
|
||||
self.log.info("Parsing current context..")
|
||||
try:
|
||||
current_file = context.data['currentFile']
|
||||
context = cbra.lib.parse_context(current_file)
|
||||
except RuntimeError, e:
|
||||
self.log.error("Can't generate UUIDs because scene isn't "
|
||||
"in new-style pipeline: ".format(current_file))
|
||||
raise e
|
||||
print(">>> DEBUG CONTEXT :", context)
|
||||
print(">>> DEBUG CONTEXT DATA:", context.data)
|
||||
|
||||
# Generate and add the ids to the nodes
|
||||
ids = id_utils.generate_ids(context, invalid)
|
||||
id_utils.add_ids(ids)
|
||||
# # Generate and add the ids to the nodes
|
||||
node_ids = self.generate_ids(context, invalid)
|
||||
self.apply_ids(node_ids)
|
||||
self.log.info("Generated ids on nodes: {0}".format(invalid))
|
||||
|
||||
def get_context(self, instance=None):
|
||||
|
||||
PROJECT = os.environ["AVALON_PROJECT"]
|
||||
ASSET = instance.data.get("asset") or os.environ["AVALON_ASSET"]
|
||||
SILO = os.environ["AVALON_SILO"]
|
||||
LOCATION = os.getenv("AVALON_LOCATION")
|
||||
|
||||
return {"project": PROJECT,
|
||||
"asset": ASSET,
|
||||
"silo": SILO,
|
||||
"location": LOCATION}
|
||||
|
||||
def generate_ids(self, context, nodes):
|
||||
"""Generate cb UUIDs for nodes.
|
||||
|
||||
The identifiers are formatted like:
|
||||
assets:character/test:bluey:46D221D9-4150-8E49-6B17-43B04BFC26B6
|
||||
|
||||
This is a concatenation of:
|
||||
- entity (shots or assets)
|
||||
- folders (parent hierarchy)
|
||||
- asset (the name of the asset)
|
||||
- uuid (unique id for node in the scene)
|
||||
|
||||
Raises:
|
||||
RuntimeError: When context can't be parsed of the current asset
|
||||
|
||||
Returns:
|
||||
dict: node, uuid dictionary
|
||||
|
||||
"""
|
||||
|
||||
# Make a copy of the context
|
||||
data = context.copy()
|
||||
|
||||
# Define folders
|
||||
|
||||
node_ids = dict()
|
||||
for node in nodes:
|
||||
# Generate a unique ID per node
|
||||
data['uuid'] = uuid.uuid4()
|
||||
unique_id = "{asset}:{item}:{uuid}".format(**data)
|
||||
node_ids[node] = unique_id
|
||||
|
||||
return node_ids
|
||||
|
||||
def apply_ids(self, node_ids):
|
||||
"""Apply the created unique IDs to the node
|
||||
Args:
|
||||
node_ids (dict): each node with a unique id
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
attribute = "mbId"
|
||||
for node, id in node_ids.items():
|
||||
# check if node has attribute
|
||||
if not cmds.attributeQuery(attribute, node=node, exists=True):
|
||||
cmds.addAttr(node, longName=attribute, dataType="string")
|
||||
|
||||
cmds.setAttr("{}.{}".format(node, attribute), id)
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ def extract_alembic(file,
|
|||
for key, value in options.items():
|
||||
if isinstance(value, (list, tuple)):
|
||||
for entry in value:
|
||||
job_args.append("-{0} {1}".format(key=key, value=entry))
|
||||
job_args.append("-{} {}".format(key, entry))
|
||||
elif isinstance(value, bool):
|
||||
job_args.append("-{0}".format(key))
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ def get_look_attrs(node):
|
|||
valid = [attr for attr in attrs if attr in SHAPE_ATTRS]
|
||||
result.extend(valid)
|
||||
|
||||
if "cbId" in result:
|
||||
result.remove("cbId")
|
||||
if "mbID" in result:
|
||||
result.remove("mbID")
|
||||
|
||||
return result
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
|
||||
# Discover related object sets
|
||||
self.log.info("Gathering sets..")
|
||||
self.gather_sets(instance)
|
||||
sets = self.gather_sets(instance)
|
||||
|
||||
# Lookup with absolute names (from root namespace)
|
||||
instance_lookup = set([str(x) for x in cmds.ls(instance,
|
||||
|
|
@ -95,9 +95,7 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
absoluteName=True)])
|
||||
|
||||
self.log.info("Gathering set relations..")
|
||||
sets = self.gather_sets(instance)
|
||||
for objset in sets:
|
||||
|
||||
self.log.debug("From %s.." % objset)
|
||||
content = cmds.sets(objset, query=True)
|
||||
objset_members = sets[objset]["members"]
|
||||
|
|
@ -108,16 +106,14 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
verbose)
|
||||
if not member_data:
|
||||
continue
|
||||
|
||||
sets[objset]["members"].append(member_data)
|
||||
|
||||
# Remove sets that didn't have any members assigned in the end
|
||||
sets = self.clean_sets(sets)
|
||||
# Member attributes (shapes + transforms)
|
||||
sets = self.remove_sets_without_members(sets)
|
||||
|
||||
self.log.info("Gathering attribute changes to instance members..")
|
||||
|
||||
attributes = self.collect_attributes_changes(instance)
|
||||
attributes = self.collect_attributes_changed(instance)
|
||||
looksets = cmds.ls(sets.keys(), absoluteName=True, long=True)
|
||||
|
||||
# Store data on the instance
|
||||
|
|
@ -133,41 +129,75 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
self.log.info("Collected look for %s" % instance)
|
||||
|
||||
def gather_sets(self, instance):
|
||||
"""Gather all objectSets which are of importance for publishing
|
||||
|
||||
It checks if all nodes in the instance are related to any objectSet
|
||||
which need to be
|
||||
|
||||
Args:
|
||||
instance (list): all nodes to be published
|
||||
|
||||
Returns:
|
||||
dict
|
||||
"""
|
||||
|
||||
# Get view sets (so we can ignore those sets later)
|
||||
sets = dict()
|
||||
view_sets = set()
|
||||
model_panels = cmds.getPanel(type="modelPanel")
|
||||
for panel in model_panels:
|
||||
for panel in cmds.getPanel(type="modelPanel"):
|
||||
view_set = cmds.modelEditor(panel, query=True, viewObjects=True)
|
||||
if view_set:
|
||||
view_sets.add(view_set)
|
||||
|
||||
for node in instance:
|
||||
node_sets = self.filter_sets(node, view_sets)
|
||||
if not node_sets:
|
||||
related_sets = self.get_related_sets(node, view_sets)
|
||||
if not related_sets:
|
||||
continue
|
||||
|
||||
for objset in node_sets:
|
||||
for objset in related_sets:
|
||||
if objset in sets:
|
||||
continue
|
||||
unique_id = cmds.getAttr("%s.mbID" % objset)
|
||||
sets[objset] = {"name": objset,
|
||||
"uuid": id_utils.get_id(objset),
|
||||
"uuid": unique_id,
|
||||
"members": list()}
|
||||
return sets
|
||||
|
||||
def filter_sets(self, node, view_sets):
|
||||
def get_related_sets(self, node, view_sets):
|
||||
"""Get the sets which do not belong to any specific group
|
||||
|
||||
node_sets = cmds.listSets(object=node, extendToShape=False) or []
|
||||
if not node_sets:
|
||||
return
|
||||
Filters out based on:
|
||||
- id attribute is NOT `pyblish.avalon.container`
|
||||
- shapes and deformer shapes (alembic creates meshShapeDeformed)
|
||||
- set name ends with any from a predefined list
|
||||
- set in not in viewport set (isolate selected for example)
|
||||
|
||||
Args:
|
||||
node (str): name of the current not to check
|
||||
"""
|
||||
|
||||
ignored = ["pyblish.avalon.instance", "pyblish.avalon.container"]
|
||||
|
||||
related_sets = cmds.listSets(object=node, extendToShape=False)
|
||||
if not related_sets:
|
||||
return []
|
||||
|
||||
# Ignore `avalon.container`
|
||||
sets = [s for s in related_sets if
|
||||
not cmds.attributeQuery("id", node=s, exists=True) or
|
||||
not cmds.getAttr("%s.id" % s) in ignored]
|
||||
|
||||
# Exclude deformer sets
|
||||
# Autodesk documentation on listSets command:
|
||||
# type(uint) : Returns all sets in the scene of the given
|
||||
# >>> type:
|
||||
# >>> 1 - all rendering sets
|
||||
# >>> 2 - all deformer sets
|
||||
deformer_sets = cmds.listSets(object=node,
|
||||
extendToShape=False,
|
||||
type=2) or []
|
||||
deformer_sets = set(deformer_sets) # optimize lookup
|
||||
sets = [s for s in node_sets if s not in deformer_sets]
|
||||
sets = [s for s in sets if s not in deformer_sets]
|
||||
|
||||
# Ignore specifically named sets
|
||||
sets = [s for s in sets if not any(s.endswith(x) for x in self.IGNORE)]
|
||||
|
|
@ -176,16 +206,24 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
# viewports)
|
||||
sets = [s for s in sets if s not in view_sets]
|
||||
|
||||
self.log.info("Found sets {0} for {1}".format(node_sets, node))
|
||||
self.log.info("Found sets %s for %s" % (related_sets, node))
|
||||
|
||||
return sets
|
||||
|
||||
def clean_sets(self, sets):
|
||||
def remove_sets_without_members(self, sets):
|
||||
"""Remove any set which does not have any members
|
||||
|
||||
Args:
|
||||
sets (dict): collection if sets with data as value
|
||||
|
||||
Returns:
|
||||
dict
|
||||
"""
|
||||
|
||||
for objset, data in sets.items():
|
||||
if not data['members']:
|
||||
self.log.debug("Removing redundant set "
|
||||
"information: %s" % objset)
|
||||
self.log.debug("Removing redundant set information: "
|
||||
"%s" % objset)
|
||||
sets.pop(objset)
|
||||
|
||||
return sets
|
||||
|
|
@ -218,7 +256,8 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
if verbose:
|
||||
self.log.debug("Such as %s.." % member)
|
||||
|
||||
member_data = {"name": node, "uuid": id_utils.get_id(node)}
|
||||
member_data = {"name": node,
|
||||
"uuid": cmds.getAttr("{}.mbID".format(node, ))}
|
||||
|
||||
# Include components information when components are assigned
|
||||
if components:
|
||||
|
|
@ -226,7 +265,22 @@ class CollectLook(pyblish.api.InstancePlugin):
|
|||
|
||||
return member_data
|
||||
|
||||
def collect_attributes_changes(self, instance):
|
||||
def collect_attributes_changed(self, instance):
|
||||
"""Collect all userDefined attributes which have changed
|
||||
|
||||
Each node gets checked for user defined attributes which have been
|
||||
altered during development. Each changes gets logged in a dictionary
|
||||
|
||||
[{name: node,
|
||||
uuid: uuid,
|
||||
attributes: {attribute: value}}]
|
||||
|
||||
Args:
|
||||
instance (list): all nodes which will be published
|
||||
|
||||
Returns:
|
||||
list
|
||||
"""
|
||||
|
||||
attributes = []
|
||||
for node in instance:
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ class ExtractLook(colorbleed.api.Extractor):
|
|||
# Remove all members of the sets so they are not included in the
|
||||
# exported file by accident
|
||||
self.log.info("Extract sets (Maya ASCII)..")
|
||||
sets = instance.data["lookSets"]
|
||||
lookdata = instance.data["lookData"]
|
||||
sets = lookdata["sets"]
|
||||
|
||||
# Define the texture file node remapping
|
||||
resource_remap = dict()
|
||||
|
|
@ -71,8 +72,8 @@ class ExtractLook(colorbleed.api.Extractor):
|
|||
|
||||
# Write the JSON data
|
||||
self.log.info("Extract json..")
|
||||
data = {"attributes": instance.data["lookAttributes"],
|
||||
"sets": instance.data["lookSetRelations"]}
|
||||
data = {"attributes": lookdata["attributes"],
|
||||
"sets": lookdata["relationships"]}
|
||||
with open(json_path, "w") as f:
|
||||
json.dump(data, f)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import maya.cmds as cmds
|
||||
|
||||
import pyblish.api
|
||||
import colorbleed.api
|
||||
|
||||
import cbra.utils.maya.node_uuid as id_utils
|
||||
|
||||
|
||||
class ValidateLookMembersNodeIds(pyblish.api.InstancePlugin):
|
||||
"""Validate look members have colorbleed id attributes
|
||||
|
|
@ -20,7 +20,8 @@ class ValidateLookMembersNodeIds(pyblish.api.InstancePlugin):
|
|||
families = ['colorbleed.look']
|
||||
hosts = ['maya']
|
||||
label = 'Look Members Id Attributes'
|
||||
actions = [colorbleed.api.SelectInvalidAction]
|
||||
actions = [colorbleed.api.SelectInvalidAction,
|
||||
colorbleed.api.GenerateUUIDsOnInvalidAction]
|
||||
|
||||
@staticmethod
|
||||
def get_invalid(instance):
|
||||
|
|
@ -40,7 +41,7 @@ class ValidateLookMembersNodeIds(pyblish.api.InstancePlugin):
|
|||
# Ensure all nodes have a cbId
|
||||
invalid = list()
|
||||
for node in members:
|
||||
if not id_utils.has_id(node):
|
||||
if not cmds.getAttr("{}.mbID".format(node)):
|
||||
invalid.append(node)
|
||||
|
||||
return invalid
|
||||
|
|
|
|||
|
|
@ -5,7 +5,14 @@ from maya import cmds
|
|||
import pyblish.api
|
||||
import colorbleed.api
|
||||
|
||||
import cbra.utils.maya.node_uuid as id_utils
|
||||
|
||||
def get_unique_id(node):
|
||||
attr = 'cbId'
|
||||
unique_id = None
|
||||
has_attribute = cmds.attributeQuery(attr, node=node, exists=True)
|
||||
if has_attribute:
|
||||
unique_id = cmds.getAttr("{}.{}".format(node, attr))
|
||||
return unique_id
|
||||
|
||||
|
||||
class ValidateLookMembersUnique(pyblish.api.InstancePlugin):
|
||||
|
|
@ -25,15 +32,16 @@ class ValidateLookMembersUnique(pyblish.api.InstancePlugin):
|
|||
families = ['colorbleed.look']
|
||||
hosts = ['maya']
|
||||
label = 'Look Members Unique'
|
||||
actions = [colorbleed.api.SelectInvalidAction]
|
||||
actions = [colorbleed.api.SelectInvalidAction,
|
||||
colorbleed.api.GenerateUUIDsOnInvalidAction]
|
||||
|
||||
@staticmethod
|
||||
def get_invalid(instance):
|
||||
|
||||
# Get all members from the sets
|
||||
members = []
|
||||
relations = instance.data["lookData"]["sets"]
|
||||
for sg in relations:
|
||||
relationships = instance.data["lookData"]["relationships"]
|
||||
for sg in relationships:
|
||||
sg_members = sg['members']
|
||||
sg_members = [member['name'] for member in sg_members]
|
||||
members.extend(sg_members)
|
||||
|
|
@ -45,10 +53,9 @@ class ValidateLookMembersUnique(pyblish.api.InstancePlugin):
|
|||
# Group members per id
|
||||
id_nodes = defaultdict(set)
|
||||
for node in members:
|
||||
node_id = id_utils.get_id(node)
|
||||
node_id = get_unique_id(node)
|
||||
if not node_id:
|
||||
continue
|
||||
|
||||
id_nodes[node_id].add(node)
|
||||
|
||||
invalid = list()
|
||||
|
|
@ -61,8 +68,9 @@ class ValidateLookMembersUnique(pyblish.api.InstancePlugin):
|
|||
def process(self, instance):
|
||||
"""Process all meshes"""
|
||||
|
||||
invalid = self.get_invalid(instance)
|
||||
print self.actions
|
||||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
raise RuntimeError("Members found without "
|
||||
"asset IDs: {0}".format(invalid))
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
from collections import defaultdict
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
import pyblish.api
|
||||
import colorbleed.api
|
||||
|
||||
import cbra.utils.maya.node_uuid as id_utils
|
||||
|
||||
|
||||
class ValidateLookNodeUniqueIds(pyblish.api.InstancePlugin):
|
||||
"""Validate look sets have unique colorbleed id attributes
|
||||
|
|
@ -15,7 +16,7 @@ class ValidateLookNodeUniqueIds(pyblish.api.InstancePlugin):
|
|||
hosts = ['maya']
|
||||
label = 'Look Id Unique Attributes'
|
||||
actions = [colorbleed.api.SelectInvalidAction,
|
||||
colorbleed.api.GenerateUUIDsOnInvalidAction]
|
||||
colorbleed.api.RepairAction]
|
||||
|
||||
@staticmethod
|
||||
def get_invalid(instance):
|
||||
|
|
@ -26,13 +27,15 @@ class ValidateLookNodeUniqueIds(pyblish.api.InstancePlugin):
|
|||
id_sets = defaultdict(list)
|
||||
invalid = list()
|
||||
for node in nodes:
|
||||
id = id_utils.get_id(node)
|
||||
if not id:
|
||||
unique_id = None
|
||||
if cmds.attributeQuery("mbId", node=node, exists=True):
|
||||
unique_id = cmds.getAttr("{}.mbId".format(node))
|
||||
if not unique_id:
|
||||
continue
|
||||
|
||||
id_sets[id].append(node)
|
||||
id_sets[unique_id].append(node)
|
||||
|
||||
for id, nodes in id_sets.iteritems():
|
||||
for unique_id, nodes in id_sets.iteritems():
|
||||
if len(nodes) > 1:
|
||||
invalid.extend(nodes)
|
||||
|
||||
|
|
@ -42,7 +45,6 @@ class ValidateLookNodeUniqueIds(pyblish.api.InstancePlugin):
|
|||
"""Process all meshes"""
|
||||
|
||||
invalid = self.get_invalid(instance)
|
||||
|
||||
if invalid:
|
||||
raise RuntimeError("Nodes found without "
|
||||
"asset IDs: {0}".format(invalid))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
import re
|
||||
|
||||
import pyblish.api
|
||||
import colorbleed.api
|
||||
|
||||
|
||||
class ValidateNamingConvention(pyblish.api.InstancePlugin):
|
||||
|
||||
label = ""
|
||||
host = ["maya"]
|
||||
actions = [colorbleed.api.SelectInvalidAction]
|
||||
|
||||
@staticmethod
|
||||
def get_invalid(instance):
|
||||
|
||||
invalid = []
|
||||
# todo: change pattern to company standard
|
||||
pattern = re.compile("[a-zA-Z]+_[A-Z]{3}")
|
||||
|
||||
nodes = list(instance)
|
||||
for node in nodes:
|
||||
match = pattern.match(node)
|
||||
if not match:
|
||||
invalid.append(node)
|
||||
|
||||
return invalid
|
||||
|
||||
def process(self, instance):
|
||||
|
||||
invalid = self.get_invalid(instance)
|
||||
if invalid:
|
||||
self.log.error("Found invalid naming convention. Failed noted :\n"
|
||||
"%s" % invalid)
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
from collections import defaultdict
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
import pyblish.api
|
||||
import colorbleed.api
|
||||
|
||||
|
|
@ -16,12 +20,9 @@ class ValidateUniqueNodeIds(pyblish.api.InstancePlugin):
|
|||
def get_invalid_dict(instance):
|
||||
"""Return a dictionary mapping of id key to list of member nodes"""
|
||||
|
||||
import maya.cmds as cmds
|
||||
|
||||
uuid_attr = "cbId"
|
||||
|
||||
# Collect each id with their members
|
||||
from collections import defaultdict
|
||||
ids = defaultdict(list)
|
||||
for member in instance:
|
||||
has_attr = cmds.attributeQuery(uuid_attr, node=member, exists=True)
|
||||
|
|
@ -60,4 +61,3 @@ class ValidateUniqueNodeIds(pyblish.api.InstancePlugin):
|
|||
if invalid:
|
||||
raise RuntimeError("Nodes found with non-unique "
|
||||
"asset IDs: {0}".format(invalid))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue