Bases: InstancePlugin, OptionalPyblishPluginMixin
Remap all paths in a USD Layer to be relative to its published path
Source code in client/ayon_usd/plugins/publish/integrate_usd_output_processor_remap_relative.py
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
133
134
135
136
137
138
139
140 | class USDOutputProcessorRemapToRelativePaths(pyblish.api.InstancePlugin,
OptionalPyblishPluginMixin):
"""Remap all paths in a USD Layer to be relative to its published path"""
label = "Process USD files to use relative paths"
families = ["usd"]
settings_category = "usd"
# Run just before the Integrator
order = pyblish.api.IntegratorOrder - 0.01
def process(self, instance):
if not self.is_active(instance.data):
return
# Skip instance if not marked for integration
if not instance.data.get("integrate", True):
return
# Some hosts may not have USD libs available but can publish USD data.
# For those we'll log a warning.
if not HAS_USD_LIBS:
self.log.warning(
"Unable to process USD files to relative paths because "
"`pxr` USD libraries could not be imported.")
return
# For each USD representation, process the file.
for representation in instance.data.get("representations", []):
representation: dict
if representation.get("name") != "usd":
continue
# Get expected publish path
published_path = get_instance_expected_output_path(
instance,
representation_name=representation["name"],
ext=representation.get("ext")
)
published_path_root = os.path.dirname(published_path)
self.log.debug(
f"Making USD paths relative to {published_path_root}")
# Process all files of the representation
staging_dir: str = representation.get(
"stagingDir", instance.data.get("stagingDir"))
# Process single file or sequence of the representation
filenames = representation["files"]
if isinstance(filenames, str):
# Single file is stored as `str` in `instance.data["files"]`
filenames = [filenames]
filenames: "list[str]"
for filename in filenames:
path = os.path.join(staging_dir, filename)
self.process_usd(path, start=published_path_root)
# Some instance may have additional transferred files which
# themselves are not a representation. For those we need to look in
# the `instance.data["transfers"]`
for src, dest in instance.data.get("transfers", []):
if not dest.endswith(".usd"):
continue
# Process USD file at `src` and turn all paths relative to
# the `dest` path the file will end up at.
dest_root = os.path.dirname(dest)
self.process_usd(src, start=dest_root)
def process_usd(self, usd_path, start):
"""Process a USD layer making all paths relative to `start`"""
self.log.debug(f"Processing '{usd_path}'")
layer = Sdf.Layer.FindOrOpen(usd_path)
def modify_fn(asset_path: str):
"""Make all absolute non-anchored paths relative to `start`"""
self.log.debug(f"Processing asset path: {asset_path}")
# Do not touch paths already anchored paths
if not os.path.isabs(asset_path):
return asset_path
# Do not touch paths already anchored paths
if asset_path.startswith(RELATIVE_ANCHOR_PREFIXES):
# Already anchored
return asset_path
# Do not touch what we know are AYON URIs
if asset_path.startswith(("ayon://", "ayon+entity://")):
return asset_path
# Consider only files on the same drive, because otherwise no
# 'relative' path exists for the file.
if get_drive(start) != get_drive(asset_path):
# Log a warning if different drive
self.log.warning(
f"USD Asset Path '{asset_path}' can not be made relative"
f" to '{start}' because they are not on the same drive.")
return asset_path
anchored_path = "./" + os.path.relpath(asset_path, start)
# Force forward slashes so that relative paths generated on Windows
# load correctly on e.g. Linux. It also makes the paths consistent
# regardless of platforms
anchored_path = anchored_path.replace("\\", "/")
self.log.debug(f"Anchored path: {anchored_path}")
return anchored_path
# Get all "asset path" specs, sublayer paths and references/payloads.
# Make all the paths relative.
UsdUtils.ModifyAssetPaths(layer, modify_fn)
if layer.dirty:
layer.Save()
|
process_usd(usd_path, start)
Process a USD layer making all paths relative to start
Source code in client/ayon_usd/plugins/publish/integrate_usd_output_processor_remap_relative.py
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
133
134
135
136
137
138
139
140 | def process_usd(self, usd_path, start):
"""Process a USD layer making all paths relative to `start`"""
self.log.debug(f"Processing '{usd_path}'")
layer = Sdf.Layer.FindOrOpen(usd_path)
def modify_fn(asset_path: str):
"""Make all absolute non-anchored paths relative to `start`"""
self.log.debug(f"Processing asset path: {asset_path}")
# Do not touch paths already anchored paths
if not os.path.isabs(asset_path):
return asset_path
# Do not touch paths already anchored paths
if asset_path.startswith(RELATIVE_ANCHOR_PREFIXES):
# Already anchored
return asset_path
# Do not touch what we know are AYON URIs
if asset_path.startswith(("ayon://", "ayon+entity://")):
return asset_path
# Consider only files on the same drive, because otherwise no
# 'relative' path exists for the file.
if get_drive(start) != get_drive(asset_path):
# Log a warning if different drive
self.log.warning(
f"USD Asset Path '{asset_path}' can not be made relative"
f" to '{start}' because they are not on the same drive.")
return asset_path
anchored_path = "./" + os.path.relpath(asset_path, start)
# Force forward slashes so that relative paths generated on Windows
# load correctly on e.g. Linux. It also makes the paths consistent
# regardless of platforms
anchored_path = anchored_path.replace("\\", "/")
self.log.debug(f"Anchored path: {anchored_path}")
return anchored_path
# Get all "asset path" specs, sublayer paths and references/payloads.
# Make all the paths relative.
UsdUtils.ModifyAssetPaths(layer, modify_fn)
if layer.dirty:
layer.Save()
|