mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
Compare commits
19 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9bbab9944 | ||
|
|
826d22b166 | ||
|
|
b6b2726795 | ||
|
|
1612b0297d | ||
|
|
a802285a6c | ||
|
|
07edce9c9c | ||
|
|
0dc34c32d8 | ||
|
|
7485d99cf6 | ||
|
|
3d0cd51e65 | ||
|
|
8f1eebfcbf | ||
|
|
f46f1d2e8d | ||
|
|
92d4da9efa | ||
|
|
1be1a30b38 | ||
|
|
c55c6a2675 | ||
|
|
818a9f21f3 | ||
|
|
a83ebe3c8d | ||
|
|
0b6c0f3de9 | ||
|
|
4b4ccad085 | ||
|
|
11f5c4ba8b |
7 changed files with 97 additions and 70 deletions
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
|
@ -35,6 +35,7 @@ body:
|
||||||
label: Version
|
label: Version
|
||||||
description: What version are you running? Look to AYON Tray
|
description: What version are you running? Look to AYON Tray
|
||||||
options:
|
options:
|
||||||
|
- 1.7.0
|
||||||
- 1.6.13
|
- 1.6.13
|
||||||
- 1.6.12
|
- 1.6.12
|
||||||
- 1.6.11
|
- 1.6.11
|
||||||
|
|
|
||||||
|
|
@ -160,9 +160,14 @@ class ExtractThumbnailFromSource(pyblish.api.InstancePlugin):
|
||||||
dst_path: str,
|
dst_path: str,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
self.log.debug("Outputting thumbnail with OIIO: {}".format(dst_path))
|
self.log.debug("Outputting thumbnail with OIIO: {}".format(dst_path))
|
||||||
|
try:
|
||||||
resolution_args = self._get_resolution_args(
|
resolution_args = self._get_resolution_args(
|
||||||
"oiiotool", src_path
|
"oiiotool", src_path
|
||||||
)
|
)
|
||||||
|
except Exception:
|
||||||
|
self.log.warning("Failed to get resolution args for OIIO.")
|
||||||
|
return False
|
||||||
|
|
||||||
oiio_cmd = get_oiio_tool_args("oiiotool", "-a", src_path)
|
oiio_cmd = get_oiio_tool_args("oiiotool", "-a", src_path)
|
||||||
if resolution_args:
|
if resolution_args:
|
||||||
# resize must be before -o
|
# resize must be before -o
|
||||||
|
|
@ -188,9 +193,13 @@ class ExtractThumbnailFromSource(pyblish.api.InstancePlugin):
|
||||||
src_path: str,
|
src_path: str,
|
||||||
dst_path: str,
|
dst_path: str,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
try:
|
||||||
resolution_args = self._get_resolution_args(
|
resolution_args = self._get_resolution_args(
|
||||||
"ffmpeg", src_path
|
"ffmpeg", src_path
|
||||||
)
|
)
|
||||||
|
except Exception:
|
||||||
|
self.log.warning("Failed to get resolution args for ffmpeg.")
|
||||||
|
return False
|
||||||
|
|
||||||
max_int = str(2147483647)
|
max_int = str(2147483647)
|
||||||
ffmpeg_cmd = get_ffmpeg_tool_args(
|
ffmpeg_cmd = get_ffmpeg_tool_args(
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import copy
|
import copy
|
||||||
import errno
|
|
||||||
import itertools
|
import itertools
|
||||||
import shutil
|
import shutil
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
|
||||||
|
|
||||||
from speedcopy import copyfile
|
|
||||||
|
|
||||||
import clique
|
import clique
|
||||||
import pyblish.api
|
import pyblish.api
|
||||||
|
|
@ -16,11 +13,15 @@ from ayon_api.operations import (
|
||||||
)
|
)
|
||||||
from ayon_api.utils import create_entity_id
|
from ayon_api.utils import create_entity_id
|
||||||
|
|
||||||
from ayon_core.lib import create_hard_link, source_hash
|
from ayon_core.lib import source_hash
|
||||||
from ayon_core.lib.file_transaction import wait_for_future_errors
|
from ayon_core.lib.file_transaction import (
|
||||||
|
FileTransaction,
|
||||||
|
DuplicateDestinationError,
|
||||||
|
)
|
||||||
from ayon_core.pipeline.publish import (
|
from ayon_core.pipeline.publish import (
|
||||||
get_publish_template_name,
|
get_publish_template_name,
|
||||||
OptionalPyblishPluginMixin,
|
OptionalPyblishPluginMixin,
|
||||||
|
KnownPublishError,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -421,19 +422,40 @@ class IntegrateHeroVersion(
|
||||||
(repre_entity, dst_paths)
|
(repre_entity, dst_paths)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.path_checks = []
|
file_transactions = FileTransaction(
|
||||||
|
log=self.log,
|
||||||
# Copy(hardlink) paths of source and destination files
|
# Enforce unique transfers
|
||||||
# TODO should we *only* create hardlinks?
|
allow_queue_replacements=False
|
||||||
# TODO should we keep files for deletion until this is successful?
|
|
||||||
with ThreadPoolExecutor(max_workers=8) as executor:
|
|
||||||
futures = [
|
|
||||||
executor.submit(self.copy_file, src_path, dst_path)
|
|
||||||
for src_path, dst_path in itertools.chain(
|
|
||||||
src_to_dst_file_paths, other_file_paths_mapping
|
|
||||||
)
|
)
|
||||||
]
|
mode = FileTransaction.MODE_COPY
|
||||||
wait_for_future_errors(executor, futures)
|
if self.use_hardlinks:
|
||||||
|
mode = FileTransaction.MODE_LINK
|
||||||
|
|
||||||
|
try:
|
||||||
|
for src_path, dst_path in itertools.chain(
|
||||||
|
src_to_dst_file_paths,
|
||||||
|
other_file_paths_mapping
|
||||||
|
):
|
||||||
|
file_transactions.add(src_path, dst_path, mode=mode)
|
||||||
|
|
||||||
|
self.log.debug("Integrating source files to destination ...")
|
||||||
|
file_transactions.process()
|
||||||
|
|
||||||
|
except DuplicateDestinationError as exc:
|
||||||
|
# Raise DuplicateDestinationError as KnownPublishError
|
||||||
|
# and rollback the transactions
|
||||||
|
file_transactions.rollback()
|
||||||
|
raise KnownPublishError(exc).with_traceback(sys.exc_info()[2])
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
# Rollback the transactions
|
||||||
|
file_transactions.rollback()
|
||||||
|
self.log.critical("Error when copying files", exc_info=True)
|
||||||
|
raise exc
|
||||||
|
|
||||||
|
# Finalizing can't rollback safely so no use for moving it to
|
||||||
|
# the try, except.
|
||||||
|
file_transactions.finalize()
|
||||||
|
|
||||||
# Update prepared representation etity data with files
|
# Update prepared representation etity data with files
|
||||||
# and integrate it to server.
|
# and integrate it to server.
|
||||||
|
|
@ -622,48 +644,6 @@ class IntegrateHeroVersion(
|
||||||
).format(path))
|
).format(path))
|
||||||
return path
|
return path
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
try:
|
|
||||||
os.makedirs(dirname)
|
|
||||||
self.log.debug("Folder(s) created: \"{}\"".format(dirname))
|
|
||||||
except OSError as exc:
|
|
||||||
if exc.errno != errno.EEXIST:
|
|
||||||
self.log.error("An unexpected error occurred.", exc_info=True)
|
|
||||||
raise
|
|
||||||
|
|
||||||
self.log.debug("Folder already exists: \"{}\"".format(dirname))
|
|
||||||
|
|
||||||
if self.use_hardlinks:
|
|
||||||
# First try hardlink and copy if paths are cross drive
|
|
||||||
self.log.debug("Hardlinking file \"{}\" to \"{}\"".format(
|
|
||||||
src_path, dst_path
|
|
||||||
))
|
|
||||||
try:
|
|
||||||
create_hard_link(src_path, dst_path)
|
|
||||||
# Return when successful
|
|
||||||
return
|
|
||||||
|
|
||||||
except OSError as exc:
|
|
||||||
# re-raise exception if different than
|
|
||||||
# EXDEV - cross drive path
|
|
||||||
# EINVAL - wrong format, must be NTFS
|
|
||||||
self.log.debug(
|
|
||||||
"Hardlink failed with errno:'{}'".format(exc.errno))
|
|
||||||
if exc.errno not in [errno.EXDEV, errno.EINVAL]:
|
|
||||||
raise
|
|
||||||
|
|
||||||
self.log.debug(
|
|
||||||
"Hardlinking failed, falling back to regular copy...")
|
|
||||||
|
|
||||||
self.log.debug("Copying file \"{}\" to \"{}\"".format(
|
|
||||||
src_path, dst_path
|
|
||||||
))
|
|
||||||
|
|
||||||
copyfile(src_path, dst_path)
|
|
||||||
|
|
||||||
def version_from_representations(self, project_name, repres):
|
def version_from_representations(self, project_name, repres):
|
||||||
for repre in repres:
|
for repre in repres:
|
||||||
version = ayon_api.get_version_by_id(
|
version = ayon_api.get_version_by_id(
|
||||||
|
|
|
||||||
|
|
@ -1045,10 +1045,23 @@ class ProjectPushItemProcess:
|
||||||
copied_tags = self._get_transferable_tags(src_version_entity)
|
copied_tags = self._get_transferable_tags(src_version_entity)
|
||||||
copied_status = self._get_transferable_status(src_version_entity)
|
copied_status = self._get_transferable_status(src_version_entity)
|
||||||
|
|
||||||
|
description_parts = []
|
||||||
|
dst_attr_description = dst_attrib.get("description")
|
||||||
|
if dst_attr_description:
|
||||||
|
description_parts.append(dst_attr_description)
|
||||||
|
|
||||||
|
description = self._create_src_version_description(
|
||||||
|
self._item.src_project_name,
|
||||||
|
src_version_entity
|
||||||
|
)
|
||||||
|
if description:
|
||||||
|
description_parts.append(description)
|
||||||
|
|
||||||
|
dst_attrib["description"] = "\n\n".join(description_parts)
|
||||||
|
|
||||||
version_entity = new_version_entity(
|
version_entity = new_version_entity(
|
||||||
dst_version,
|
dst_version,
|
||||||
product_id,
|
product_id,
|
||||||
author=src_version_entity["author"],
|
|
||||||
status=copied_status,
|
status=copied_status,
|
||||||
tags=copied_tags,
|
tags=copied_tags,
|
||||||
task_id=self._task_info.get("id"),
|
task_id=self._task_info.get("id"),
|
||||||
|
|
@ -1370,6 +1383,30 @@ class ProjectPushItemProcess:
|
||||||
return copied_status["name"]
|
return copied_status["name"]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _create_src_version_description(
|
||||||
|
self,
|
||||||
|
src_project_name: str,
|
||||||
|
src_version_entity: dict[str, Any]
|
||||||
|
) -> str:
|
||||||
|
"""Creates description text about source version."""
|
||||||
|
src_version_id = src_version_entity["id"]
|
||||||
|
src_author = src_version_entity["author"]
|
||||||
|
query = "&".join([
|
||||||
|
f"project={src_project_name}",
|
||||||
|
"type=version",
|
||||||
|
f"id={src_version_id}"
|
||||||
|
])
|
||||||
|
version_url = (
|
||||||
|
f"{ayon_api.get_base_url()}"
|
||||||
|
f"/projects/{src_project_name}/products?{query}"
|
||||||
|
)
|
||||||
|
description = (
|
||||||
|
f"Version copied from from {version_url} "
|
||||||
|
f"created by '{src_author}', "
|
||||||
|
)
|
||||||
|
|
||||||
|
return description
|
||||||
|
|
||||||
|
|
||||||
class IntegrateModel:
|
class IntegrateModel:
|
||||||
def __init__(self, controller):
|
def __init__(self, controller):
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""Package declaring AYON addon 'core' version."""
|
"""Package declaring AYON addon 'core' version."""
|
||||||
__version__ = "1.7.0"
|
__version__ = "1.7.0+dev"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name = "core"
|
name = "core"
|
||||||
title = "Core"
|
title = "Core"
|
||||||
version = "1.7.0"
|
version = "1.7.0+dev"
|
||||||
|
|
||||||
client_dir = "ayon_core"
|
client_dir = "ayon_core"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "ayon-core"
|
name = "ayon-core"
|
||||||
version = "1.7.0"
|
version = "1.7.0+dev"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["Ynput Team <team@ynput.io>"]
|
authors = ["Ynput Team <team@ynput.io>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue