OLD | NEW |
---|---|
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import posixpath | |
6 | |
5 from future import Gettable, Future | 7 from future import Gettable, Future |
8 from path_util import IsDirectory, SplitParent, ToDirectory | |
6 | 9 |
7 | 10 |
8 class _BaseFileSystemException(Exception): | 11 class _BaseFileSystemException(Exception): |
9 def __init__(self, message): | 12 def __init__(self, message): |
10 Exception.__init__(self, message) | 13 Exception.__init__(self, message) |
11 | 14 |
12 @classmethod | 15 @classmethod |
13 def RaiseInFuture(cls, message): | 16 def RaiseInFuture(cls, message): |
14 def boom(): raise cls(message) | 17 def boom(): raise cls(message) |
15 return Future(delegate=Gettable(boom)) | 18 return Future(delegate=Gettable(boom)) |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
70 ''' | 73 ''' |
71 raise NotImplementedError(self.__class__) | 74 raise NotImplementedError(self.__class__) |
72 | 75 |
73 def ReadSingle(self, path): | 76 def ReadSingle(self, path): |
74 '''Reads a single file from the FileSystem. Returns a Future with the same | 77 '''Reads a single file from the FileSystem. Returns a Future with the same |
75 rules as Read(). | 78 rules as Read(). |
76 ''' | 79 ''' |
77 read_single = self.Read([path]) | 80 read_single = self.Read([path]) |
78 return Future(delegate=Gettable(lambda: read_single.Get()[path])) | 81 return Future(delegate=Gettable(lambda: read_single.Get()[path])) |
79 | 82 |
83 def Exists(self, path): | |
84 '''Returns a Future to the existence of |path|; True if |path| exists, | |
85 False is not. This method will not throw a FileNotFoundError unlike | |
Yoyo Zhou
2014/02/04 00:27:20
s/is/if/
not at google - send to devlin
2014/02/04 16:14:40
Done.
| |
86 the Read* methods, however it may still throw a FileSystemError. | |
87 | |
88 There are several ways to implement this method via the interface but this | |
89 method exists to do so in a canonical and most efficient way for caching. | |
90 ''' | |
91 if path in ('', '/'): | |
92 # There is always a root directory. | |
93 return Future(value=True) | |
94 | |
95 parent, base = SplitParent(path) | |
96 list_future = self.ReadSingle(ToDirectory(parent)) | |
97 def resolve(): | |
98 try: | |
99 return base in list_future.Get() | |
100 except FileNotFoundError: | |
101 return False | |
102 return Future(delegate=Gettable(resolve)) | |
103 | |
80 def Refresh(self): | 104 def Refresh(self): |
81 '''Asynchronously refreshes the content of the FileSystem, returning a | 105 '''Asynchronously refreshes the content of the FileSystem, returning a |
82 future to its completion. | 106 future to its completion. |
83 ''' | 107 ''' |
84 raise NotImplementedError(self.__class__) | 108 raise NotImplementedError(self.__class__) |
85 | 109 |
86 # TODO(cduvall): Allow Stat to take a list of paths like Read. | 110 # TODO(cduvall): Allow Stat to take a list of paths like Read. |
87 def Stat(self, path): | 111 def Stat(self, path): |
88 '''Returns a |StatInfo| object containing the version of |path|. If |path| | 112 '''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 | 113 is a directory, |StatInfo| will have the versions of all the children of |
90 the directory in |StatInfo.child_versions|. | 114 the directory in |StatInfo.child_versions|. |
91 | 115 |
92 If the path cannot be found, raises a FileNotFoundError. | 116 If the path cannot be found, raises a FileNotFoundError. |
93 For any other failure, raises a FileSystemError. | 117 For any other failure, raises a FileSystemError. |
94 ''' | 118 ''' |
95 raise NotImplementedError(self.__class__) | 119 raise NotImplementedError(self.__class__) |
96 | 120 |
97 def GetIdentity(self): | 121 def GetIdentity(self): |
98 '''The identity of the file system, exposed for caching classes to | 122 '''The identity of the file system, exposed for caching classes to |
99 namespace their caches. this will usually depend on the configuration of | 123 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 | 124 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 | 125 different to that of a SubversionFileSystem with a base path of /bar, is |
102 different to a LocalFileSystem with a base path of /usr. | 126 different to a LocalFileSystem with a base path of /usr. |
103 ''' | 127 ''' |
104 raise NotImplementedError(self.__class__) | 128 raise NotImplementedError(self.__class__) |
105 | 129 |
106 def Walk(self, root): | 130 def Walk(self, root): |
107 '''Recursively walk the directories in a file system, starting with root. | 131 '''Recursively walk the directories in a file system, starting with root. |
108 Emulates os.walk from the standard os module. | |
109 | 132 |
110 If the root cannot be found, raises a FileNotFoundError. | 133 Behaviour is very similar to os.walk from the standard os module, yielding |
Yoyo Zhou
2014/02/04 00:27:20
nice spelling =)
not at google - send to devlin
2014/02/04 16:14:40
are you referring to my favourite way of spelling
| |
134 (base, files, dirs) recursively, where |base| is the base path of |files| | |
Yoyo Zhou
2014/02/04 00:30:03
Seems like this is actually base, dirs, files.
not at google - send to devlin
2014/02/04 16:14:40
yes. Thank you.
| |
135 and |dirs| is relative to |root|, and |files| and |dirs| are the files and | |
Yoyo Zhou
2014/02/04 00:27:20
delete 'is'
not at google - send to devlin
2014/02/04 16:14:40
Done.
| |
136 dirs in |base| respectively. | |
Yoyo Zhou
2014/02/04 00:27:20
Clarify that files and dirs are lists.
not at google - send to devlin
2014/02/04 16:14:40
Done.
| |
137 | |
138 Note that directories will always end with a '/', files never will. | |
139 | |
140 If |root| cannot be found, raises a FileNotFoundError. | |
111 For any other failure, raises a FileSystemError. | 141 For any other failure, raises a FileSystemError. |
112 ''' | 142 ''' |
113 basepath = root.rstrip('/') + '/' | 143 root = ToDirectory(root) # TODO(kalman): assert IsDirectory(root) |
144 basepath = root | |
114 | 145 |
115 def walk(root): | 146 def walk(root): |
116 if not root.endswith('/'): | 147 assert IsDirectory(root), root |
117 root += '/' | |
118 | |
119 dirs, files = [], [] | 148 dirs, files = [], [] |
120 | 149 |
121 for f in self.ReadSingle(root).Get(): | 150 for f in self.ReadSingle(root).Get(): |
122 if f.endswith('/'): | 151 if f.endswith('/'): |
123 dirs.append(f) | 152 dirs.append(f) |
124 else: | 153 else: |
125 files.append(f) | 154 files.append(f) |
126 | 155 |
127 yield root[len(basepath):].rstrip('/'), dirs, files | 156 yield root[len(basepath):].rstrip('/'), dirs, files |
128 | 157 |
129 for d in dirs: | 158 for d in dirs: |
130 for walkinfo in walk(root + d): | 159 for walkinfo in walk(root + d): |
131 yield walkinfo | 160 yield walkinfo |
132 | 161 |
133 for walkinfo in walk(root): | 162 for walkinfo in walk(root): |
134 yield walkinfo | 163 yield walkinfo |
135 | 164 |
136 def __repr__(self): | 165 def __repr__(self): |
137 return '<%s>' % type(self).__name__ | 166 return '<%s>' % type(self).__name__ |
138 | 167 |
139 def __str__(self): | 168 def __str__(self): |
140 return repr(self) | 169 return repr(self) |
OLD | NEW |