__all__ = ["ScanDirectoryNode"] from panda3d.core import VirtualFileSystem, VirtualFileMountSystem, Filename, TiXmlDocument vfs = VirtualFileSystem.getGlobalPtr() class ScanDirectoryNode: """ This class is used to scan a list of files on disk. """ def __init__(self, pathname, ignoreUsageXml = False): self.pathname = pathname self.filenames = [] self.fileSize = 0 self.nested = [] self.nestedSize = 0 xusage = None if not ignoreUsageXml: # Look for a usage.xml file in this directory. If we find # one, we read it for the file size and then stop here, as # an optimization. usageFilename = Filename(pathname, 'usage.xml') doc = TiXmlDocument(usageFilename.toOsSpecific()) if doc.LoadFile(): xusage = doc.FirstChildElement('usage') if xusage: diskSpace = xusage.Attribute('disk_space') try: diskSpace = int(diskSpace or '') except ValueError: diskSpace = None if diskSpace is not None: self.fileSize = diskSpace return files = vfs.scanDirectory(self.pathname) if files is None: files = [] for vfile in files: if hasattr(vfile, 'getMount'): if not isinstance(vfile.getMount(), VirtualFileMountSystem): # Not a real file; ignore it. continue if vfile.isDirectory(): # A nested directory. subdir = ScanDirectoryNode(vfile.getFilename(), ignoreUsageXml = ignoreUsageXml) self.nested.append(subdir) self.nestedSize += subdir.getTotalSize() elif vfile.isRegularFile(): # A nested file. self.filenames.append(vfile.getFilename()) self.fileSize += vfile.getFileSize() else: # Some other wacky file thing. self.filenames.append(vfile.getFilename()) if xusage: # Now update the usage.xml file with the newly-determined # disk space. xusage.SetAttribute('disk_space', str(self.getTotalSize())) tfile = Filename.temporary(str(pathname), '.xml') if doc.SaveFile(tfile.toOsSpecific()): tfile.renameTo(usageFilename) def getTotalSize(self): return self.nestedSize + self.fileSize def extractSubdir(self, pathname): """ Finds the ScanDirectoryNode within this node that corresponds to the indicated full pathname. If it is found, removes it from its parent, and returns it. If it is not found, returns None. """ # We could be a little smarter here, but why bother. Just # recursively search all children. for subdir in self.nested: if subdir.pathname == pathname: self.nested.remove(subdir) self.nestedSize -= subdir.getTotalSize() return subdir result = subdir.extractSubdir(pathname) if result: self.nestedSize -= result.getTotalSize() if subdir.getTotalSize() == 0: # No other files in the subdirectory that contains # this package; remove it too. self.nested.remove(subdir) return result return None