mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge pull request #2192 from davidlatwe/feature/typed_asset_version_dependencies
This commit is contained in:
commit
a8f2e0f7ec
6 changed files with 283 additions and 6 deletions
55
openpype/plugins/publish/collect_scene_loaded_versions.py
Normal file
55
openpype/plugins/publish/collect_scene_loaded_versions.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
import pyblish.api
|
||||
from avalon import api, io
|
||||
|
||||
|
||||
class CollectSceneLoadedVersions(pyblish.api.ContextPlugin):
|
||||
|
||||
order = pyblish.api.CollectorOrder + 0.0001
|
||||
label = "Collect Versions Loaded in Scene"
|
||||
hosts = [
|
||||
"aftereffects",
|
||||
"blender",
|
||||
"celaction",
|
||||
"fusion",
|
||||
"harmony",
|
||||
"hiero",
|
||||
"houdini",
|
||||
"maya",
|
||||
"nuke",
|
||||
"photoshop",
|
||||
"resolve",
|
||||
"tvpaint"
|
||||
]
|
||||
|
||||
def process(self, context):
|
||||
host = api.registered_host()
|
||||
if host is None:
|
||||
self.log.warn("No registered host.")
|
||||
return
|
||||
|
||||
if not hasattr(host, "ls"):
|
||||
host_name = host.__name__
|
||||
self.log.warn("Host %r doesn't have ls() implemented." % host_name)
|
||||
return
|
||||
|
||||
loaded_versions = []
|
||||
_containers = list(host.ls())
|
||||
_repr_ids = [io.ObjectId(c["representation"]) for c in _containers]
|
||||
version_by_repr = {
|
||||
str(doc["_id"]): doc["parent"] for doc in
|
||||
io.find({"_id": {"$in": _repr_ids}}, projection={"parent": 1})
|
||||
}
|
||||
|
||||
for con in _containers:
|
||||
# NOTE:
|
||||
# may have more then one representation that are same version
|
||||
version = {
|
||||
"objectName": con["objectName"], # container node name
|
||||
"subsetName": con["name"],
|
||||
"representation": io.ObjectId(con["representation"]),
|
||||
"version": version_by_repr[con["representation"]], # _id
|
||||
}
|
||||
loaded_versions.append(version)
|
||||
|
||||
context.data["loadedVersions"] = loaded_versions
|
||||
|
|
@ -10,7 +10,7 @@ class CollectSceneVersion(pyblish.api.ContextPlugin):
|
|||
"""
|
||||
|
||||
order = pyblish.api.CollectorOrder
|
||||
label = 'Collect Version'
|
||||
label = 'Collect Scene Version'
|
||||
hosts = [
|
||||
"aftereffects",
|
||||
"blender",
|
||||
|
|
|
|||
130
openpype/plugins/publish/integrate_inputlinks.py
Normal file
130
openpype/plugins/publish/integrate_inputlinks.py
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
|
||||
from collections import OrderedDict
|
||||
from avalon import io
|
||||
import pyblish.api
|
||||
|
||||
|
||||
class IntegrateInputLinks(pyblish.api.ContextPlugin):
|
||||
"""Connecting version level dependency links"""
|
||||
|
||||
order = pyblish.api.IntegratorOrder + 0.2
|
||||
label = "Connect Dependency InputLinks"
|
||||
|
||||
def process(self, context):
|
||||
"""Connect dependency links for all instances, globally
|
||||
|
||||
Code steps:
|
||||
* filter out instances that has "versionEntity" entry in data
|
||||
* find workfile instance within context
|
||||
* if workfile found:
|
||||
- link all `loadedVersions` as input of the workfile
|
||||
- link workfile as input of all publishing instances
|
||||
* else:
|
||||
- show "no workfile" warning
|
||||
* link instances' inputs if it's data has "inputVersions" entry
|
||||
* Write into database
|
||||
|
||||
inputVersions:
|
||||
The "inputVersions" in instance.data should be a list of
|
||||
version document's Id (str or ObjectId), which are the
|
||||
dependencies of the publishing instance that should be
|
||||
extracted from working scene by the DCC specific publish
|
||||
plugin.
|
||||
|
||||
"""
|
||||
workfile = None
|
||||
publishing = []
|
||||
|
||||
for instance in context:
|
||||
if not instance.data.get("publish", True):
|
||||
# Skip inactive instances
|
||||
continue
|
||||
|
||||
version_doc = instance.data.get("versionEntity")
|
||||
if not version_doc:
|
||||
self.log.debug("Instance %s doesn't have version." % instance)
|
||||
continue
|
||||
|
||||
version_data = version_doc.get("data", {})
|
||||
families = version_data.get("families", [])
|
||||
|
||||
if "workfile" in families:
|
||||
workfile = instance
|
||||
else:
|
||||
publishing.append(instance)
|
||||
|
||||
if workfile is None:
|
||||
self.log.warn("No workfile in this publish session.")
|
||||
else:
|
||||
workfile_version_doc = workfile.data["versionEntity"]
|
||||
# link all loaded versions in scene into workfile
|
||||
for version in context.data.get("loadedVersions", []):
|
||||
self.add_link(
|
||||
link_type="reference",
|
||||
input_id=version["version"],
|
||||
version_doc=workfile_version_doc,
|
||||
)
|
||||
# link workfile to all publishing versions
|
||||
for instance in publishing:
|
||||
self.add_link(
|
||||
link_type="generative",
|
||||
input_id=workfile_version_doc["_id"],
|
||||
version_doc=instance.data["versionEntity"],
|
||||
)
|
||||
|
||||
# link versions as dependencies to the instance
|
||||
for instance in publishing:
|
||||
for input_version in instance.data.get("inputVersions") or []:
|
||||
self.add_link(
|
||||
link_type="generative",
|
||||
input_id=input_version,
|
||||
version_doc=instance.data["versionEntity"],
|
||||
)
|
||||
|
||||
publishing.append(workfile)
|
||||
self.write_links_to_database(publishing)
|
||||
|
||||
def add_link(self, link_type, input_id, version_doc):
|
||||
"""Add dependency link data into version document
|
||||
|
||||
Args:
|
||||
link_type (str): Type of link, one of 'reference' or 'generative'
|
||||
input_id (str or ObjectId): Document Id of input version
|
||||
version_doc (dict): The version document that takes the input
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
"""
|
||||
# NOTE:
|
||||
# using OrderedDict() here is just for ensuring field order between
|
||||
# python versions, if we ever need to use mongodb operation '$addToSet'
|
||||
# to update and avoid duplicating elements in 'inputLinks' array in the
|
||||
# future.
|
||||
link = OrderedDict()
|
||||
link["type"] = link_type
|
||||
link["input"] = io.ObjectId(input_id)
|
||||
link["linkedBy"] = "publish"
|
||||
|
||||
if "inputLinks" not in version_doc["data"]:
|
||||
version_doc["data"]["inputLinks"] = []
|
||||
version_doc["data"]["inputLinks"].append(link)
|
||||
|
||||
def write_links_to_database(self, instances):
|
||||
"""Iter instances in context to update database
|
||||
|
||||
If `versionEntity.data.inputLinks` not None in `instance.data`, doc
|
||||
in database will be updated.
|
||||
|
||||
"""
|
||||
for instance in instances:
|
||||
version_doc = instance.data.get("versionEntity")
|
||||
if version_doc is None:
|
||||
continue
|
||||
|
||||
input_links = version_doc["data"].get("inputLinks")
|
||||
if input_links is None:
|
||||
continue
|
||||
|
||||
io.update_one({"_id": version_doc["_id"]},
|
||||
{"$set": {"data.inputLinks": input_links}})
|
||||
0
openpype/tools/assetlinks/__init__.py
Normal file
0
openpype/tools/assetlinks/__init__.py
Normal file
85
openpype/tools/assetlinks/widgets.py
Normal file
85
openpype/tools/assetlinks/widgets.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
from Qt import QtWidgets
|
||||
|
||||
|
||||
class SimpleLinkView(QtWidgets.QWidget):
|
||||
|
||||
def __init__(self, dbcon, parent=None):
|
||||
super(SimpleLinkView, self).__init__(parent=parent)
|
||||
self.dbcon = dbcon
|
||||
|
||||
# TODO: display selected target
|
||||
|
||||
in_text = QtWidgets.QLabel("Inputs")
|
||||
in_view = QtWidgets.QListWidget(parent=self)
|
||||
out_text = QtWidgets.QLabel("Outputs")
|
||||
out_view = QtWidgets.QListWidget(parent=self)
|
||||
|
||||
layout = QtWidgets.QGridLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(in_text, 0, 0)
|
||||
layout.addWidget(in_view, 1, 0)
|
||||
layout.addWidget(out_text, 0, 1)
|
||||
layout.addWidget(out_view, 1, 1)
|
||||
|
||||
self._in_view = in_view
|
||||
self._out_view = out_view
|
||||
|
||||
def clear(self):
|
||||
self._in_view.clear()
|
||||
self._out_view.clear()
|
||||
|
||||
def set_version(self, version_doc):
|
||||
self.clear()
|
||||
if not version_doc or not self.isVisible():
|
||||
return
|
||||
|
||||
# inputs
|
||||
#
|
||||
for link in version_doc["data"].get("inputLinks", []):
|
||||
version = self.dbcon.find_one(
|
||||
{"_id": link["input"], "type": "version"},
|
||||
projection={"name": 1, "parent": 1}
|
||||
)
|
||||
if not version:
|
||||
continue
|
||||
subset = self.dbcon.find_one(
|
||||
{"_id": version["parent"], "type": "subset"},
|
||||
projection={"name": 1, "parent": 1}
|
||||
)
|
||||
if not subset:
|
||||
continue
|
||||
asset = self.dbcon.find_one(
|
||||
{"_id": subset["parent"], "type": "asset"},
|
||||
projection={"name": 1}
|
||||
)
|
||||
|
||||
self._in_view.addItem("{asset} {subset} v{version:0>3}".format(
|
||||
asset=asset["name"],
|
||||
subset=subset["name"],
|
||||
version=version["name"],
|
||||
))
|
||||
|
||||
# outputs
|
||||
#
|
||||
outputs = self.dbcon.find(
|
||||
{"type": "version", "data.inputLinks.input": version_doc["_id"]},
|
||||
projection={"name": 1, "parent": 1}
|
||||
)
|
||||
for version in outputs or []:
|
||||
subset = self.dbcon.find_one(
|
||||
{"_id": version["parent"], "type": "subset"},
|
||||
projection={"name": 1, "parent": 1}
|
||||
)
|
||||
if not subset:
|
||||
continue
|
||||
asset = self.dbcon.find_one(
|
||||
{"_id": subset["parent"], "type": "asset"},
|
||||
projection={"name": 1}
|
||||
)
|
||||
|
||||
self._out_view.addItem("{asset} {subset} v{version:0>3}".format(
|
||||
asset=asset["name"],
|
||||
subset=subset["name"],
|
||||
version=version["name"],
|
||||
))
|
||||
|
|
@ -21,6 +21,7 @@ from openpype.tools.utils.views import (
|
|||
TreeViewSpinner,
|
||||
DeselectableTreeView
|
||||
)
|
||||
from openpype.tools.assetlinks.widgets import SimpleLinkView
|
||||
|
||||
from .model import (
|
||||
SubsetsModel,
|
||||
|
|
@ -845,19 +846,25 @@ class VersionWidget(QtWidgets.QWidget):
|
|||
def __init__(self, dbcon, parent=None):
|
||||
super(VersionWidget, self).__init__(parent=parent)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
label = QtWidgets.QLabel("Version", self)
|
||||
data = VersionTextEdit(dbcon, self)
|
||||
data.setReadOnly(True)
|
||||
|
||||
layout.addWidget(label)
|
||||
layout.addWidget(data)
|
||||
depend_widget = SimpleLinkView(dbcon, self)
|
||||
|
||||
tab = QtWidgets.QTabWidget()
|
||||
tab.addTab(data, "Version Info")
|
||||
tab.addTab(depend_widget, "Dependency")
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(tab)
|
||||
|
||||
self.data = data
|
||||
self.depend_widget = depend_widget
|
||||
|
||||
def set_version(self, version_doc):
|
||||
self.data.set_version(version_doc)
|
||||
self.depend_widget.set_version(version_doc)
|
||||
|
||||
|
||||
class FamilyModel(QtGui.QStandardItemModel):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue