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 /// \file Sdf/LayerRegistry.cpp
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/sdf/layerRegistry.h"
29 #include "pxr/usd/sdf/assetPathResolver.h"
30 #include "pxr/usd/sdf/debugCodes.h"
31 #include "pxr/usd/sdf/fileFormat.h"
32 #include "pxr/usd/sdf/layer.h"
33 //#include "pxr/usd/sdf/schema.h"
34 #include "pxr/usd/ar/resolver.h"
35 #include "pxr/base/trace/trace.h"
36 #include "pxr/base/tf/pathUtils.h"
37 #include "pxr/base/tf/registryManager.h"
38 #include "pxr/base/tf/staticData.h"
39 #include <ostream>
40 
41 using namespace boost::multi_index;
42 using std::string;
43 
44 PXR_NAMESPACE_OPEN_SCOPE
45 
46 // A simple layer repr, used for debug and error messages, that includes both
47 // the identifier and the real path.
48 static string
Sdf_LayerDebugRepr(const SdfLayerHandle & layer)49 Sdf_LayerDebugRepr(
50     const SdfLayerHandle& layer)
51 {
52     return layer ?
53         "SdfLayer('" +
54             layer->GetIdentifier() + "', '" +
55             layer->GetRealPath() + "')" :
56         "None"
57         ;
58 }
59 
60 const Sdf_LayerRegistry::layer_identifier::result_type&
operator ()(const SdfLayerHandle & layer) const61 Sdf_LayerRegistry::layer_identifier::operator()(
62     const SdfLayerHandle& layer) const
63 {
64     static string emptyString;
65     return layer ? layer->GetIdentifier() : emptyString;
66 }
67 
68 Sdf_LayerRegistry::layer_repository_path::result_type
operator ()(const SdfLayerHandle & layer) const69 Sdf_LayerRegistry::layer_repository_path::operator()(
70     const SdfLayerHandle& layer) const
71 {
72     if (!layer) {
73         return std::string();
74     }
75 
76     const string repoPath = layer->GetRepositoryPath();
77     if (!repoPath.empty()) {
78         string layerPath, arguments;
79         TF_VERIFY(Sdf_SplitIdentifier(
80                 layer->GetIdentifier(), &layerPath, &arguments));
81         return Sdf_CreateIdentifier(repoPath, arguments);
82     }
83 
84     return std::string();
85 }
86 
87 Sdf_LayerRegistry::layer_real_path::result_type
operator ()(const SdfLayerHandle & layer) const88 Sdf_LayerRegistry::layer_real_path::operator()(
89     const SdfLayerHandle& layer) const
90 {
91     if (!layer) {
92         return std::string();
93     }
94 
95     if (layer->IsAnonymous()) {
96         // The layer_real_path index requires a unique key. As anonymous do
97         // not have a realPath, we use the (unique) identifier as the key.
98         return layer->GetIdentifier();
99     }
100 
101     const string realPath = layer->GetRealPath();
102     if (!realPath.empty()) {
103         string layerPath, arguments;
104         TF_VERIFY(Sdf_SplitIdentifier(
105                 layer->GetIdentifier(), &layerPath, &arguments));
106         return Sdf_CreateIdentifier(realPath, arguments);
107     }
108 
109     return std::string();
110 }
111 
Sdf_LayerRegistry()112 Sdf_LayerRegistry::Sdf_LayerRegistry()
113 {
114 }
115 
116 struct update_index_only {
operator ()update_index_only117     void operator()(const SdfLayerHandle&) { }
118 };
119 
120 void
InsertOrUpdate(const SdfLayerHandle & layer)121 Sdf_LayerRegistry::InsertOrUpdate(
122     const SdfLayerHandle& layer)
123 {
124     TRACE_FUNCTION();
125 
126     if (!layer) {
127         TF_CODING_ERROR("Expired layer handle");
128         return;
129     }
130 
131     TF_DEBUG(SDF_LAYER).Msg(
132         "Sdf_LayerRegistry::InsertOrUpdate(%s)\n",
133         Sdf_LayerDebugRepr(layer).c_str());
134 
135     // Attempt to insert the layer into the registry. This may fail because
136     // the new layer violates constraints of one of the registry indices.
137     std::pair<_Layers::iterator, bool> result = _layers.insert(layer);
138     if (!result.second) {
139         SdfLayerHandle existingLayer = *result.first;
140         if (layer == existingLayer) {
141             // We failed to insert the layer into the registry because this
142             // layer object is already in the registry. All we need to do is
143             // update the indices so it can be found.
144             _layers.modify(result.first, update_index_only());
145         } else {
146             // We failed to insert the layer into the registry because there
147             // is a realPath conflict. This can happen when the same layer is
148             // crated twice in the same location in the same session.
149             TF_CODING_ERROR("Cannot insert duplicate registry entry for "
150                 "%s layer %s over existing entry for %s layer %s",
151                 layer->GetFileFormat()->GetFormatId().GetText(),
152                 Sdf_LayerDebugRepr(layer).c_str(),
153                 existingLayer->GetFileFormat()->GetFormatId().GetText(),
154                 Sdf_LayerDebugRepr(existingLayer).c_str());
155         }
156     }
157 }
158 
159 void
Erase(const SdfLayerHandle & layer)160 Sdf_LayerRegistry::Erase(
161     const SdfLayerHandle& layer)
162 {
163     bool erased = _layers.erase(layer);
164 
165     TF_DEBUG(SDF_LAYER).Msg(
166         "Sdf_LayerRegistry::Erase(%s) => %s\n",
167         Sdf_LayerDebugRepr(layer).c_str(),
168         erased ? "Success" : "Failed");
169 }
170 
171 SdfLayerHandle
Find(const string & inputLayerPath,const string & resolvedPath) const172 Sdf_LayerRegistry::Find(
173     const string &inputLayerPath,
174     const string &resolvedPath) const
175 {
176     TRACE_FUNCTION();
177 
178     SdfLayerHandle foundLayer;
179 
180     if (Sdf_IsAnonLayerIdentifier(inputLayerPath)) {
181         foundLayer = FindByIdentifier(inputLayerPath);
182     } else {
183         ArResolver& resolver = ArGetResolver();
184 
185 #if AR_VERSION == 1
186         const string layerPath =
187             resolver.ComputeNormalizedPath(inputLayerPath);
188 
189         // If the layer path is relative, this may be either a search path
190         // or a layer relative to the current working directory. Use the
191         // look-here-first scheme to check whether the registry holds a
192         // layer with the correct absolute identifier.
193         //
194         // We call TfNormPath() so we get a platform independent
195         // representation;  specifically on Windows we get forward slashes.
196         const bool isRelativePath = resolver.IsRelativePath(layerPath);
197         if (isRelativePath)
198             foundLayer = FindByIdentifier(TfNormPath(TfAbsPath(layerPath)));
199 
200         // If the layer path is not relative, and we haven't found a layer
201         // yet, look up the layer using the normalized identifier.
202         if (!foundLayer && !isRelativePath)
203             foundLayer = FindByIdentifier(layerPath);
204 #else
205         const string& layerPath = inputLayerPath;
206 
207         // If the layer path depends on context there may be multiple
208         // layers with the same identifier but different resolved paths.
209         // In this case we need to look up the layer by resolved path.
210         string assetPath, args;
211         Sdf_SplitIdentifier(inputLayerPath, &assetPath, &args);
212         if (!resolver.IsContextDependentPath(assetPath)) {
213             foundLayer = FindByIdentifier(layerPath);
214         }
215 #endif
216 
217         // If the layer path is in repository form and we haven't yet
218         // found the layer via the identifier, attempt to look up the
219         // layer by repository path.
220 #if AR_VERSION == 1
221         const bool isRepositoryPath = resolver.IsRepositoryPath(layerPath);
222 #else
223         const bool isRepositoryPath = resolver.IsRepositoryPath(assetPath);
224 #endif
225         if (!foundLayer && isRepositoryPath)
226             foundLayer = FindByRepositoryPath(layerPath);
227 
228         // If the layer has not yet been found, this may be some other
229         // form of path that requires path resolution and lookup in the
230         // real path index in order to locate.
231         if (!foundLayer)
232             foundLayer = FindByRealPath(layerPath, resolvedPath);
233     }
234 
235     TF_DEBUG(SDF_LAYER).Msg(
236         "Sdf_LayerRegistry::Find('%s') => %s\n",
237         inputLayerPath.c_str(),
238         Sdf_LayerDebugRepr(foundLayer).c_str());
239 
240     return foundLayer;
241 }
242 
243 SdfLayerHandle
FindByIdentifier(const string & layerPath) const244 Sdf_LayerRegistry::FindByIdentifier(
245     const string& layerPath) const
246 {
247     TRACE_FUNCTION();
248 
249     SdfLayerHandle foundLayer;
250 
251     const _LayersByIdentifier& byIdentifier = _layers.get<by_identifier>();
252     _LayersByIdentifier::const_iterator identifierIt =
253         byIdentifier.find(layerPath);
254     if (identifierIt != byIdentifier.end())
255         foundLayer = *identifierIt;
256 
257     TF_DEBUG(SDF_LAYER).Msg(
258         "Sdf_LayerRegistry::FindByIdentifier('%s') => %s\n",
259         layerPath.c_str(),
260         foundLayer ? "Found" : "Not Found");
261 
262     return foundLayer;
263 }
264 
265 SdfLayerHandle
FindByRepositoryPath(const string & layerPath) const266 Sdf_LayerRegistry::FindByRepositoryPath(
267     const string& layerPath) const
268 {
269     TRACE_FUNCTION();
270 
271     SdfLayerHandle foundLayer;
272 
273     if (layerPath.empty())
274         return foundLayer;
275 
276     const _LayersByRepositoryPath& byRepoPath = _layers.get<by_repository_path>();
277     _LayersByRepositoryPath::const_iterator repoPathIt =
278         byRepoPath.find(layerPath);
279     if (repoPathIt != byRepoPath.end())
280         foundLayer = *repoPathIt;
281 
282     TF_DEBUG(SDF_LAYER).Msg(
283         "Sdf_LayerRegistry::FindByRepositoryPath('%s') => %s\n",
284         layerPath.c_str(),
285         foundLayer ? "Found" : "Not Found");
286 
287     return foundLayer;
288 }
289 
290 SdfLayerHandle
FindByRealPath(const string & layerPath,const string & resolvedPath) const291 Sdf_LayerRegistry::FindByRealPath(
292     const string& layerPath,
293     const string& resolvedPath) const
294 {
295     TRACE_FUNCTION();
296 
297     SdfLayerHandle foundLayer;
298 
299     if (layerPath.empty())
300         return foundLayer;
301 
302     string searchPath, arguments;
303     if (!Sdf_SplitIdentifier(layerPath, &searchPath, &arguments))
304         return foundLayer;
305 
306     // Ignore errors reported by Sdf_ComputeFilePath. These errors mean we
307     // weren't able to compute a real path from the given layerPath. However,
308     // that shouldn't be an error for this function, it just means there was
309     // nothing to find at that layerPath.
310     {
311         TfErrorMark m;
312         searchPath = !resolvedPath.empty() ?
313             resolvedPath : Sdf_ComputeFilePath(searchPath);
314 
315         if (!m.IsClean()) {
316             std::vector<std::string> errors;
317             for (const TfError& e : m) {
318                 errors.push_back(e.GetCommentary());
319             }
320 
321             TF_DEBUG(SDF_LAYER).Msg(
322                 "Sdf_LayerRegistry::FindByRealPath('%s'): "
323                 "Failed to compute real path: %s\n",
324                 layerPath.c_str(), TfStringJoin(errors, ", ").c_str());
325 
326             m.Clear();
327         }
328     }
329     searchPath = Sdf_CreateIdentifier(searchPath, arguments);
330 
331 #if AR_VERSION == 1
332     // Avoid ambiguity by converting the path to a platform dependent
333     // path.  (On Windows this converts slashes to backslashes.)  The
334     // real paths stored in the registry are in platform dependent form.
335     searchPath = TfAbsPath(searchPath);
336 #endif
337 
338     const _LayersByRealPath& byRealPath = _layers.get<by_real_path>();
339     _LayersByRealPath::const_iterator realPathIt =
340         byRealPath.find(searchPath);
341     if (realPathIt != byRealPath.end())
342         foundLayer = *realPathIt;
343 
344     TF_DEBUG(SDF_LAYER).Msg(
345         "Sdf_LayerRegistry::FindByRealPath('%s') => %s\n",
346         searchPath.c_str(),
347         foundLayer ? "Found" : "Not Found");
348 
349     return foundLayer;
350 }
351 
352 SdfLayerHandleSet
GetLayers() const353 Sdf_LayerRegistry::GetLayers() const
354 {
355     SdfLayerHandleSet layers;
356 
357     TF_FOR_ALL(i, _layers.get<by_identity>()) {
358         SdfLayerHandle layer = *i;
359         if (TF_VERIFY(layer, "Found expired layer in registry")) {
360             layers.insert(layer);
361         }
362     }
363 
364     return layers;
365 }
366 
367 std::ostream&
operator <<(std::ostream & ostr,const Sdf_LayerRegistry & registry)368 operator<<(std::ostream& ostr, const Sdf_LayerRegistry& registry)
369 {
370     SdfLayerHandleSet layers = registry.GetLayers();
371     TF_FOR_ALL(i, layers) {
372         if (SdfLayerHandle layer = *i) {
373             ostr << TfStringPrintf(
374                 "%p[ref=%zu]:\n"
375                 "    format           = %s\n"
376                 "    identifier       = '%s'\n"
377                 "    repositoryPath   = '%s'\n"
378                 "    realPath         = '%s'\n"
379                 "    version          = '%s'\n"
380                 "    assetInfo        = \n'%s'\n"
381                 "    muted            = %s\n"
382                 "    anonymous        = %s\n"
383                 "\n"
384                 , layer.GetUniqueIdentifier()
385                 , layer->GetCurrentCount()
386                 , layer->GetFileFormat()->GetFormatId().GetText()
387                 , layer->GetIdentifier().c_str()
388                 , layer->GetRepositoryPath().c_str()
389                 , layer->GetRealPath().c_str()
390                 , layer->GetVersion().c_str()
391                 , TfStringify(layer->GetAssetInfo()).c_str()
392                 , (layer->IsMuted()          ? "True" : "False")
393                 , (layer->IsAnonymous()      ? "True" : "False")
394                 );
395         }
396     }
397 
398     return ostr;
399 }
400 
401 PXR_NAMESPACE_CLOSE_SCOPE
402