Bases: HoudiniExtractorPlugin
Extractor copying files from last published to staging directory.
It works only if instance data includes "last_version_published_files" and there are frames to fix.
The files from last published are based on files which will be extended/fixed for specific frames.
NOTE
This plugin is closely taken from ayon-nuke. It contains some Houdini addon specific logic as various addons may have unique methods for managing staging_dir, expectedFiles and frames.
TODO: It's preferable to to generalize this plugin for broader use and integrate it into ayon-core.
Source code in client/ayon_houdini/plugins/publish/extract_last_published.py
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 | class ExtractLastPublished(plugin.HoudiniExtractorPlugin):
"""Extractor copying files from last published to staging directory.
It works only if instance data includes "last_version_published_files"
and there are frames to fix.
The files from last published are based on files which will be
extended/fixed for specific frames.
NOTE:
This plugin is closely taken from ayon-nuke.
It contains some Houdini addon specific logic as various addons may
have unique methods for managing `staging_dir`, `expectedFiles`
and `frames`.
TODO:
It's preferable to to generalize this plugin for broader use and
integrate it into ayon-core.
"""
order = pyblish.api.ExtractorOrder - 0.1
label = "Extract Last Published"
targets = ["local"] # Same target as `CollectFramesFixDef`
families = ["*"]
def process(self, instance):
frames_to_fix = instance.data.get("frames_to_fix")
if not frames_to_fix:
self.log.debug("Skipping, No frames to fix.")
return
if not instance.data.get("integrate", True):
self.log.debug("Skipping collecting frames to fix data for "
"instance because instance is set to not integrate")
return
last_published = instance.data.get("last_version_published_files")
if not last_published:
self.log.debug("Skipping, No last publish found.")
return
last_published_and_frames = collect_frames(last_published)
if not all(last_published_and_frames.values()):
self.log.debug("Skipping, No file sequence found in the "
"last version published files.")
return
expected_filepaths = self.get_expected_files_and_staging_dir(instance)
# We assume all outputs of this one instance end up in one folder, and
# hence there being just one 'staging dir'. We will take the first
# expected file's folder as staging directory.
staging_dir: str = os.path.dirname(expected_filepaths[0])
os.makedirs(staging_dir, exist_ok=True)
expected_and_frames = collect_frames(expected_filepaths)
frames_and_expected = {v: k for k, v in expected_and_frames.items()}
frames_to_fix = clique.parse(frames_to_fix, "{ranges}")
anatomy = instance.context.data["anatomy"]
# TODO: This currently copies ALL frames from the last version instead
# of only those within the frame range we're currently looking to
# publish. It should instead, iterate over all expected frames for
# current instance, exclude all "to fix" frames and copy the
# other existing ones.
for file_path, frame in last_published_and_frames.items():
if frame is None:
continue
# Last published filepath
file_path = anatomy.fill_root(file_path)
if not os.path.exists(file_path):
continue
# Expected filepath for this render for that frame
target_filepath: str = frames_and_expected.get(frame)
if not target_filepath:
continue
# Copy only the frames that we won't render.
if frame in frames_to_fix:
continue
self.log.debug(f"Copying '{file_path}' -> '{target_filepath}'")
shutil.copy(file_path, target_filepath)
def get_expected_files_and_staging_dir(self, instance):
"""Get expected file names or frames.
This method includes Houdini specific code.
Args:
instance (pyblish.api.Instance): The instance to publish.
Returns:
list[str]: Full paths to the expected filepaths for this publish
instance.
"""
expected_filepaths: list[str] = []
expected_files = instance.data.get("expectedFiles", [])
# 'expectedFiles' are preferred over 'frames'
if expected_files:
# Products with expected files
# This can be Render products or submitted cache to farm.
for expected in expected_files:
# expected.values() is a list of lists
expected_filepaths.extend(sum(expected.values(), []))
else:
# Products with frames or single file.
frames = instance.data.get("frames", "")
staging_dir: str = instance.data.get("stagingDir")
if isinstance(frames, str):
# single file.
expected_filepaths.append("{}/{}".format(staging_dir, frames))
else:
# list of frame.
expected_filepaths.extend(
["{}/{}".format(staging_dir, f) for f in frames]
)
return expected_filepaths
|
get_expected_files_and_staging_dir(instance)
Get expected file names or frames.
This method includes Houdini specific code.
Parameters:
| Name | Type | Description | Default |
instance | Instance | | required |
Returns:
| Type | Description |
| | list[str]: Full paths to the expected filepaths for this publish instance. |
Source code in client/ayon_houdini/plugins/publish/extract_last_published.py
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 | def get_expected_files_and_staging_dir(self, instance):
"""Get expected file names or frames.
This method includes Houdini specific code.
Args:
instance (pyblish.api.Instance): The instance to publish.
Returns:
list[str]: Full paths to the expected filepaths for this publish
instance.
"""
expected_filepaths: list[str] = []
expected_files = instance.data.get("expectedFiles", [])
# 'expectedFiles' are preferred over 'frames'
if expected_files:
# Products with expected files
# This can be Render products or submitted cache to farm.
for expected in expected_files:
# expected.values() is a list of lists
expected_filepaths.extend(sum(expected.values(), []))
else:
# Products with frames or single file.
frames = instance.data.get("frames", "")
staging_dir: str = instance.data.get("stagingDir")
if isinstance(frames, str):
# single file.
expected_filepaths.append("{}/{}".format(staging_dir, frames))
else:
# list of frame.
expected_filepaths.extend(
["{}/{}".format(staging_dir, f) for f in frames]
)
return expected_filepaths
|