Mercurial > ~astiob > upreckon > hgweb
comparison upreckon/files.py @ 208:ede78fbd509a
Revamped files.File
This changes (simplifies) file search path:
* when searching for testconf, .../testconf.py is now given precendence
over .../tests/testconf.py;
* when searching inside archives, a/tests/b/c is now given precedence
over a/c.
author | Oleg Oshmyan <chortos@inbox.lv> |
---|---|
date | Thu, 18 Aug 2011 02:20:24 +0300 |
parents | 79f4f2fdeead |
children | c03a8113685d |
comparison
equal
deleted
inserted
replaced
207:946e8c09ba12 | 208:ede78fbd509a |
---|---|
207 else: | 207 else: |
208 open_archives[path] = archive = Archive(path) | 208 open_archives[path] = archive = Archive(path) |
209 return archive | 209 return archive |
210 | 210 |
211 class File(object): | 211 class File(object): |
212 __slots__ = 'virtual_path', 'real_path', 'full_real_path', 'archive' | 212 __slots__ = ('virtual_path', 'archive', |
213 | 213 '_external_path', '_internal_path', '_has_tests') |
214 def __init__(self, virtpath, allow_root=False, msg='test data'): | 214 |
215 self.virtual_path = virtpath | 215 def __init__(self, _virtual_path='', _external_path='', _internal_path='', |
216 self.archive = None | 216 _archive=None, _has_tests=False): |
217 if not self.realize_path('', tuple(comp.replace('.', os.path.extsep) for comp in virtpath.split('/')), allow_root): | 217 self.virtual_path = _virtual_path |
218 raise IOError("%s file '%s' could not be found" % (msg, virtpath)) | 218 self._external_path = _external_path |
219 | 219 self._internal_path = _internal_path |
220 def realize_path(self, root, virtpath, allow_root=False, hastests=False): | 220 self.archive = _archive |
221 if root and not os.path.exists(root): | 221 self._has_tests = _has_tests |
222 return False | 222 if not _archive: |
223 if len(virtpath) > 1: | 223 try: |
224 if self.realize_path(os.path.join(root, virtpath[0]), virtpath[1:], allow_root, hastests): | 224 self.archive = open_archive(_external_path) |
225 return True | 225 except Exception: |
226 elif not hastests: | 226 pass |
227 if self.realize_path(os.path.join(root, 'tests'), virtpath, allow_root, True): | 227 |
228 return True | 228 @property |
229 for archive in archives: | 229 def full_real_path(self): |
230 path = os.path.join(root, archive) | 230 intpath = self._internal_path.split('/') if self._internal_path else () |
231 if os.path.exists(path): | 231 return os.path.join(self._external_path, |
232 if self.realize_path_archive(open_archive(path), '', virtpath, path): | 232 *(filename.replace('.', os.path.extsep) |
233 return True | 233 for filename in intpath)) |
234 if self.realize_path(root, virtpath[1:], allow_root, hastests): | 234 |
235 return True | 235 def exists(self): |
236 else: | 236 if self.archive: |
237 if not hastests: | 237 return self.archive.exists(self._internal_path) |
238 path = os.path.join(root, 'tests', virtpath[0]) | 238 else: |
239 if os.path.exists(path): | 239 return (not self._external_path or |
240 self.full_real_path = self.real_path = path | 240 os.path.exists(self._external_path)) |
241 return True | |
242 for archive in archives: | |
243 path = os.path.join(root, archive) | |
244 if os.path.exists(path): | |
245 if self.realize_path_archive(open_archive(path), '', virtpath, path): | |
246 return True | |
247 if hastests or allow_root: | |
248 path = os.path.join(root, virtpath[0]) | |
249 if os.path.exists(path): | |
250 self.full_real_path = self.real_path = path | |
251 return True | |
252 return False | |
253 | |
254 def realize_path_archive(self, archive, root, virtpath, archpath, hastests=False): | |
255 if root and not archive.exists(root): | |
256 return False | |
257 path = posixpath.join(root, virtpath[0]) | |
258 if len(virtpath) > 1: | |
259 if self.realize_path_archive(archive, path, virtpath[1:], archpath): | |
260 return True | |
261 elif self.realize_path_archive(archive, root, virtpath[1:], archpath): | |
262 return True | |
263 else: | |
264 if archive.exists(path): | |
265 self.archive = archive | |
266 self.real_path = path | |
267 self.full_real_path = os.path.join(archpath, *path.split('/')) | |
268 return True | |
269 if not hastests: | |
270 if self.realize_path_archive(archive, posixpath.join(root, 'tests'), virtpath, archpath, True): | |
271 return True | |
272 return False | |
273 | 241 |
274 def open(self): | 242 def open(self): |
275 if self.archive: | 243 if self.archive: |
276 file = self.archive.open(self.real_path) | 244 file = self.archive.open(self._internal_path) |
277 if hasattr(file, '__exit__'): | 245 if hasattr(file, '__exit__'): |
278 return file | 246 return file |
279 else: | 247 else: |
280 return contextlib.closing(file) | 248 return contextlib.closing(file) |
281 else: | 249 else: |
282 return open(self.real_path, 'rb') | 250 return open(self._external_path, 'rb') |
283 | 251 |
284 def copy(self, target): | 252 def copy(self, target): |
285 if self.archive: | 253 if self.archive: |
286 self.archive.extract(self.real_path, target) | 254 self.archive.extract(self._internal_path, target) |
287 else: | 255 else: |
288 shutil.copy(self.real_path, target) | 256 shutil.copy(self._external_path, target) |
257 | |
258 def listdir(self): | |
259 if self.archive: | |
260 return self.archive.listdir(self._internal_path) | |
261 else: | |
262 return os.listdir(self._external_path) | |
263 | |
264 @classmethod | |
265 def from_virtual_path(cls, virtual_path, allow_root, msg): | |
266 metafile = cls()._realize_path(virtual_path.split('/'), allow_root) | |
267 if not metafile: | |
268 raise IOError("%s file with virtual path %r could not be found" % | |
269 (msg, virtual_path)) | |
270 assert metafile.virtual_path == virtual_path | |
271 return metafile | |
272 | |
273 def _realize_path(self, virtpath, allow_root): | |
274 if not self.exists(): | |
275 return None | |
276 elif not virtpath: | |
277 if allow_root or self._has_tests or self.archive: | |
278 return self | |
279 return None | |
280 cand = (self + virtpath[0])._realize_path(virtpath[1:], allow_root) | |
281 if cand: return cand | |
282 if not cand and not self._has_tests: | |
283 for metafile in self._add_tests(): | |
284 cand = metafile._realize_path(virtpath, allow_root) | |
285 if cand: return cand | |
286 if not cand and len(virtpath) > 1: | |
287 metafile = self._add_virtual(virtpath[0]) | |
288 cand = metafile._realize_path(virtpath[1:], allow_root) | |
289 if cand: return cand | |
290 | |
291 def _add_tests(self): | |
292 assert not self._has_tests | |
293 metafile = self.__add__('tests', False) | |
294 metafile._has_tests = True | |
295 yield metafile | |
296 if not self.archive: | |
297 for filename in archives: | |
298 yield self.__add__(filename, False) | |
299 | |
300 def _add_virtual(self, filename): | |
301 return File(posixpath.join(self.virtual_path, filename), | |
302 self._external_path, | |
303 self._internal_path, | |
304 self.archive, | |
305 self._has_tests) | |
306 | |
307 def __add__(self, filename, add_virtual=True): | |
308 if not isinstance(filename, basestring): | |
309 return NotImplemented | |
310 if add_virtual: | |
311 virtual_path = posixpath.join(self.virtual_path, filename) | |
312 else: | |
313 virtual_path = self.virtual_path | |
314 if self.archive: | |
315 return File(virtual_path, | |
316 self._external_path, | |
317 posixpath.join(self._internal_path, filename), | |
318 self.archive, | |
319 self._has_tests) | |
320 else: | |
321 filename = filename.replace('.', os.path.extsep) | |
322 return File(virtual_path, | |
323 os.path.join(self._external_path, filename), | |
324 _has_tests=self._has_tests) | |
289 | 325 |
290 class RegexpMatchFile(object): | 326 class RegexpMatchFile(object): |
291 __slots__ = 'virtual_path', 'real_path', 'hastests', 'archive' | 327 __slots__ = 'virtual_path', 'real_path', 'hastests', 'archive' |
292 | 328 |
293 def __init__(self, virtual_path, real_path, hastests=False, archive=None): | 329 def __init__(self, virtual_path, real_path, hastests=False, archive=None): |