mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
AYON: Implement integrate links publish plugin (#4842)
* implemented get_output_link_versions * implemented remainin entity link functions * implemented ayon variant of links integration * Changed class name and label * fix data types iteration * added links query fix from ayon api develop * removed unnecessary import
This commit is contained in:
parent
899f9965e4
commit
ed9b25236e
6 changed files with 304 additions and 11 deletions
|
|
@ -423,8 +423,23 @@ def get_last_version_by_subset_name(
|
|||
)
|
||||
|
||||
|
||||
def get_output_link_versions(*args, **kwargs):
|
||||
raise NotImplementedError("'get_output_link_versions' not implemented")
|
||||
def get_output_link_versions(project_name, version_id, fields=None):
|
||||
if not version_id:
|
||||
return []
|
||||
|
||||
con = get_server_api_connection()
|
||||
version_links = con.get_version_links(
|
||||
project_name, version_id, link_direction="out")
|
||||
|
||||
version_ids = {
|
||||
link["entityId"]
|
||||
for link in version_links
|
||||
if link["entityType"] == "version"
|
||||
}
|
||||
if not version_ids:
|
||||
return []
|
||||
|
||||
return get_versions(project_name, version_ids=version_ids, fields=fields)
|
||||
|
||||
|
||||
def version_is_latest(project_name, version_id):
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
import ayon_api
|
||||
from ayon_api import get_folder_links, get_versions_links
|
||||
|
||||
from .entities import get_assets, get_representation_by_id
|
||||
|
||||
|
||||
def get_linked_asset_ids(project_name, asset_doc=None, asset_id=None):
|
||||
"""Extract linked asset ids from asset document.
|
||||
|
||||
|
|
@ -15,7 +21,19 @@ def get_linked_asset_ids(project_name, asset_doc=None, asset_id=None):
|
|||
List[Union[ObjectId, str]]: Asset ids of input links.
|
||||
"""
|
||||
|
||||
return []
|
||||
output = []
|
||||
if not asset_doc and not asset_id:
|
||||
return output
|
||||
|
||||
if not asset_id:
|
||||
asset_id = asset_doc["_id"]
|
||||
|
||||
links = get_folder_links(project_name, asset_id, link_direction="in")
|
||||
return [
|
||||
link["entityId"]
|
||||
for link in links
|
||||
if link["entityType"] == "folder"
|
||||
]
|
||||
|
||||
|
||||
def get_linked_assets(
|
||||
|
|
@ -38,7 +56,11 @@ def get_linked_assets(
|
|||
asset doc.
|
||||
"""
|
||||
|
||||
return []
|
||||
link_ids = get_linked_asset_ids(project_name, asset_doc, asset_id)
|
||||
if not link_ids:
|
||||
return []
|
||||
return list(get_assets(project_name, asset_ids=link_ids, fields=fields))
|
||||
|
||||
|
||||
|
||||
def get_linked_representation_id(
|
||||
|
|
@ -51,6 +73,10 @@ def get_linked_representation_id(
|
|||
Representation links now works only from representation through version
|
||||
back to representations.
|
||||
|
||||
Todos:
|
||||
Missing depth query. Not sure how it did find more representations in
|
||||
depth, probably links to version?
|
||||
|
||||
Args:
|
||||
project_name (str): Name of project where look for links.
|
||||
repre_doc (Dict[str, Any]): Representation document.
|
||||
|
|
@ -62,4 +88,69 @@ def get_linked_representation_id(
|
|||
List[ObjectId] Linked representation ids.
|
||||
"""
|
||||
|
||||
return []
|
||||
if repre_doc:
|
||||
repre_id = repre_doc["_id"]
|
||||
|
||||
if not repre_id and not repre_doc:
|
||||
return []
|
||||
|
||||
version_id = None
|
||||
if repre_doc:
|
||||
version_id = repre_doc.get("parent")
|
||||
|
||||
if not version_id:
|
||||
repre_doc = get_representation_by_id(
|
||||
project_name, repre_id, fields=["parent"]
|
||||
)
|
||||
if repre_doc:
|
||||
version_id = repre_doc["parent"]
|
||||
|
||||
if not version_id:
|
||||
return []
|
||||
|
||||
if max_depth is None or max_depth == 0:
|
||||
max_depth = 1
|
||||
|
||||
link_types = None
|
||||
if link_type:
|
||||
link_types = [link_type]
|
||||
|
||||
# Store already found version ids to avoid recursion, and also to store
|
||||
# output -> Don't forget to remove 'version_id' at the end!!!
|
||||
linked_version_ids = {version_id}
|
||||
# Each loop of depth will reset this variable
|
||||
versions_to_check = {version_id}
|
||||
for _ in range(max_depth):
|
||||
if not versions_to_check:
|
||||
break
|
||||
|
||||
links = get_versions_links(
|
||||
project_name,
|
||||
versions_to_check,
|
||||
link_types=link_types,
|
||||
link_direction="out")
|
||||
|
||||
versions_to_check = set()
|
||||
for link in links:
|
||||
# Care only about version links
|
||||
if link["entityType"] != "version":
|
||||
continue
|
||||
entity_id = link["entityId"]
|
||||
# Skip already found linked version ids
|
||||
if entity_id in linked_version_ids:
|
||||
continue
|
||||
linked_version_ids.add(entity_id)
|
||||
versions_to_check.add(entity_id)
|
||||
|
||||
linked_version_ids.remove(version_id)
|
||||
if not linked_version_ids:
|
||||
return []
|
||||
|
||||
representations = ayon_api.get_representations(
|
||||
project_name,
|
||||
version_ids=linked_version_ids,
|
||||
fields=["id"])
|
||||
return [
|
||||
repre["id"]
|
||||
for repre in representations
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ from collections import OrderedDict
|
|||
from bson.objectid import ObjectId
|
||||
import pyblish.api
|
||||
|
||||
from openpype import AYON_SERVER_ENABLED
|
||||
from openpype.pipeline import legacy_io
|
||||
|
||||
|
||||
|
|
@ -34,6 +35,11 @@ class IntegrateInputLinks(pyblish.api.ContextPlugin):
|
|||
plugin.
|
||||
|
||||
"""
|
||||
|
||||
if AYON_SERVER_ENABLED:
|
||||
self.log.info("Skipping, in AYON mode")
|
||||
return
|
||||
|
||||
workfile = None
|
||||
publishing = []
|
||||
|
||||
|
|
|
|||
160
openpype/plugins/publish/integrate_inputlinks_ayon.py
Normal file
160
openpype/plugins/publish/integrate_inputlinks_ayon.py
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
import collections
|
||||
|
||||
import pyblish.api
|
||||
from ayon_api import create_link, make_sure_link_type_exists
|
||||
|
||||
from openpype import AYON_SERVER_ENABLED
|
||||
|
||||
|
||||
class IntegrateInputLinksAYON(pyblish.api.ContextPlugin):
|
||||
"""Connecting version level dependency links"""
|
||||
|
||||
order = pyblish.api.IntegratorOrder + 0.2
|
||||
label = "Connect Dependency InputLinks AYON"
|
||||
|
||||
def process(self, context):
|
||||
"""Connect dependency links for all instances, globally
|
||||
|
||||
Code steps:
|
||||
- filter instances that integrated version
|
||||
- have "versionEntity" entry in data
|
||||
- separate workfile instance within filtered instances
|
||||
- when workfile instance is available:
|
||||
- link all `loadedVersions` as input of the workfile
|
||||
- link workfile as input of all other integrated versions
|
||||
- link version's inputs if it's instance have "inputVersions" entry
|
||||
-
|
||||
|
||||
inputVersions:
|
||||
The "inputVersions" in instance.data should be a list of
|
||||
version ids (str), which are the dependencies of the publishing
|
||||
instance that should be extracted from working scene by the DCC
|
||||
specific publish plugin.
|
||||
"""
|
||||
|
||||
if not AYON_SERVER_ENABLED:
|
||||
self.log.info("Skipping, not in AYON mode")
|
||||
return
|
||||
|
||||
workfile_instance, other_instances = self.split_instances(context)
|
||||
|
||||
# Variable where links are stored in submethods
|
||||
new_links_by_type = collections.defaultdict(list)
|
||||
|
||||
self.create_workfile_links(
|
||||
workfile_instance, other_instances, new_links_by_type)
|
||||
|
||||
self.create_generative_links(other_instances, new_links_by_type)
|
||||
|
||||
self.create_links_on_server(context, new_links_by_type)
|
||||
|
||||
def split_instances(self, context):
|
||||
workfile_instance = None
|
||||
other_instances = []
|
||||
|
||||
for instance in context:
|
||||
# Skip inactive instances
|
||||
if not instance.data.get("publish", True):
|
||||
continue
|
||||
|
||||
version_doc = instance.data.get("versionEntity")
|
||||
if not version_doc:
|
||||
self.log.debug(
|
||||
"Instance {} doesn't have version.".format(instance))
|
||||
continue
|
||||
|
||||
family = instance.data.get("family")
|
||||
if family == "workfile":
|
||||
workfile_instance = instance
|
||||
else:
|
||||
other_instances.append(instance)
|
||||
return workfile_instance, other_instances
|
||||
|
||||
def add_link(self, new_links_by_type, link_type, input_id, output_id):
|
||||
"""Add dependency link data into temporary variable.
|
||||
|
||||
Args:
|
||||
new_links_by_type (dict[str, list[dict[str, Any]]]): Object where
|
||||
output is stored.
|
||||
link_type (str): Type of link, one of 'reference' or 'generative'
|
||||
input_id (str): Input version id.
|
||||
output_id (str): Output version id.
|
||||
"""
|
||||
|
||||
new_links_by_type[link_type].append((input_id, output_id))
|
||||
|
||||
def create_workfile_links(
|
||||
self, workfile_instance, other_instances, new_links_by_type
|
||||
):
|
||||
if workfile_instance is None:
|
||||
self.log.warn("No workfile in this publish session.")
|
||||
return
|
||||
|
||||
workfile_version_id = workfile_instance.data["versionEntity"]["_id"]
|
||||
# link workfile to all publishing versions
|
||||
for instance in other_instances:
|
||||
self.add_link(
|
||||
new_links_by_type,
|
||||
"generative",
|
||||
workfile_version_id,
|
||||
instance.data["versionEntity"]["_id"],
|
||||
)
|
||||
|
||||
loaded_versions = workfile_instance.context.get("loadedVersions")
|
||||
if not loaded_versions:
|
||||
return
|
||||
|
||||
# link all loaded versions in scene into workfile
|
||||
for version in loaded_versions:
|
||||
self.add_link(
|
||||
new_links_by_type,
|
||||
"reference",
|
||||
version["version"],
|
||||
workfile_version_id,
|
||||
)
|
||||
|
||||
def create_generative_links(self, other_instances, new_links_by_type):
|
||||
for instance in other_instances:
|
||||
input_versions = instance.data.get("inputVersions")
|
||||
if not input_versions:
|
||||
continue
|
||||
|
||||
version_entity = instance.data["versionEntity"]
|
||||
for input_version in input_versions:
|
||||
self.add_link(
|
||||
new_links_by_type,
|
||||
"generative",
|
||||
input_version,
|
||||
version_entity["_id"],
|
||||
)
|
||||
|
||||
def create_links_on_server(self, context, new_links):
|
||||
"""Create new links on server.
|
||||
|
||||
Args:
|
||||
dict[str, list[tuple[str, str]]]: Version links by link type.
|
||||
"""
|
||||
|
||||
if not new_links:
|
||||
return
|
||||
|
||||
project_name = context.data["projectName"]
|
||||
|
||||
# Make sure link types are available on server
|
||||
for link_type in new_links.keys():
|
||||
make_sure_link_type_exists(
|
||||
project_name, link_type, "version", "version"
|
||||
)
|
||||
|
||||
# Create link themselves
|
||||
for link_type, items in new_links.items():
|
||||
for item in items:
|
||||
input_id, output_id = item
|
||||
create_link(
|
||||
project_name,
|
||||
link_type,
|
||||
input_id,
|
||||
"version",
|
||||
output_id,
|
||||
"version"
|
||||
)
|
||||
|
|
@ -4514,13 +4514,34 @@ class ServerAPI(object):
|
|||
dict[str, list[dict[str, Any]]]: Link info by entity ids.
|
||||
"""
|
||||
|
||||
mapped_type = self._entity_types_link_mapping.get(entity_type)
|
||||
if not mapped_type:
|
||||
if entity_type == "folder":
|
||||
query_func = folders_graphql_query
|
||||
id_filter_key = "folderIds"
|
||||
project_sub_key = "folders"
|
||||
elif entity_type == "task":
|
||||
query_func = tasks_graphql_query
|
||||
id_filter_key = "taskIds"
|
||||
project_sub_key = "tasks"
|
||||
elif entity_type == "subset":
|
||||
query_func = subsets_graphql_query
|
||||
id_filter_key = "subsetIds"
|
||||
project_sub_key = "subsets"
|
||||
elif entity_type == "version":
|
||||
query_func = versions_graphql_query
|
||||
id_filter_key = "versionIds"
|
||||
project_sub_key = "versions"
|
||||
elif entity_type == "representation":
|
||||
query_func = representations_graphql_query
|
||||
id_filter_key = "representationIds"
|
||||
project_sub_key = "representations"
|
||||
else:
|
||||
raise ValueError("Unknown type \"{}\". Expected {}".format(
|
||||
entity_type, ", ".join(self._entity_types_link_mapping.keys())
|
||||
entity_type,
|
||||
", ".join(
|
||||
("folder", "task", "subset", "version", "representation")
|
||||
)
|
||||
))
|
||||
|
||||
id_filter_key, project_sub_key = mapped_type
|
||||
output = collections.defaultdict(list)
|
||||
filters = {
|
||||
"projectName": project_name
|
||||
|
|
@ -4534,7 +4555,7 @@ class ServerAPI(object):
|
|||
if not self._prepare_link_filters(filters, link_types, link_direction):
|
||||
return output
|
||||
|
||||
query = folders_graphql_query({"id", "links"})
|
||||
query = query_func({"id", "links"})
|
||||
for attr, filter_value in filters.items():
|
||||
query.set_variable_value(attr, filter_value)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
"""Package declaring Python API for Ayon server."""
|
||||
__version__ = "0.1.17"
|
||||
__version__ = "0.1.17-1"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue