Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Publish: register publishes without copying them #4157

Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
59b4f58
OP-4504 - added originalBasename and originalDirname to instance
kalisp Dec 1, 2022
5aed3f9
OP-4504 - added originalDirname to data filling template
kalisp Dec 1, 2022
07ee68e
OP-4504 - added checks for not overwriting same file
kalisp Dec 1, 2022
3eb9672
Merge branch 'develop' of github.com:pypeclub/OpenPype into feature/O…
kalisp Dec 1, 2022
0aa0080
OP-4504 - fixed check file in project folder
kalisp Dec 1, 2022
2327438
OP-4504 - moved path parsing to global plugin
kalisp Dec 1, 2022
499c321
OP-4504 - revert of unwanted change
kalisp Dec 1, 2022
9c381b4
OP-4504 - added logic for originalDirname into integrate
kalisp Dec 1, 2022
1106f8c
OP-4504 - check for None
kalisp Dec 1, 2022
b67c8e2
OP-4504 - cleanup of logic
kalisp Dec 1, 2022
ddfaae8
OP-4504 - added source template to defaults
kalisp Dec 2, 2022
af3ebeb
OP-4504 - Hound
kalisp Dec 2, 2022
d971f9e
OP-4504 - merge develop
kalisp Dec 6, 2022
d1ee451
OP-4504 - update logging
kalisp Dec 6, 2022
ea27412
Merge remote-tracking branch 'origin/bugfix/integrate_thumbnail_sourc…
kalisp Dec 6, 2022
c208a82
Merge remote-tracking branch 'origin/bugfix/integrate_thumbnail_sourc…
kalisp Dec 6, 2022
c9496bc
OP-4504 - change boolean test to validation with exception
kalisp Dec 7, 2022
3fabd51
OP-4504 - weird unpacking not necessary
kalisp Dec 7, 2022
0a12a42
OP-4504 - use existing method to check if path in project
kalisp Dec 7, 2022
cccd9c6
OP-4504 - logging message is wrong as it is called on instances also
kalisp Dec 7, 2022
30eca6f
OP-4504 - fix default source template
kalisp Dec 7, 2022
4c53a77
OP-4504 - make root comparison case insensitive for windows
kalisp Dec 7, 2022
726c8f2
OP-4504 - fix resolving of originalDirname
kalisp Dec 7, 2022
a1f85d3
OP-4504 - use always stagingDir from instance instead of repre
kalisp Dec 7, 2022
d8ed899
OP-4504 - removed unwanted lower
kalisp Dec 7, 2022
98f45c2
OP-4504 - Hound
kalisp Dec 7, 2022
f3481dd
Merge branch 'develop' into feature/OP-4504_Publishing-Register-publi…
kalisp Dec 7, 2022
663538c
Merge develop
kalisp Dec 12, 2022
fe0336c
OP-4504 - removed path comparison function
kalisp Dec 12, 2022
a1a50a6
OP-4504 conflict resolution
kalisp Dec 12, 2022
d18fc94
OP-4504 - fix for deadline publishing
kalisp Dec 12, 2022
8a267f6
OP-4504 - handle originalDirname only if in template
kalisp Dec 12, 2022
9bf00f9
OP-4504 - added collector for originalDirname
kalisp Dec 14, 2022
3cf3fd6
OP-4504 - added validator for source template
kalisp Dec 14, 2022
d9a7d5c
OP-4504 - Hound
kalisp Dec 14, 2022
51c7925
Merge branch 'develop' of github.com:pypeclub/OpenPype into feature/O…
kalisp Dec 14, 2022
a3969f8
Update openpype/plugins/publish/validate_publish_dir.py
kalisp Dec 15, 2022
ee58c0c
OP-4504 - changed to XMLPublishError
kalisp Dec 15, 2022
da274a7
OP-4504 - safer comparison of two paths
kalisp Dec 15, 2022
b6873a0
OP-4504 - added '_thumb' suffix to thumbnail
kalisp Dec 15, 2022
e3866df
OP-4504 - remove check for existence
kalisp Dec 15, 2022
3c09dfc
OP-4504 - remove extension from originalBasename
kalisp Dec 15, 2022
5d8ddb6
OP-4504 - added explicit check
kalisp Dec 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion openpype/plugins/publish/collect_resources_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@


