diff --git a/pype/harmony/__init__.py b/pype/harmony/__init__.py new file mode 100644 index 0000000000..8ac21d3cd3 --- /dev/null +++ b/pype/harmony/__init__.py @@ -0,0 +1,22 @@ +import os + +import avalon.api +import pyblish.api + + +def install(): + print("Installing Pype config...") + + plugins_directory = os.path.join( + os.path.dirname(os.path.dirname(__file__)), "plugins", "harmony" + ) + + pyblish.api.register_plugin_path( + os.path.join(plugins_directory, "publish") + ) + avalon.api.register_plugin_path( + avalon.api.Loader, os.path.join(plugins_directory, "load") + ) + avalon.api.register_plugin_path( + avalon.api.Creator, os.path.join(plugins_directory, "create") + ) diff --git a/pype/plugins/global/publish/integrate_new.py b/pype/plugins/global/publish/integrate_new.py index 0cd46d8891..985a1d2ee7 100644 --- a/pype/plugins/global/publish/integrate_new.py +++ b/pype/plugins/global/publish/integrate_new.py @@ -81,7 +81,8 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): "assembly", "fbx", "textures", - "action" + "action", + "template" ] exclude_families = ["clip"] db_representation_context_keys = [ @@ -743,7 +744,7 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin): matching_profiles[name] = filters if len(matching_profiles) == 1: - template_name = matching_profiles.keys()[0] + template_name = tuple(matching_profiles.keys())[0] self.log.debug( "Using template name \"{}\".".format(template_name) ) diff --git a/pype/plugins/harmony/create/template.py b/pype/plugins/harmony/create/template.py new file mode 100644 index 0000000000..6268127687 --- /dev/null +++ b/pype/plugins/harmony/create/template.py @@ -0,0 +1,12 @@ +from avalon import harmony + + +class CreateTemplate(harmony.Creator): + """Composite node for publishing to templates.""" + + name = "templateDefault" + label = "Template" + family = "template" + + def __init__(self, *args, **kwargs): + super(CreateTemplate, self).__init__(*args, **kwargs) diff --git a/pype/plugins/harmony/publish/collect_current_file.py b/pype/plugins/harmony/publish/collect_current_file.py new file mode 100644 index 0000000000..aab66c2b62 --- /dev/null +++ b/pype/plugins/harmony/publish/collect_current_file.py @@ -0,0 +1,27 @@ +import os + +import pyblish.api +from avalon import harmony + + +class CollectCurrentFile(pyblish.api.ContextPlugin): + """Inject the current working file into context""" + + order = pyblish.api.CollectorOrder - 0.5 + label = "Current File" + hosts = ["harmony"] + + def process(self, context): + """Inject the current working file""" + func = """function func() + { + return ( + scene.currentProjectPath() + "/" + + scene.currentVersionName() + ".xstage" + ); + } + func + """ + + current_file = harmony.send({"function": func})["result"] + context.data["currentFile"] = os.path.normpath(current_file) diff --git a/pype/plugins/harmony/publish/collect_instances.py b/pype/plugins/harmony/publish/collect_instances.py new file mode 100644 index 0000000000..1ed49e3eb8 --- /dev/null +++ b/pype/plugins/harmony/publish/collect_instances.py @@ -0,0 +1,44 @@ +import pyblish.api +from avalon import harmony + + +class CollectInstances(pyblish.api.ContextPlugin): + """Gather instances by nodes metadata. + + This collector takes into account assets that are associated with + a composite node and marked with a unique identifier; + + Identifier: + id (str): "pyblish.avalon.instance" + """ + + label = "Instances" + order = pyblish.api.CollectorOrder + hosts = ["harmony"] + + def process(self, context): + nodes = harmony.send( + {"function": "node.getNodes", "args": [["COMPOSITE"]]} + )["result"] + + for node in nodes: + data = harmony.read(node) + + # Skip non-tagged nodes. + if not data: + continue + + # Skip containers. + if "container" in data["id"]: + continue + + # Adding families if missing. + data["families"] = data.get("families", []) + + instance = context.create_instance(node.split("/")[-1]) + instance.append(node) + instance.data.update(data) + + # Produce diagnostic message for any graphical + # user interface interested in visualising it. + self.log.info("Found: \"%s\" " % instance.data["name"]) diff --git a/pype/plugins/harmony/publish/extract_template.py b/pype/plugins/harmony/publish/extract_template.py new file mode 100644 index 0000000000..9347620dc2 --- /dev/null +++ b/pype/plugins/harmony/publish/extract_template.py @@ -0,0 +1,90 @@ +import os +import shutil + +import pype.api +from avalon import harmony + + +class ExtractTemplate(pype.api.Extractor): + """Extract the connected nodes to the composite instance.""" + label = "Extract Template" + hosts = ["harmony"] + families = ["template"] + + def process(self, instance): + staging_dir = self.staging_dir(instance) + + self.log.info("Outputting template to %s" % staging_dir) + + self.dependencies = [] + self.get_dependencies(instance[0]) + + func = """function func(args) + { + var nodes = args[0]; + selection.clearSelection(); + for (var i = 0 ; i < nodes.length; i++) + { + selection.addNodeToSelection(nodes[i]); + } + } + func + """ + harmony.send({"function": func, "args": [self.dependencies]}) + func = """function func(args) + { + copyPaste.createTemplateFromSelection(args[0], args[1]); + } + func + """ + harmony.send( + { + "function": func, + "args": ["{}.tpl".format(instance.name), staging_dir] + } + ) + + os.chdir(staging_dir) + shutil.make_archive( + "{}".format(instance.name), + "zip", + os.path.join(staging_dir, "{}.tpl".format(instance.name)) + ) + + representation = { + "name": "tpl", + "ext": "zip", + "files": "{}.zip".format(instance.name), + "stagingDir": staging_dir, + } + instance.data["representations"] = [representation] + + def get_dependencies(self, node): + func = """function func(args) + { + var target_node = args[0]; + var numInput = node.numberOfInputPorts(target_node); + var dependencies = []; + for (var i = 0 ; i < numInput; i++) + { + dependencies.push(node.srcNode(target_node, i)); + } + return dependencies; + } + func + """ + + current_dependencies = harmony.send( + {"function": func, "args": [node]} + )["result"] + + for dependency in current_dependencies: + if not dependency: + continue + + if dependency in self.dependencies: + continue + + self.dependencies.append(dependency) + + self.get_dependencies(dependency)