1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 class FileNotFoundError(Exception): 6 def __init__(self, filename): 7 Exception.__init__(self, filename) 8 9 class StatInfo(object): 10 '''The result of calling Stat on a FileSystem. 11 ''' 12 def __init__(self, version, child_versions=None): 13 self.version = version 14 self.child_versions = child_versions 15 16 def __eq__(self, other): 17 return (isinstance(other, StatInfo) and 18 self.version == other.version and 19 self.child_versions == other.child_versions) 20 21 def __ne__(self, other): 22 return not (self == other) 23 24 def __str__(self): 25 return '{version: %s, child_versions: %s}' % (self.version, 26 self.child_versions) 27 28 def __repr__(self): 29 return str(self) 30 31 def ToUnicode(data): 32 '''Returns the str |data| as a unicode object. It's expected to be utf8, but 33 there are also latin-1 encodings in there for some reason. Fall back to that. 34 ''' 35 try: 36 return unicode(data, 'utf-8') 37 except: 38 return unicode(data, 'latin-1') 39 40 class FileSystem(object): 41 '''A FileSystem interface that can read files and directories. 42 ''' 43 def Read(self, paths, binary=False): 44 '''Reads each file in paths and returns a dictionary mapping the path to the 45 contents. If a path in paths ends with a '/', it is assumed to be a 46 directory, and a list of files in the directory is mapped to the path. 47 48 If binary=False, the contents of each file will be unicode parsed as utf-8, 49 and failing that as latin-1 (some extension docs use latin-1). If 50 binary=True then the contents will be a str. 51 ''' 52 raise NotImplementedError(self.__class__) 53 54 def ReadSingle(self, path, binary=False): 55 '''Reads a single file from the FileSystem. 56 ''' 57 return self.Read([path], binary=binary).Get()[path] 58 59 # TODO(cduvall): Allow Stat to take a list of paths like Read. 60 def Stat(self, path): 61 '''Returns a |StatInfo| object containing the version of |path|. If |path| 62 is a directory, |StatInfo| will have the versions of all the children of 63 the directory in |StatInfo.child_versions|. 64 ''' 65 raise NotImplementedError(self.__class__) 66 67 def GetIdentity(self): 68 '''The identity of the file system, exposed for caching classes to 69 namespace their caches. this will usually depend on the configuration of 70 that file system - e.g. a LocalFileSystem with a base path of /var is 71 different to that of a SubversionFileSystem with a base path of /bar, is 72 different to a LocalFileSystem with a base path of /usr. 73 ''' 74 raise NotImplementedError(self.__class__) 75 76 def Walk(self, root): 77 '''Recursively walk the directories in a file system, starting with root. 78 Emulates os.walk from the standard os module. 79 ''' 80 basepath = root.rstrip('/') + '/' 81 82 def walk(root): 83 if not root.endswith('/'): 84 root += '/' 85 86 dirs, files = [], [] 87 88 for f in self.ReadSingle(root): 89 if f.endswith('/'): 90 dirs.append(f) 91 else: 92 files.append(f) 93 94 yield root[len(basepath):].rstrip('/'), dirs, files 95 96 for d in dirs: 97 for walkinfo in walk(root + d): 98 yield walkinfo 99 100 for walkinfo in walk(root): 101 yield walkinfo 102