class CollectResourcesPath(pyblish.api.InstancePlugin):
"""Generate directory path where the files and resources will be stored"""
"""Generate directory path where the files and resources will be stored.

Collects folder name and file name from files, if exists, for in-situ
publishing.
"""

label = "Collect Resources Path"
order = pyblish.api.CollectorOrder + 0.495
Expand Down Expand Up @@ -100,3 +104,19 @@ def process(self, instance):

self.log.debug("publishDir: \"{}\"".format(publish_folder))
self.log.debug("resourcesDir: \"{}\"".format(resources_folder))

# parse folder name and file name for online and source templates
# currentFile comes from hosts workfiles
# source comes from Publisher
current_file = instance.data.get("currentFile")
source = instance.data.get("source")
source_file = current_file or source
if source_file and os.path.exists(source_file):
self.log.debug("Parsing paths for {}".format(source_file))
if not instance.data.get("originalBasename"):
instance.data["originalBasename"] = \
os.path.basename(source_file)

if not instance.data.get("originalDirname"):
instance.data["originalDirname"] = \
os.path.dirname(source_file)
99 changes: 76 additions & 23 deletions openpype/plugins/publish/integrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,8 @@ def register(self, instance, file_transactions, filtered_repres):
)
instance.data["versionEntity"] = version

anatomy = instance.context.data["anatomy"]

# Get existing representations (if any)
existing_repres_by_name = {
repre_doc["name"].lower(): repre_doc
Expand All @@ -291,6 +293,14 @@ def register(self, instance, file_transactions, filtered_repres):
instance)

for src, dst in prepared["transfers"]:

if self._are_paths_same(src, dst):
kalisp marked this conversation as resolved.
Show resolved Hide resolved
continue
kalisp marked this conversation as resolved.
Show resolved Hide resolved

if not self._is_path_in_project_roots(anatomy.all_root_paths(),
dst):
continue

# todo: add support for hardlink transfers
file_transactions.add(src, dst)

Expand All @@ -301,13 +311,20 @@ def register(self, instance, file_transactions, filtered_repres):
# .ma representation. Those destination paths are pre-defined, etc.
# todo: should we move or simplify this logic?
resource_destinations = set()
for src, dst in instance.data.get("transfers", []):
file_transactions.add(src, dst, mode=FileTransaction.MODE_COPY)
resource_destinations.add(os.path.abspath(dst))

for src, dst in instance.data.get("hardlinks", []):
file_transactions.add(src, dst, mode=FileTransaction.MODE_HARDLINK)
resource_destinations.add(os.path.abspath(dst))
file_copy_modes = [
("transfers", FileTransaction.MODE_COPY),
("hardlinks", FileTransaction.MODE_HARDLINK)
]
for files_type, copy_mode in zip(*file_copy_modes): # unpack
for src, dst in instance.data.get(files_type, []):
if self._are_paths_same(src, dst):
continue
if not self._is_path_in_project_roots(anatomy.all_root_paths(),
dst):
continue
file_transactions.add(src, dst, mode=copy_mode)
resource_destinations.add(os.path.abspath(dst))

