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):