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.
5 from future
import Gettable
, Future
8 class _BaseFileSystemException(Exception):
9 def __init__(self
, message
):
10 Exception.__init
__(self
, message
)
13 def RaiseInFuture(cls
, message
):
14 def boom(): raise cls(message
)
15 return Future(delegate
=Gettable(boom
))
18 class FileNotFoundError(_BaseFileSystemException
):
19 '''Raised when a file isn't found for read or stat.
21 def __init__(self
, filename
):
22 _BaseFileSystemException
.__init
__(self
, filename
)
25 class FileSystemError(_BaseFileSystemException
):
26 '''Raised on when there are errors reading or statting files, such as a
29 def __init__(self
, filename
):
30 _BaseFileSystemException
.__init
__(self
, filename
)
33 class StatInfo(object):
34 '''The result of calling Stat on a FileSystem.
36 def __init__(self
, version
, child_versions
=None):
37 self
.version
= version
38 self
.child_versions
= child_versions
40 def __eq__(self
, other
):
41 return (isinstance(other
, StatInfo
) and
42 self
.version
== other
.version
and
43 self
.child_versions
== other
.child_versions
)
45 def __ne__(self
, other
):
46 return not (self
== other
)
49 return '{version: %s, child_versions: %s}' % (self
.version
,
56 class FileSystem(object):
57 '''A FileSystem interface that can read files and directories.
59 def Read(self
, paths
):
60 '''Reads each file in paths and returns a dictionary mapping the path to the
61 contents. If a path in paths ends with a '/', it is assumed to be a
62 directory, and a list of files in the directory is mapped to the path.
64 The contents will be a str.
66 If any path cannot be found, raises a FileNotFoundError. This is guaranteed
67 to only happen once the Future has been resolved (Get() called).
69 For any other failure, raises a FileSystemError.
71 raise NotImplementedError(self
.__class
__)
73 def ReadSingle(self
, path
):
74 '''Reads a single file from the FileSystem. Returns a Future with the same
77 read_single
= self
.Read([path
])
78 return Future(delegate
=Gettable(lambda: read_single
.Get()[path
]))
81 '''Asynchronously refreshes the content of the FileSystem, returning a
82 future to its completion.
84 raise NotImplementedError(self
.__class
__)
86 # TODO(cduvall): Allow Stat to take a list of paths like Read.
88 '''Returns a |StatInfo| object containing the version of |path|. If |path|
89 is a directory, |StatInfo| will have the versions of all the children of
90 the directory in |StatInfo.child_versions|.
92 If the path cannot be found, raises a FileNotFoundError.
93 For any other failure, raises a FileSystemError.
95 raise NotImplementedError(self
.__class
__)
97 def GetIdentity(self
):
98 '''The identity of the file system, exposed for caching classes to
99 namespace their caches. this will usually depend on the configuration of
100 that file system - e.g. a LocalFileSystem with a base path of /var is
101 different to that of a SubversionFileSystem with a base path of /bar, is
102 different to a LocalFileSystem with a base path of /usr.
104 raise NotImplementedError(self
.__class
__)
106 def Walk(self
, root
):
107 '''Recursively walk the directories in a file system, starting with root.
108 Emulates os.walk from the standard os module.
110 If the root cannot be found, raises a FileNotFoundError.
111 For any other failure, raises a FileSystemError.
113 basepath
= root
.rstrip('/') + '/'
116 if not root
.endswith('/'):
121 for f
in self
.ReadSingle(root
).Get():
127 yield root
[len(basepath
):].rstrip('/'), dirs
, files
130 for walkinfo
in walk(root
+ d
):
133 for walkinfo
in walk(root
):
137 return '<%s>' % type(self
).__name
__