# Bulk write to the database
# We write the subset and version to the database before the File
Expand Down Expand Up @@ -340,7 +357,6 @@ def register(self, instance, file_transactions, filtered_repres):
# Compute the resource file infos once (files belonging to the
# version instance instead of an individual representation) so
# we can re-use those file infos per representation
anatomy = instance.context.data["anatomy"]
resource_file_infos = self.get_files_info(resource_destinations,
sites=sites,
anatomy=anatomy)
Expand Down Expand Up @@ -527,15 +543,33 @@ def prepare_representation(self, repre,
template_data["representation"] = repre["name"]
template_data["ext"] = repre["ext"]

stagingdir = repre.get("stagingDir")
if not stagingdir:
# Fall back to instance staging dir if not explicitly
# set for representation in the instance
self.log.debug((
"Representation uses instance staging dir: {}"
).format(instance_stagingdir))
stagingdir = instance_stagingdir

if not stagingdir:
raise KnownPublishError(
"No staging directory set for representation: {}".format(repre)
)

# optionals
# retrieve additional anatomy data from representation if exists
if not instance.data.get("originalDirname"):
Copy link
Member

@iLLiCiTiT iLLiCiTiT Dec 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say original dirname and basename is representation specific and not instance specific.
EDITED:
The dirname is used for all representations. But I think it should be always set to staging dir from instance and never from representation.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, used instance_stagingdir instead.

instance.data["originalDirname"] = stagingdir

for key, anatomy_key in {
# Representation Key: Anatomy data key
"resolutionWidth": "resolution_width",
"resolutionHeight": "resolution_height",
"fps": "fps",
"outputName": "output",
"originalBasename": "originalBasename"
"originalBasename": "originalBasename",
"originalDirname": "originalDirname"
}.items():
# Allow to take value from representation
# if not found also consider instance.data
Expand All @@ -546,20 +580,6 @@ def prepare_representation(self, repre,
if value is not None:
template_data[anatomy_key] = value

stagingdir = repre.get("stagingDir")
if not stagingdir:
# Fall back to instance staging dir if not explicitly
# set for representation in the instance
self.log.debug((
"Representation uses instance staging dir: {}"
).format(instance_stagingdir))
stagingdir = instance_stagingdir

if not stagingdir:
raise KnownPublishError(
"No staging directory set for representation: {}".format(repre)
)

self.log.debug("Anatomy template name: {}".format(template_name))
anatomy = instance.context.data["anatomy"]
publish_template_category = anatomy.templates[template_name]
Expand All @@ -585,6 +605,7 @@ def prepare_representation(self, repre,
))

src_collection = src_collections[0]
template_data["originalBasename"] = src_collection.head[:-1]
destination_indexes = list(src_collection.indexes)
# Use last frame for minimum padding
# - that should cover both 'udim' and 'frame' minimum padding
Expand Down Expand Up @@ -669,7 +690,8 @@ def prepare_representation(self, repre,
raise KnownPublishError(
"This is a bug. Representation file name is full path"
)

if not template_data.get("originalBasename"):
template_data["originalBasename"] = fname
# Manage anatomy template data
template_data.pop("frame", None)
if is_udim:
Expand Down Expand Up @@ -888,3 +910,34 @@ def prepare_file_info(self, path, anatomy, sites):
"hash": source_hash(path),
"sites": sites
}

def _is_path_in_project_roots(self, roots, file_path):
"""Checks if 'file_path' starts with any of the roots.

Used to check that published path belongs to project, eg. we are not
trying to publish to local only folder.
Args:
roots (list of RootItem): {ROOT_NAME: ROOT_PATH}
file_path (str)
Returns:
(bool)
"""
file_path = str(file_path).replace("\\", "/").lower()
kalisp marked this conversation as resolved.
Show resolved Hide resolved
for root_item in roots:
if file_path.startswith(root_item.lower()):
return True
self.log.warning(
"Destination '{}' is not in project folder. Skipping"
.format(file_path))
return False

def _are_paths_same(self, src, dst):
src = str(src).replace("\\", "/").lower()
dst = str(dst).replace("\\", "/").lower()

same = src == dst
if same:
self.log.info(
"Source '{}' same as destination '{}'. Skipping."
.format(src, dst))
return same
8 changes: 7 additions & 1 deletion openpype/settings/defaults/project_anatomy/templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,17 @@
"file": "{originalBasename}<.{@frame}><_{udim}>.{ext}",
"path": "{@folder}/{@file}"
},
"source": {
"folder": "{originalBasename}<.{@frame}><_{udim}>.{ext}",
"file": "{originalDirname}",
"path": "{@folder}/{@file}"
},
"__dynamic_keys_labels__": {
"maya2unreal": "Maya to Unreal",
"simpleUnrealTextureHero": "Simple Unreal Texture - Hero",
"simpleUnrealTexture": "Simple Unreal Texture",
"online": "online"
"online": "online",
"source": "source"
}
}
}