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