1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24
25 #include "pxr/pxr.h"
26 #include "pxr/usd/pcp/namespaceEdits.h"
27 #include "pxr/usd/pcp/debugCodes.h"
28 #include "pxr/usd/pcp/dependencies.h"
29 #include "pxr/usd/pcp/layerStack.h"
30 #include "pxr/base/trace/trace.h"
31
32 #include <algorithm>
33 #include <utility>
34 #include <vector>
35
36 using std::make_pair;
37 using std::pair;
38 using std::vector;
39
40 PXR_NAMESPACE_OPEN_SCOPE
41
TF_REGISTRY_FUNCTION(TfEnum)42 TF_REGISTRY_FUNCTION(TfEnum)
43 {
44 TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditPath);
45 TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditInherit);
46 TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditSpecializes);
47 TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditReference);
48 TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditPayload);
49 TF_ADD_ENUM_NAME(PcpNamespaceEdits::EditRelocate);
50 }
51
52 static bool
_IsInvalidEdit(const SdfPath & oldPath,const SdfPath & newPath)53 _IsInvalidEdit(const SdfPath& oldPath, const SdfPath& newPath)
54 {
55 // Can't reparent an object to be a descendant of itself.
56 // See testPcpRegressionBugs_bug109700 for more details
57 // on how this can happen.
58 return newPath.HasPrefix(oldPath);
59 }
60
61 static PcpNamespaceEdits::LayerStackSites &
_GetLayerStackSitesForEdit(PcpNamespaceEdits * result,const SdfPath & oldPath,const SdfPath & newPath)62 _GetLayerStackSitesForEdit(
63 PcpNamespaceEdits* result,
64 const SdfPath& oldPath,
65 const SdfPath& newPath)
66 {
67 // Catch any invalid fixups that have been requested here and
68 // store them away in invalidLayerStackSites so that consumers
69 // can be informed about them.
70 return _IsInvalidEdit(oldPath, newPath) ?
71 result->invalidLayerStackSites : result->layerStackSites;
72 }
73
74 static bool
_RelocatesMapContainsPrimOrDescendant(const SdfRelocatesMapProxy & reloMap,const SdfPath & primPath)75 _RelocatesMapContainsPrimOrDescendant(
76 const SdfRelocatesMapProxy& reloMap,
77 const SdfPath& primPath)
78 {
79 TF_FOR_ALL(it, reloMap) {
80 if (it->first.HasPrefix(primPath) ||
81 it->second.HasPrefix(primPath)) {
82 return true;
83 }
84 }
85
86 return false;
87 }
88
89 static void
_AddRelocateEditsForLayerStack(PcpNamespaceEdits * result,const PcpLayerStackPtr & layerStack,size_t cacheIndex,const SdfPath & oldRelocatePath,const SdfPath & newRelocatePath)90 _AddRelocateEditsForLayerStack(
91 PcpNamespaceEdits* result,
92 const PcpLayerStackPtr& layerStack,
93 size_t cacheIndex,
94 const SdfPath& oldRelocatePath,
95 const SdfPath& newRelocatePath)
96 {
97 if (!result) {
98 return;
99 }
100
101 // Record a relocates edit for each layer stack site if any prim spec
102 // at that site has a relocates statement that contains oldRelocatePath.
103 //
104 // XXX: If this is a performance issue, PcpLayerStack could keep track
105 // of a finer-grained table to avoid scanning through every prim
106 // with relocates here.
107 const SdfPathVector& relocatePrimPaths =
108 layerStack->GetPathsToPrimsWithRelocates();
109 TF_FOR_ALL(pathIt, relocatePrimPaths) {
110 TF_FOR_ALL(layerIt, layerStack->GetLayers()) {
111 const SdfPrimSpecHandle prim = (*layerIt)->GetPrimAtPath(*pathIt);
112 // The relocate we discovered in the layerStack at this path
113 // doesn't necessarily mean there is a spec with a relocate
114 // in every layer. Skip layers that don't have a spec with
115 // a relocate.
116 if (!prim || !prim->HasRelocates()) {
117 continue;
118 }
119
120 if (_RelocatesMapContainsPrimOrDescendant(
121 prim->GetRelocates(), oldRelocatePath)) {
122
123 PcpNamespaceEdits::LayerStackSites& layerStackSites =
124 _GetLayerStackSitesForEdit(
125 result, oldRelocatePath, newRelocatePath);
126
127 layerStackSites.resize(layerStackSites.size() + 1);
128 PcpNamespaceEdits::LayerStackSite& site =
129 layerStackSites.back();
130 site.cacheIndex = cacheIndex;
131 site.type = PcpNamespaceEdits::EditRelocate;
132 site.sitePath = *pathIt;
133 site.oldPath = oldRelocatePath;
134 site.newPath = newRelocatePath;
135 site.layerStack = layerStack;
136
137 // Since we record edits at the granularity of layer stacks,
138 // we can bail out once we've determined that at least one
139 // prim in this layer stack needs relocates edits.
140 break;
141 }
142 }
143 }
144 }
145
146 static SdfPath
_TranslatePathAndTargetPaths(const PcpNodeRef & node,const SdfPath & pathIn)147 _TranslatePathAndTargetPaths(
148 const PcpNodeRef& node,
149 const SdfPath& pathIn)
150 {
151 SdfPath path = node.GetMapToParent().MapSourceToTarget(pathIn);
152
153 if (path == pathIn) {
154 // We don't want to map paths that aren't explicitly allowed. The
155 // </> -> </> mapping should not be attempted.
156 const SdfPath absRoot = SdfPath::AbsoluteRootPath();
157 if (node.GetMapToParent().MapSourceToTarget(absRoot) == absRoot) {
158 return SdfPath();
159 }
160 }
161
162 SdfPathVector targetPaths;
163 path.GetAllTargetPathsRecursively(&targetPaths);
164 for (const auto& targetPath : targetPaths) {
165 // Do allow translation via </> -> </> in target paths.
166 const SdfPath translatedTargetPath =
167 node.GetMapToParent().MapSourceToTarget(targetPath);
168 if (translatedTargetPath.IsEmpty()) {
169 return SdfPath();
170 }
171 path = path.ReplacePrefix(targetPath, translatedTargetPath);
172 }
173
174 return path;
175 }
176
177 // Translate *oldNodePath and *newNodePath to node's parent's namespace.
178 // Request any necessary edits to relocations used for the translation.
179 static void
_TranslatePathsAndEditRelocates(PcpNamespaceEdits * result,const PcpNodeRef & node,size_t cacheIndex,SdfPath * oldNodePath,SdfPath * newNodePath)180 _TranslatePathsAndEditRelocates(
181 PcpNamespaceEdits* result,
182 const PcpNodeRef& node,
183 size_t cacheIndex,
184 SdfPath* oldNodePath,
185 SdfPath* newNodePath)
186 {
187 // Map the path in the node namespace to the parent's namespace. Note
188 // that these are not the namespace parent paths, they're the paths in
189 // the *node's parent's* namespace.
190 SdfPath oldParentPath = _TranslatePathAndTargetPaths(node, *oldNodePath);
191 SdfPath newParentPath = _TranslatePathAndTargetPaths(node, *newNodePath);
192
193 // Check if there are relocations that need fixing. Since relocates only
194 // target prims, we can bail out early if the translated path isn't a
195 // prim path. Note that we just check oldNodePath, since newNodePath may
196 // be empty if the namespace edit is a deletion.
197 const bool mayAffectRelocates = oldNodePath->IsPrimPath();
198 if (!mayAffectRelocates) {
199 *oldNodePath = oldParentPath;
200 *newNodePath = newParentPath;
201 return;
202 }
203
204 //
205 // At this point, if oldParentPath and newParentPath refer to a
206 // relocated prim or a descendant of a relocated prim, they will have
207 // already had the relevant relocations from the parent's layerStack
208 // applied.
209 // Check if one of these relocations affected oldParentPath.
210 //
211 const PcpLayerStackPtr& layerStack =
212 node.GetParentNode().GetLayerStack();
213
214 // Since oldParentPath and newParentPath are post-relocation,
215 // we'll use the targetToSource table to check for applicable
216 // relocations.
217 const SdfRelocatesMap& relocates = layerStack->GetRelocatesTargetToSource();
218
219 // Find the relocation, which should be the entry whose key is the
220 // longest prefix of oldParentPath.
221 SdfRelocatesMap::const_iterator i =
222 SdfPathFindLongestPrefix(relocates, oldParentPath);
223
224 if (i != relocates.end()) {
225 const SdfPath & reloTargetPath = i->first;
226 const SdfPath & reloSourcePath = i->second;
227
228 // Un-relocate oldParentPath and newParentPath.
229 // We will use these paths to decide how to fix the
230 // relocation that applied to them.
231 const SdfPath unrelocatedOldParentPath =
232 oldParentPath.ReplacePrefix(reloTargetPath, reloSourcePath);
233 const SdfPath unrelocatedNewParentPath =
234 newParentPath.ReplacePrefix(reloTargetPath, reloSourcePath);
235
236 bool reloTargetNeedsEdit = true;
237
238 // Old path is relocated in this layer stack. We might need to
239 // change the relocation as part of the namespace edit. If so
240 // we'll relocate the new path differently from the old path.
241 // Relocating the new parent path depends on various stuff.
242 if (newParentPath.IsEmpty()) {
243 // Removing the object or can't map across the arc.
244 // Nothing to translate, but need to add a relocation edit
245 // to indicate that relocations that involve prims at and
246 // below oldParentPath need to be fixed.
247 _AddRelocateEditsForLayerStack(
248 result, layerStack, cacheIndex,
249 oldParentPath, newParentPath);
250 }
251 else if (oldNodePath->GetParentPath() !=
252 newNodePath->GetParentPath()) {
253 // Reparenting within the arc's root. We'll fix the
254 // relocation source but not the target.
255 _AddRelocateEditsForLayerStack(
256 result, layerStack, cacheIndex,
257 unrelocatedOldParentPath, unrelocatedNewParentPath);
258
259 reloTargetNeedsEdit = false;
260 }
261 else {
262 // Renaming. We must fix the relocation source path,
263 // and potentially also the relocation target path
264 // (if the relocation keeps the prim name).
265 _AddRelocateEditsForLayerStack(
266 result, layerStack, cacheIndex,
267 unrelocatedOldParentPath, unrelocatedNewParentPath);
268
269 // If the prim being renamed was the target of a relocation
270 // in this layer stack (i.e., oldParentPath == reloTargetPath)
271 // and the relocation keeps the prim name, then
272 // we'll fix the relocation by changing the final prim
273 // name in both the source and target. So the new parent
274 // path is the old parent path with the name changed.
275 if (reloTargetPath == oldParentPath &&
276 reloSourcePath.GetNameToken() == reloTargetPath.GetNameToken()) {
277 // Relocate the new path.
278 newParentPath = reloTargetPath
279 .ReplaceName(newNodePath->GetNameToken());
280
281 _AddRelocateEditsForLayerStack(
282 result, layerStack, cacheIndex,
283 reloTargetPath, newParentPath);
284 }
285 else {
286 // The relocation changes the prim name. We've no
287 // reason to try to adjust the target's name but we
288 // should change the source name.
289 reloTargetNeedsEdit = false;
290 }
291 }
292
293 if (!reloTargetNeedsEdit) {
294 // Since the relocation target isn't changing, this node
295 // 'absorbs' the namespace edit -- no layer stacks that
296 // reference this layer stack need to be updated. So,
297 // we can stop traversing the graph looking for things
298 // that need to be fixed. Indicate that to consumers by
299 // setting newParentPath = oldParentPath.
300 newParentPath = oldParentPath;
301 }
302 }
303 else {
304 // In this case, oldParentPath and newParentPath do not refer to a
305 // relocated prim. However, there may be descendants of oldParentPath
306 // that have been relocated, requiring relocates to be fixed up.
307 _AddRelocateEditsForLayerStack(
308 result, layerStack, cacheIndex,
309 oldParentPath, newParentPath);
310 }
311
312 *oldNodePath = oldParentPath;
313 *newNodePath = newParentPath;
314 }
315
316 static bool
_AddLayerStackSite(PcpNamespaceEdits * result,const PcpNodeRef & node,size_t cacheIndex,SdfPath * oldNodePath,SdfPath * newNodePath)317 _AddLayerStackSite(
318 PcpNamespaceEdits* result,
319 const PcpNodeRef& node,
320 size_t cacheIndex,
321 SdfPath* oldNodePath,
322 SdfPath* newNodePath)
323 {
324 bool final = false;
325
326 // Save the old paths.
327 SdfPath oldPath = *oldNodePath, newPath = *newNodePath;
328
329 // Translate the paths to the parent.
330 _TranslatePathsAndEditRelocates(result, node, cacheIndex,
331 oldNodePath, newNodePath);
332
333 // The site is the parent's path.
334 SdfPath sitePath = *oldNodePath;
335
336 // Compute the type of edit.
337 PcpNamespaceEdits::EditType type;
338 if (node.GetArcType() == PcpArcTypeRelocate) {
339 // Ignore.
340 *oldNodePath = oldPath;
341 *newNodePath = newPath;
342 TF_DEBUG(PCP_NAMESPACE_EDIT)
343 .Msg(" - not final. skipping relocate\n");
344 return final;
345 }
346 else if (*oldNodePath == *newNodePath) {
347 // The edit is absorbed by this layer stack, so there's
348 // no need to propagate the edit any further.
349 TF_DEBUG(PCP_NAMESPACE_EDIT)
350 .Msg(" - final. stopping at node where path is unaffected\n");
351 final = true;
352 return final;
353 }
354 else if (oldNodePath->IsPrimPath() && !node.IsDueToAncestor()) {
355 final = true;
356 TF_DEBUG(PCP_NAMESPACE_EDIT)
357 .Msg(" - final. direct arc fixup\n");
358 switch (node.GetArcType()) {
359 case PcpArcTypeInherit:
360 type = PcpNamespaceEdits::EditInherit;
361 break;
362
363 case PcpArcTypeSpecialize:
364 type = PcpNamespaceEdits::EditSpecializes;
365 break;
366
367 case PcpArcTypeReference:
368 type = PcpNamespaceEdits::EditReference;
369 break;
370
371 case PcpArcTypePayload:
372 type = PcpNamespaceEdits::EditPayload;
373 break;
374
375 case PcpArcTypeVariant:
376 // Do nothing. The variant prim has no name (and therefore
377 // nothing referring to the name) so there's nothing to do.
378 return final;
379
380 default:
381 TF_VERIFY(false, "Unexpected arc type %d", node.GetArcType());
382 return final;
383 }
384 }
385 else {
386 // NamespaceEditPath the parent.
387 type = PcpNamespaceEdits::EditPath;
388 oldPath = *oldNodePath;
389 newPath = *newNodePath;
390 }
391
392 if (result) {
393 // Add a new layer stack site element at the end.
394 PcpNamespaceEdits::LayerStackSites& layerStackSites =
395 _GetLayerStackSitesForEdit(result, oldPath, newPath);
396
397 layerStackSites.resize(layerStackSites.size() + 1);
398 PcpNamespaceEdits::LayerStackSite& site = layerStackSites.back();
399
400 // Fill in the site.
401 site.cacheIndex = cacheIndex;
402 site.type = type;
403 site.sitePath = sitePath;
404 site.oldPath = oldPath;
405 site.newPath = newPath;
406 site.layerStack = node.GetParentNode().GetLayerStack();
407
408 TF_DEBUG(PCP_NAMESPACE_EDIT)
409 .Msg(" - adding layer stack edit <%s> -> <%s>\n",
410 site.oldPath.GetText(),
411 site.newPath.GetText());
412 }
413
414 return final;
415 }
416
417 PcpNamespaceEdits
PcpComputeNamespaceEdits(const PcpCache * primaryCache,const std::vector<PcpCache * > & caches,const SdfPath & curPath,const SdfPath & newPath,const SdfLayerHandle & relocatesLayer)418 PcpComputeNamespaceEdits(
419 const PcpCache *primaryCache,
420 const std::vector<PcpCache*>& caches,
421 const SdfPath& curPath,
422 const SdfPath& newPath,
423 const SdfLayerHandle& relocatesLayer)
424 {
425 TRACE_FUNCTION();
426
427 PcpNamespaceEdits result;
428 SdfPathVector depPaths;
429
430 if (caches.empty()) {
431 return result;
432 }
433 const PcpLayerStackRefPtr primaryLayerStack = primaryCache->GetLayerStack();
434
435 // We find dependencies using prim paths. Compute the closest prim
436 // path to curPath.
437 const SdfPath primPath = curPath.GetPrimPath();
438
439 // Verify that a prim index at primPath exists.
440 if (!primaryCache->FindPrimIndex(primPath)) {
441 TF_CODING_ERROR("No prim index computed for %s<%s>\n",
442 TfStringify(primaryLayerStack->GetIdentifier()).c_str(),
443 curPath.GetText());
444 return result;
445 }
446
447 // Handle trivial case.
448 if (curPath == newPath) {
449 return result;
450 }
451
452 // Find cache sites one cache at a time. We can't simply check if a
453 // site uses (primaryLayerStack, primPath) -- we must check if it uses any
454 // site at primPath with an intersecting layer stack. Even that's not
455 // quite right -- we only care if the layer stacks intersect where a
456 // spec already exists (see bug 59216). And, unfortunately, that's
457 // not right either -- if (primaryLayerStack, primPath) has no specs at all
458 // (because opinions come across an ancestor arc) then we're doing a
459 // relocation and only sites using primPath in a layer stack that
460 // includes relocatesLayer are affected. We special case the last
461 // case. The earlier cases we handle by looking for any site using
462 // any spec at the namespace edited site.
463
464 // Find all specs at (primaryLayerStack, primPath).
465 SdfSiteVector primSites;
466 PcpComposeSitePrimSites(primaryLayerStack, primPath, &primSites);
467
468 // Find the nodes corresponding to primPath in any relevant layer
469 // stack over all caches.
470 typedef std::pair<size_t, PcpNodeRef> CacheNodePair;
471 std::set<CacheNodePair> nodes, descendantNodes;
472
473 struct _CacheNodeHelper {
474 static void InsertCacheNodePair(size_t cacheIdx, PcpNodeRef node,
475 std::set<CacheNodePair>* nodes)
476 {
477 // If a dependency on primPath was introduced via a variant
478 // node (e.g., a prim authored locally in a variant), we store
479 // the node that introduced the variant as this truly represents
480 // the namespace edited site.
481 while (node && node.GetArcType() == PcpArcTypeVariant) {
482 node = node.GetParentNode();
483 }
484
485 if (TF_VERIFY(node)) {
486 nodes->insert(std::make_pair(cacheIdx, node));
487 }
488 }
489 };
490
491 if (primSites.empty()) {
492 // This is the relocation case.
493 // We'll find every site using (someLayerStack, primPath)
494 // where someLayerStack is any layer stack that includes
495 // relocatesLayer.
496 for (size_t cacheIndex = 0, n = caches.size();
497 cacheIndex != n; ++cacheIndex) {
498 PcpCache* cache = caches[cacheIndex];
499
500 // Store the node for each dependent site.
501 PcpDependencyVector deps =
502 cache->FindSiteDependencies(
503 relocatesLayer, primPath,
504 PcpDependencyTypeAnyNonVirtual,
505 /* recurseOnSite */ true,
506 /* recurseOnIndex */ true,
507 /* filter */ true);
508 auto visitNodeFn = [&](const SdfPath &depIndexPath,
509 const PcpNodeRef &node) {
510 _CacheNodeHelper::InsertCacheNodePair(cacheIndex,
511 node, &nodes);
512 };
513 for(const PcpDependency &dep: deps) {
514 Pcp_ForEachDependentNode(dep.sitePath, relocatesLayer,
515 dep.indexPath,
516 *cache, visitNodeFn);
517 }
518 }
519 }
520 else {
521 // We find dependent sites by looking for used prim specs.
522 for (size_t cacheIndex = 0, n = caches.size();
523 cacheIndex != n; ++cacheIndex) {
524 PcpCache* cache = caches[cacheIndex];
525
526 // Store the node for each dependent site.
527 for(const SdfSite& primSite: primSites) {
528 PcpDependencyVector deps =
529 cache->FindSiteDependencies(
530 primSite.layer, primPath,
531 PcpDependencyTypeAnyNonVirtual,
532 /* recurseOnSite */ false,
533 /* recurseOnIndex */ false,
534 /* filter */ true);
535 auto visitNodeFn = [&](const SdfPath &depIndexPath,
536 const PcpNodeRef &node) {
537 TF_DEBUG(PCP_NAMESPACE_EDIT)
538 .Msg(" found dep node: <%s> -> <%s> %s\n",
539 depIndexPath.GetText(),
540 node.GetPath().GetText(),
541 PcpDependencyFlagsToString(
542 PcpClassifyNodeDependency(node)).c_str());
543 _CacheNodeHelper::InsertCacheNodePair(cacheIndex,
544 node, &nodes);
545 };
546 for(const PcpDependency &dep: deps) {
547 Pcp_ForEachDependentNode(dep.sitePath, primSite.layer,
548 dep.indexPath,
549 *cache, visitNodeFn);
550 }
551 }
552
553 // Special case for direct inherits. An inherit can target a
554 // descendant of curPath and we must fix up those inherits.
555 // References and payloads can't target a non-root prim so we
556 // don't have to worry about those.
557 //
558 // XXX: We only do this in this cache. Inherits in this
559 // cache can definitely see the namespace edit so
560 // they must be fixed, but can't inherits outside
561 // this cache also see the namespace edit?
562 if (cache == primaryCache && curPath.IsPrimPath()) {
563
564 SdfPathSet descendentPrimPaths;
565
566 const PcpDependencyFlags depMask =
567 PcpDependencyTypeDirect | PcpDependencyTypeNonVirtual;
568
569 // Get all of the direct dependents on the namespace edited
570 // site and anything below.
571 for (const PcpDependency &dep:
572 primaryCache->FindSiteDependencies(
573 primaryLayerStack, primPath, depMask,
574 /* recurseOnSite */ true,
575 /* recurseOnIndex */ false,
576 /* filter */ true)) {
577 if (dep.indexPath.IsPrimPath()) {
578 descendentPrimPaths.insert(dep.indexPath);
579 }
580 }
581
582 // Remove the direct dependents on the site itself.
583 for (const PcpDependency &dep:
584 primaryCache->FindSiteDependencies(
585 primaryLayerStack, primPath, depMask,
586 /* recurseOnSite */ false,
587 /* recurseOnIndex */ false,
588 /* filter */ true)) {
589 descendentPrimPaths.erase(dep.indexPath);
590 }
591
592 // Check each direct dependent site for inherits pointing
593 // at this cache's layer stack. Make sure to skip ancestral
594 // nodes, since the code that handles direct inherits below
595 // needs to have the nodes where the inherits are introduced.
596 for (const SdfPath& descendentPrimPath : descendentPrimPaths) {
597 // We were just told this prim index is a dependency
598 // so it certainly should exist.
599 const PcpPrimIndex *index =
600 primaryCache->FindPrimIndex(descendentPrimPath);
601 if (TF_VERIFY(index, "Reported descendent dependency "
602 "lacks a prim index")) {
603 for (const PcpNodeRef &node:
604 index->GetNodeRange(PcpRangeTypeInherit)) {
605 if (node.GetLayerStack() == primaryLayerStack &&
606 !node.GetPath().IsRootPrimPath() &&
607 !node.IsDueToAncestor()) {
608 // Found an inherit using a descendant.
609 descendantNodes.insert(
610 std::make_pair(cacheIndex, node));
611 }
612 }
613 }
614 }
615 }
616 }
617 }
618
619 // We now have every node representing the namespace edited site in
620 // every graph in every cache in caches that uses that site. We now
621 // need to convert them into something the client can use. There are
622 // two kinds of sites from the client's point of view:
623 //
624 // 1) Composed sites. Composed sites are stored in
625 // result.cacheSites. They represent composed namespace
626 // that is being namespace edited, i.e. the object is
627 // being renamed, reparented, renamed and reparented, or
628 // removed. They're identified by a cache (index) and path.
629 //
630 // 2) Uncomposed sites. Uncomposed sites are stored in
631 // result.layerStackSites. Each site is a layer stack and a
632 // path (the site path) -- all Sd specs at the path in any
633 // layer in the layer stack must be fixed up the same way.
634 //
635 // We don't include composed sites here just because they have a
636 // reference (or payload or inherit) to a site that's being namespace
637 // edited. The reference itself absorbs the namespace edit, so the
638 // object with the reference doesn't need a namespace edit. For
639 // example, if </A> references </B> and we rename </B> to </C> we need
640 // to fix the reference on </A> but we don't need to change the name
641 // of </A>. So </B> is added to cacheSites but </A> is not.
642 //
643 // To find composed sites we simply include one for every node that
644 // doesn't have any direct (i.e. non-ancestral) reference, inherit, or
645 // payload on the traversal of the graph from node to the root. The
646 // old and new paths are found by translating the edited site's old
647 // and new paths from the node to the root.
648 //
649 // We expect the caller (i.e. Csd) to consume cacheSites to fix up
650 // connections and targets that point to anything in cacheSites. It
651 // must also fix up relocations involving old paths in cacheSites.
652 //
653 // Uncomposed sites are found by walking the graph from node to root
654 // for each node. Every node is an uncomposed site. If we find a
655 // a direct (i.e. non-ancestral) reference, inherit, or payload then
656 // we store the referencing site and stop the traversal because the
657 // reference absorbs the namespace edit.
658 //
659 // The trick is to do path translation correctly while traversing the
660 // graph. The easy but wrong way is to translate the path from node
661 // to root once, then translate the root paths to each node in the
662 // traversal. That doesn't work for the new path if we need to fix
663 // any relocation, reference, inherit, or payload along the traversal
664 // because the mapping functions will not have the new mapping. Using
665 // the example above </A> references </B> and we rename </B> to </C>.
666 // We can't map path </C> across the existing reference because it
667 // maps </A> -> </B>. If we try we'll just get the empty path. So
668 // we translate the path using mapToParent across each arc and we
669 // account for relocations as necessary.
670 //
671 // If we're removing then we must also remove every object using any
672 // descendant of the namespace edited prim. (This only applies to
673 // prims since non-prims can't have arcs.) This cleans up the layers
674 // in a way that users expect. Note, however, that we remove objects
675 // even if they're provided via other arcs. That could be unexpected
676 // but it doesn't normally happen. We don't find these descendants
677 // during traversal; instead we find them separately by getting sites
678 // using any prim spec that's a descendant of the namespace edited
679 // object.
680 //
681 // Similar to removing, if we reparent a descendant of a referenced
682 // (or inherited or payloaded) prim outside of the arc then it's as
683 // if the object was removed as far as the referencing site is
684 // concerned.
685 //
686 // Uncomposed sites have an edit type associated with them, along
687 // with an old path and a new path. The type may be a namespace edit
688 // (in which case the site path and the old path are the same); an
689 // edit to the references, inherits, or payload where old path must
690 // be replaced with new path; or a relocation where we must replace
691 // old path with new path in every relocation table on every ancestor.
692 // These edits must be applied directly to the Sd objects. If we know
693 // there are no opinions to fix at a given uncomposed site we don't
694 // have to record the site (but may anyway).
695
696 // XXX: We need to report errors, too. There are various edits
697 // that can't be represented and we should detect them and
698 // call them out. Examples are:
699 // 1) Reparent a referenced/payloaded prim (e.g. /B ->
700 // /X/B). We can't target a non-root prim.
701 // 2) Rename a prim into namespace already used upstream.
702 // E.g. </A> references </B>, </A/Y> exists and so
703 // does </B/X> -- rename </B/X> to </B/Y>. Doing so
704 // would cause </A/Y> to pull in </B/Y>, probably
705 // unexpectedly.
706 // 3) Rename a prim into namespace that's salted earth
707 // upstream. E.g. </A> references </B>, </A> relocates
708 // </A/Y> to </A/Z> and </B/X> exists -- rename </B/X>
709 // to </B/Y>. Doing so would cause </B/Y> to map to
710 // the salted earth </A/Y>.
711 // XXX: Should we be doing (layer,path) sites? If we have
712 // intersecting layer stacks we might do the same spec
713 // twice. Csd is aware of this so it's okay for now.
714
715 // Walk the graph for each node.
716 typedef PcpNamespaceEdits::LayerStackSites LayerStackSites;
717 typedef PcpNamespaceEdits::LayerStackSite LayerStackSite;
718 typedef PcpNamespaceEdits::CacheSite CacheSite;
719 std::set<PcpLayerStackSite> sites;
720 for (const auto& cacheAndNode : nodes) {
721 size_t cacheIndex = cacheAndNode.first;
722 PcpNodeRef node = cacheAndNode.second;
723 SdfPath oldNodePath = curPath;
724 SdfPath newNodePath = newPath;
725
726 TF_DEBUG(PCP_NAMESPACE_EDIT)
727 .Msg("\n processing node:\n"
728 " cache: %s\n"
729 " node.type: %s\n"
730 " node.path: <%s>\n"
731 " node.rootPath: <%s>\n"
732 " node.layerStack: %s\n"
733 " curPath: <%s>\n"
734 " newPath: <%s>\n"
735 " oldNodePath: <%s>\n"
736 " newNodePath: <%s>\n",
737 TfStringify( caches[cacheIndex]
738 ->GetLayerStack()->GetIdentifier()).c_str(),
739 TfStringify(node.GetArcType()).c_str(),
740 node.GetPath().GetText(),
741 node.GetRootNode().GetPath().GetText(),
742 TfStringify(node.GetLayerStack()->GetIdentifier()).c_str(),
743 curPath.GetText(),
744 newPath.GetText(),
745 oldNodePath.GetText(),
746 newNodePath.GetText()
747 );
748
749 // Handle the node itself. Note that the node, although representing
750 // the namespace edited site, can appear in different layer stacks.
751 // This happens when we have two scenes sharing a layer. If we edit
752 // in the shared layer then we must do the corresponding edit in each
753 // of the scene's layer stacks.
754 if (sites.insert(node.GetSite()).second) {
755 LayerStackSites& layerStackSites =
756 _GetLayerStackSitesForEdit(&result, oldNodePath, newNodePath);
757 layerStackSites.resize(layerStackSites.size()+1);
758 {
759 LayerStackSite& site = layerStackSites.back();
760 site.cacheIndex = cacheIndex;
761 site.type = PcpNamespaceEdits::EditPath;
762 site.sitePath = oldNodePath;
763 site.oldPath = oldNodePath;
764 site.newPath = newNodePath;
765 site.layerStack = node.GetLayerStack();
766 // Drop the 'site' reference here since the call to
767 // _AddRelocateEditsForLayerStack can invalidate the reference
768 // from layerStackSites, when it resizes the vector.
769 }
770 _AddRelocateEditsForLayerStack(
771 &result, node.GetLayerStack(), cacheIndex,
772 oldNodePath, newNodePath);
773 }
774
775 // Handle each arc from node to the root.
776 while (node.GetParentNode()) {
777 TF_DEBUG(PCP_NAMESPACE_EDIT)
778 .Msg(" - traverse to parent of <%s>. <%s> -> <%s>\n",
779 node.GetPath().GetText(),
780 oldNodePath.GetText(),
781 newNodePath.GetText());
782
783 // Add site to result if we haven't handled it before, and
784 // translate paths to parent node.
785 const bool newSite =
786 sites.insert(node.GetParentNode().GetSite()).second;
787
788 if (_AddLayerStackSite(
789 newSite ? &result : nullptr,
790 node, cacheIndex, &oldNodePath, &newNodePath)) {
791 // Reached a direct arc, so we don't have to continue.
792 // The composed object will continue to exist at the
793 // same path, with the arc target updated.
794 TF_DEBUG(PCP_NAMESPACE_EDIT)
795 .Msg(" - done! fixed direct arc.\n");
796 break;
797 }
798
799 // Next node.
800 node = node.GetParentNode();
801 }
802
803 // If we made it all the way to the root then we have a cacheSite.
804 if (!node.GetParentNode()) {
805 if (!_IsInvalidEdit(oldNodePath, newNodePath)) {
806 TF_DEBUG(PCP_NAMESPACE_EDIT)
807 .Msg(" - adding cacheSite <%s> -> <%s>\n",
808 oldNodePath.GetText(), newNodePath.GetText());
809 result.cacheSites.resize(result.cacheSites.size() + 1);
810 CacheSite& cacheSite = result.cacheSites.back();
811 cacheSite.cacheIndex = cacheIndex;
812 cacheSite.oldPath = oldNodePath;
813 cacheSite.newPath = newNodePath;
814 }
815 }
816 }
817
818 // Helper functions.
819 struct _Helper {
820 // Returns true if sites contains site or any ancestor of site.
821 static bool HasSite(const std::map<PcpLayerStackSite, size_t>& sites,
822 const PcpLayerStackSite& site)
823 {
824 std::map<PcpLayerStackSite, size_t>::const_iterator i =
825 sites.lower_bound(site);
826 if (i != sites.end() && i->first == site) {
827 // Site exists in sites.
828 return true;
829 }
830 if (i == sites.begin()) {
831 // Site comes before any other site so it's not in sites.
832 return false;
833 }
834 --i;
835 if (site.layerStack != i->first.layerStack) {
836 // Closest site is in a different layer stack.
837 return false;
838 }
839 if (site.path.HasPrefix(i->first.path)) {
840 // Ancestor exists.
841 return true;
842 }
843 // Neither site nor any ancestor of it is in sites.
844 return false;
845 }
846 };
847
848 // If we're removing a prim then also collect every uncomposed site
849 // that uses a descendant of the namespace edited site.
850 if (newPath.IsEmpty() && curPath.IsPrimPath()) {
851 std::map<PcpLayerStackSite, size_t> descendantSites;
852
853 // Make a set of sites we already know have direct arcs to
854 // descendants. We don't want to remove those but we may
855 // want to remove their descendants.
856 std::set<PcpLayerStackSite> doNotRemoveSites;
857 for (const auto& cacheAndNode : descendantNodes) {
858 const PcpNodeRef& node = cacheAndNode.second;
859 doNotRemoveSites.insert(node.GetParentNode().GetSite());
860 }
861
862 for (size_t cacheIndex = 0, n = caches.size();
863 cacheIndex != n; ++cacheIndex) {
864 PcpCache* cache = caches[cacheIndex];
865
866 TF_DEBUG(PCP_NAMESPACE_EDIT)
867 .Msg("- dep cache: %s\n",
868 TfStringify( cache->GetLayerStack()->GetIdentifier()).c_str());
869
870 std::set<PcpLayerStackPtr> layerStacks;
871 for (const SdfSite &site: primSites) {
872 const PcpLayerStackPtrVector& layerStackVec =
873 cache->FindAllLayerStacksUsingLayer(site.layer);
874 layerStacks.insert(layerStackVec.begin(), layerStackVec.end());
875 }
876
877 // Get the sites in cache that use any proper descendant of the
878 // namespace edited site and what each site depends on.
879 std::map<SdfPath, PcpNodeRef> descendantPathsAndNodes;
880 for (const PcpLayerStackPtr& layerStack: layerStacks) {
881 PcpDependencyVector deps =
882 cache->FindSiteDependencies(
883 layerStack, primPath,
884 PcpDependencyTypeAnyNonVirtual,
885 /* recurseOnSite */ true,
886 /* recurseOnIndex */ true,
887 /* filter */ true);
888 auto visitNodeFn = [&](const SdfPath &depIndexPath,
889 const PcpNodeRef &node) {
890 if (!depIndexPath.IsPrimPath() ||
891 node.GetPath() != curPath) {
892 descendantPathsAndNodes[depIndexPath] = node;
893 }
894 };
895 for(const PcpDependency &dep: deps) {
896 // Check that specs exist at this site. There may
897 // not be any, because we synthesized dependent paths
898 // with recurseOnIndex, which may not actually
899 // have depended on this site (and exist for other
900 // reasons).
901 if (PcpComposeSiteHasPrimSpecs(layerStack, dep.sitePath)) {
902 Pcp_ForEachDependentNode(dep.sitePath, layerStack,
903 dep.indexPath,
904 *cache, visitNodeFn);
905 }
906 }
907 }
908
909 // Add every uncomposed site used by each (cache,path) pair
910 // if we haven't already added its parent. We don't need to
911 // add a site if we've added its parent because removing the
912 // parent will remove its descendants. The result is that we
913 // add every uncomposed site that doesn't have a direct arc to
914 // another uncomposed site.
915 //
916 // Note that we only check nodes from the namespace edited
917 // site and its descendants to the root. Other nodes are due
918 // to other arcs and not affected by the namespace edit.
919 TF_FOR_ALL(i, descendantPathsAndNodes) {
920 PcpNodeRef node = i->second;
921 const SdfPath& descendantPath = i->first;
922 SdfPath descendantPrimPath = descendantPath.GetPrimPath();
923
924 for (; node; node = node.GetParentNode()) {
925 SdfPath path =
926 descendantPath.ReplacePrefix(descendantPrimPath,
927 node.GetPath());
928 PcpLayerStackSite site(node.GetLayerStack(), path);
929 if (!_Helper::HasSite(descendantSites, site)) {
930 // We haven't seen this site or an ancestor yet.
931 if (doNotRemoveSites.count(site) == 0) {
932 // We're not blocking the addition of this site.
933 descendantSites[site] = cacheIndex;
934 }
935 }
936 }
937 }
938 }
939
940 // We now have all the descendant sites to remove. Add them to
941 // result.layerStackSites.
942 TF_FOR_ALL(j, descendantSites) {
943 result.layerStackSites.resize(result.layerStackSites.size()+1);
944 LayerStackSite& site = result.layerStackSites.back();
945 site.cacheIndex = j->second;
946 site.type = PcpNamespaceEdits::EditPath;
947 site.sitePath = j->first.path;
948 site.oldPath = j->first.path;
949 site.newPath = newPath; // This is the empty path.
950 site.layerStack = j->first.layerStack;
951 }
952 }
953
954 // Fix up all direct inherits to a descendant site.
955 if (!descendantNodes.empty()) {
956 for (const auto& cacheAndNode : descendantNodes) {
957 size_t cacheIndex = cacheAndNode.first;
958 const PcpNodeRef& node = cacheAndNode.second;
959 SdfPath oldNodePath = node.GetPath();
960 SdfPath newNodePath = oldNodePath.ReplacePrefix(curPath, newPath);
961 _AddLayerStackSite(&result, node, cacheIndex,
962 &oldNodePath, &newNodePath);
963 }
964 }
965
966 // Final namespace edits.
967
968 // Diagnostics.
969 // TODO: We should split this into a PcpNamespaceEdits->string function
970 // in diagnostics.cpp.
971 if (TfDebug::IsEnabled(PCP_NAMESPACE_EDIT)) {
972 TF_DEBUG(PCP_NAMESPACE_EDIT)
973 .Msg("PcpComputeNamespaceEdits():\n"
974 " cache: %s\n"
975 " curPath: <%s>\n"
976 " newPath: <%s>\n",
977 TfStringify( primaryLayerStack->GetIdentifier()).c_str(),
978 curPath.GetText(),
979 newPath.GetText()
980 );
981 TF_FOR_ALL(cacheSite, result.cacheSites) {
982 TF_DEBUG(PCP_NAMESPACE_EDIT)
983 .Msg(" cacheSite:\n"
984 " cache: %s\n"
985 " oldPath: <%s>\n"
986 " newPath: <%s>\n",
987 TfStringify( caches[cacheSite->cacheIndex]
988 ->GetLayerStack()->GetIdentifier()).c_str(),
989 cacheSite->oldPath.GetText(),
990 cacheSite->newPath.GetText());
991 }
992 TF_FOR_ALL(layerStackSite, result.layerStackSites) {
993 TF_DEBUG(PCP_NAMESPACE_EDIT)
994 .Msg(" layerStackSite:\n"
995 " cache: %s\n"
996 " type: %s\n"
997 " layerStack: %s\n"
998 " sitePath: <%s>\n"
999 " oldPath: <%s>\n"
1000 " newPath: <%s>\n",
1001 TfStringify( caches[layerStackSite->cacheIndex]
1002 ->GetLayerStack()->GetIdentifier()).c_str(),
1003 TfStringify(layerStackSite->type).c_str(),
1004 TfStringify(layerStackSite->layerStack
1005 ->GetIdentifier()).c_str(),
1006 layerStackSite->sitePath.GetText(),
1007 layerStackSite->oldPath.GetText(),
1008 layerStackSite->newPath.GetText());
1009 }
1010 TF_FOR_ALL(layerStackSite, result.invalidLayerStackSites) {
1011 TF_DEBUG(PCP_NAMESPACE_EDIT)
1012 .Msg(" invalidLayerStackSite:\n"
1013 " cache: %s\n"
1014 " type: %s\n"
1015 " layerStack: %s\n"
1016 " sitePath: <%s>\n"
1017 " oldPath: <%s>\n"
1018 " newPath: <%s>\n",
1019 TfStringify( caches[layerStackSite->cacheIndex]
1020 ->GetLayerStack()->GetIdentifier()).c_str(),
1021 TfStringify(layerStackSite->type).c_str(),
1022 TfStringify(layerStackSite->layerStack
1023 ->GetIdentifier()).c_str(),
1024 layerStackSite->sitePath.GetText(),
1025 layerStackSite->oldPath.GetText(),
1026 layerStackSite->newPath.GetText());
1027 }
1028 }
1029
1030 return result;
1031 }
1032
1033 PXR_NAMESPACE_CLOSE_SCOPE
1034