def CheckCompliance(self, inputFile): from pxr import Sdf, Usd, UsdUtils if not Usd.Stage.IsSupportedFile(inputFile): _AddError("Cannot open file '%s' on a USD stage." % args.inputFile) return # Collect all warnings using a diagnostic delegate. delegate = UsdUtils.CoalescingDiagnosticDelegate() usdStage = Usd.Stage.Open(inputFile) stageOpenDiagnostics = delegate.TakeUncoalescedDiagnostics() for rule in self._rules: rule.CheckStage(usdStage) rule.CheckDiagnostics(stageOpenDiagnostics) with Ar.ResolverContextBinder(usdStage.GetPathResolverContext()): # This recursively computes all of inputFiles's external # dependencies. (allLayers, allAssets, unresolvedPaths) = \ UsdUtils.ComputeAllDependencies(Sdf.AssetPath(inputFile)) for rule in self._rules: rule.CheckUnresolvedPaths(unresolvedPaths) rule.CheckDependencies(usdStage, allLayers, allAssets) if self._rootPackageOnly: rootLayer = usdStage.GetRootLayer() if rootLayer.GetFileFormat().IsPackage(): packagePath = Ar.SplitPackageRelativePathInner( rootLayer.identifier)[0] self._CheckPackage(packagePath) else: self._AddError( "Root layer of the USD stage (%s) doesn't belong to " "a package, but 'rootPackageOnly' is True!" % Usd.Describe(usdStage)) else: # Process every package just once by storing them all in a set. packages = set() for layer in allLayers: if _IsPackageOrPackagedLayer(layer): packagePath = Ar.SplitPackageRelativePathInner( layer.identifier)[0] packages.add(packagePath) self._CheckLayer(layer) for package in packages: self._CheckPackage(package) # Traverse the entire stage and check every prim. from pxr import Usd # Author all variant switches in the session layer. usdStage.SetEditTarget(usdStage.GetSessionLayer()) allPrimsIt = iter( Usd.PrimRange.Stage(usdStage, Usd.TraverseInstanceProxies())) self._TraverseRange(allPrimsIt, isStageRoot=True)
def _CheckPackage(self, packagePath): self._Msg("Checking package <%s>." % packagePath) # XXX: Should we open the package on a stage to ensure that it is valid # and entirely self-contained. from pxr import Usd pkgExt = Ar.GetResolver().GetExtension(packagePath) if pkgExt != "usdz": self._AddError("Package at path %s has an invalid extension." % packagePath) return # Check the parent package first. if Ar.IsPackageRelativePath(packagePath): parentPackagePath = Ar.SplitPackageRelativePathInner(packagePath)[0] self._CheckPackage(parentPackagePath) # Avoid checking the same parent package multiple times. if packagePath in self._checkedPackages: return self._checkedPackages.add(packagePath) resolvedPath = Ar.GetResolver().Resolve(packagePath) if len(resolvedPath) == 0: self._AddError("Failed to resolve package path '%s'." % packagePath) return zipFile = Usd.ZipFile.Open(resolvedPath) if not zipFile: self._AddError("Could not open package at path '%s'." % resolvedPath) return for rule in self._rules: rule.CheckZipFile(zipFile, packagePath)
def RunCommand(self): if not self._item: return # Get layer path from item layerPath = getattr(self._item, "layerPath") if not layerPath: print("Error: Could not find layer file.") return if Ar.IsPackageRelativePath(layerPath): layerName = os.path.basename( Ar.SplitPackageRelativePathInner(layerPath)[1]) else: layerName = os.path.basename(layerPath) layerName += ".tmp" usdeditExe = self._FindUsdEdit() if not usdeditExe: print( "Warning: Could not find 'usdedit', expected it to be in PATH." ) return print("Opening file: %s" % layerPath) command = [usdeditExe, '-n', layerPath, '-p', layerName] subprocess.Popen(command, close_fds=True)
def _CheckPackage(self, packagePath): self._Msg("Checking package <%s>." % packagePath) # XXX: Should we open the package on a stage to ensure that it is valid # and entirely self-contained. from pxr import Ar, Usd pkgExt = Ar.GetResolver().GetExtension(packagePath) if self._arkit and pkgExt != "usdz": self._AddFailedCheck( "Package at path %s has an invalid extension." % packagePath, ruleNum=5) return # Check the parent package first. if Ar.IsPackageRelativePath(packagePath): parentPackagePath = Ar.SplitPackageRelativePathInner( packagePath)[0] self._CheckPackage(parentPackagePath) # Avoid checking the same parent package multiple times. if packagePath in self._checkedPackages: return self._checkedPackages.add(packagePath) resolvedPath = Ar.GetResolver().Resolve(packagePath) if len(resolvedPath) == 0: self._AddError("Failed to resolve package path '%s'." % packagePath) return zipFile = Usd.ZipFile.Open(resolvedPath) if not zipFile: self._AddError("Could not open package at path '%s'." % resolvedPath) return fileNames = zipFile.GetFileNames() for fileName in fileNames: fileExt = Ar.GetResolver().GetExtension(fileName) if fileExt not in ComplianceChecker._allowedFileExtensions: self._AddFailedCheck( "File '%s' in package '%s' has unknown or " "unsupported extension '%s'." % (fileName, packagePath, fileExt), ruleNum=[4, 5]) fileInfo = zipFile.GetFileInfo(fileName) offset = fileInfo.dataOffset if offset % 64 != 0: self._AddFailedCheck( "File '%s' in package '%s' has an invalid " "offset %s." % (fileName, packagePath, offset), ruleNum=1) if fileInfo.compressionMethod != 0: self._AddFailedCheck( "File '%s' in package '%s' has " "compression. Compression method is '%s', actual size is " "%s. Uncompressed size is %s." % (fileName, packagePath, fileInfo.compressionMethod, fileInfo.size, fileInfo.uncompressedSize), ruleNum=2)
def _CheckRootPackage(self, usdStage): from pxr import Ar rootLayer = usdStage.GetRootLayer() if rootLayer.GetFileFormat().IsPackage(): packagePath = Ar.SplitPackageRelativePathInner( rootLayer.identifier)[0] self._CheckPackage(packagePath) else: self._AddError( "Root layer of the USD stage (%s) doesn't belong to " "a package!" % Usd.Describe(usdStage))
def _CheckDependencies(self, usdStage, layerDeps, assetDeps, unresolvedPaths): from pxr import Ar def _IsPackageOrPackagedLayer(layer): return layer.GetFileFormat().IsPackage() or \ Ar.IsPackageRelativePath(layer.identifier) # Process every package just once by storing them all in a set. packages = set() for layer in layerDeps: if _IsPackageOrPackagedLayer(layer): packagePath = Ar.SplitPackageRelativePathInner( layer.identifier)[0] packages.add(packagePath) self._CheckLayer(layer) for package in packages: self._CheckPackage(package) # If the root layer is a package, validate that all the loaded layers # belong to the package. rootLayer = usdStage.GetRootLayer() if self._arkit and _IsPackageOrPackagedLayer(rootLayer): packagePath = usdStage.GetRootLayer().realPath if packagePath: if Ar.IsPackageRelativePath(packagePath): packagePath = Ar.SplitPackageRelativePathOuter( packagePath)[0] for layer in layerDeps: # In-memoery layers that session layers won't have a real # path. We can skip them. if layer.realPath: if not layer.realPath.startswith(packagePath): self._AddFailedCheck( "Found loaded layer '%s' that " "does not belong to the package '%s'." % (layer.identifier, packagePath), ruleNum=4) for asset in assetDeps: if not asset.startswith(packagePath): self._AddFailedCheck( "Found asset reference '%s' that " "does not belong to the package '%s'." % (asset, packagePath), ruleNum=4) for unresolvedPath in unresolvedPaths: self._AddFailedCheck( "Found unresolvable external dependency '%s'." % unresolvedPath, ruleNum=4)
def test_SplitPackageRelativePathInner(self): """Test Ar.SplitPackageRelativePathInner""" self.assertEqual(Ar.SplitPackageRelativePathInner(""), ("", "")) self.assertEqual(Ar.SplitPackageRelativePathInner("foo.file"), ("foo.file", "")) self.assertEqual( Ar.SplitPackageRelativePathInner("foo.pack[bar.file]"), ("foo.pack", "bar.file")) self.assertEqual( Ar.SplitPackageRelativePathInner("foo.pack[bar.pack[baz.file]]"), ("foo.pack[bar.pack]", "baz.file")) self.assertEqual( Ar.SplitPackageRelativePathInner("foo[0].pack[bar.file]"), ("foo[0].pack", "bar.file")) # Corner case: ensure delimiter characters in paths are unescaped # when removed from delimiters by Ar.SplitPackageRelativePathInner. self.assertEqual( Ar.SplitPackageRelativePathInner( "foo]a.pack[bar\\[b.pack[baz\\]c.file]]"), ("foo]a.pack[bar\\[b.pack]", "baz]c.file"))