annotate upreckon/files.py @ 246:1bc89faac941 2.04

Fixed: match='re' could produce duplicate test identifiers files.Files.regexp(pattern) now makes sure to return only one metafile for each matching virtual path, namely, the one that would be returned for that virtual path by files.Files.from_virtual_path.
author Oleg Oshmyan <chortos@inbox.lv>
date Thu, 03 Oct 2013 01:19:09 +0300
parents 7827e63cd148
children f5847d29e838
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
194
8c30a2c8a09e Updated copyright years in files.py
Oleg Oshmyan <chortos@inbox.lv>
parents: 193
diff changeset
1 # Copyright (c) 2010-2011 Chortos-2 <chortos@inbox.lv>
16
f2279b7602d3 Initial 2.00 commit
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
2
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
3 """File access routines and classes with support for archives."""
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
4
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
5 from __future__ import division, with_statement
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
6
146
d5b6708c1955 Distutils support, reorganization and cleaning up
Oleg Oshmyan <chortos@inbox.lv>
parents: 133
diff changeset
7 from .compat import *
212
1cbe2c428942 Cleaned up import statements
Oleg Oshmyan <chortos@inbox.lv>
parents: 209
diff changeset
8 import contextlib, os, posixpath, re, shutil
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
9
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
10 # You don't need to know about anything else.
193
a76cdc26ba9d Added conf. var. match and match='regexp' for non-archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 178
diff changeset
11 __all__ = 'File', 'regexp'
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
12
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
13 # In these two variables, use full stops no matter what os.extsep is;
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
14 # all full stops will be converted to os.extsep on the fly
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
15 archives = 'tests.tar', 'tests.zip', 'tests.tgz', 'tests.tar.gz', 'tests.tbz2', 'tests.tar.bz2'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
16 formats = {}
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
17
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
18 class Archive(object):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
19 __slots__ = ()
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
20
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
21 if ABCMeta:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
22 __metaclass__ = ABCMeta
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
23
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
24 def __new__(cls, path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
25 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
26 Create a new instance of the archive class corresponding
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
27 to the file name in the given path.
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
28 """
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
29 if cls is not Archive:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
30 return object.__new__(cls)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
31 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
32 # Do this by hand rather than through os.path.splitext
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
33 # because we support multi-dotted file name extensions
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
34 ext = path.partition(os.path.extsep)[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
35 while ext:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
36 if ext in formats:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
37 return formats[ext](path)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
38 ext = ext.partition(os.path.extsep)[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
39 raise LookupError("unsupported archive file name extension in file name '%s'" % filename)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
40
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
41 @abstractmethod
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
42 def __init__(self, path): raise NotImplementedError
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
43
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
44 @abstractmethod
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
45 def extract(self, name, target): raise NotImplementedError
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
46
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
47 @abstractmethod
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
48 def open(self, name): raise NotImplementedError
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
49
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
50 @abstractmethod
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
51 def exists(self, name): raise NotImplementedError
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
52
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
53 @abstractmethod
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
54 def listdir(self, name): raise NotImplementedError
16
f2279b7602d3 Initial 2.00 commit
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
55
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
56 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
57 import tarfile
31
fe1463e7e24d Clean up try-except clauses
Oleg Oshmyan <chortos@inbox.lv>
parents: 23
diff changeset
58 except ImportError:
fe1463e7e24d Clean up try-except clauses
Oleg Oshmyan <chortos@inbox.lv>
parents: 23
diff changeset
59 TarArchive = None
fe1463e7e24d Clean up try-except clauses
Oleg Oshmyan <chortos@inbox.lv>
parents: 23
diff changeset
60 else:
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
61 class TarArchive(Archive):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
62 __slots__ = '_tarfile', '_files', '_dirs', '_names'
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
63
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
64 def __init__(self, path):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
65 self._tarfile = tarfile.open(path)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
66 files, dirs = {}, set(('/',))
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
67 for member in self._tarfile.getmembers():
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
68 cutname = posixpath.normpath('/' + member.name)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
69 if cutname == '/':
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
70 continue
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
71 if member.isfile():
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
72 files[cutname] = member
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
73 cutname = posixpath.dirname(cutname)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
74 elif not member.isdir():
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
75 continue
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
76 while cutname != '/':
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
77 dirs.add(cutname)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
78 cutname = posixpath.dirname(cutname)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
79 self._files = files
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
80 self._dirs = frozenset(dirs)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
81 self._names = self._dirs | frozenset(files)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
82
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
83 def extract(self, name, target):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
84 member = self._files[posixpath.normpath('/' + name)]
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
85 member.name = target
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
86 self._tarfile.extract(member)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
87
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
88 def open(self, name):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
89 name = posixpath.normpath('/' + name)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
90 return self._tarfile.extractfile(self._files[name])
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
91
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
92 def exists(self, name):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
93 return posixpath.normpath('/' + name) in self._names
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
94
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
95 def listdir(self, name):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
96 normname = posixpath.normpath('/' + name)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
97 if normname not in self._dirs:
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
98 raise KeyError('No such directory: %r' % name)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
99 if normname != '/':
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
100 normname += '/'
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
101 nnlen = len(normname)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
102 return [fname[nnlen:] for fname in self._names
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
103 if fname.startswith(normname) and
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
104 fname.find('/', nnlen) == -1]
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
105
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
106 def __enter__(self):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
107 if hasattr(self._tarfile, '__enter__'):
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
108 self._tarfile.__enter__()
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
109 return self
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
110
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
111 def __exit__(self, exc_type, exc_value, traceback):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
112 if hasattr(self._tarfile, '__exit__'):
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
113 return self._tarfile.__exit__(exc_type, exc_value, traceback)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
114 elif exc_type is None:
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
115 self._tarfile.close()
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
116 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
117 # This code was shamelessly copied from tarfile.py of Python 2.7
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
118 if not self._tarfile._extfileobj:
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
119 self._tarfile.fileobj.close()
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
120 self._tarfile.closed = True
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
121
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
122 formats['tar'] = formats['tgz'] = formats['tar.gz'] = formats['tbz2'] = formats['tar.bz2'] = TarArchive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
123
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
124 try:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
125 import zipfile
31
fe1463e7e24d Clean up try-except clauses
Oleg Oshmyan <chortos@inbox.lv>
parents: 23
diff changeset
126 except ImportError:
fe1463e7e24d Clean up try-except clauses
Oleg Oshmyan <chortos@inbox.lv>
parents: 23
diff changeset
127 ZipArchive = None
fe1463e7e24d Clean up try-except clauses
Oleg Oshmyan <chortos@inbox.lv>
parents: 23
diff changeset
128 else:
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
129 class ZipArchive(Archive):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
130 __slots__ = '_zipfile', '_files', '_dirs', '_names'
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
131
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
132 def __init__(self, path):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
133 self._zipfile = zipfile.ZipFile(path)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
134 files, dirs = {}, set(('/',))
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
135 for member in self._zipfile.infolist():
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
136 cutname = posixpath.normpath('/' + member.filename)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
137 if not member.filename.endswith('/'):
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
138 files[cutname] = member
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
139 cutname = posixpath.dirname(cutname)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
140 while cutname != '/':
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
141 dirs.add(cutname)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
142 cutname = posixpath.dirname(cutname)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
143 self._files = files
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
144 self._dirs = frozenset(dirs)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
145 self._names = self._dirs | frozenset(files)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
146
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
147 def extract(self, name, target):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
148 member = self._files[posixpath.normpath('/' + name)]
98
62a96d51bf94 Fixed ZipArchive.extract with relative paths on Windows
Oleg Oshmyan <chortos@inbox.lv>
parents: 91
diff changeset
149 # FIXME: 2.5 lacks ZipFile.extract
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
150 if os.path.isabs(target):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
151 # To my knowledge, this is as portable as it gets
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
152 path = os.path.join(os.path.splitdrive(target)[0], os.path.sep)
98
62a96d51bf94 Fixed ZipArchive.extract with relative paths on Windows
Oleg Oshmyan <chortos@inbox.lv>
parents: 91
diff changeset
153 member.filename = os.path.relpath(target, path)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
154 self._zipfile.extract(member, path)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
155 else:
98
62a96d51bf94 Fixed ZipArchive.extract with relative paths on Windows
Oleg Oshmyan <chortos@inbox.lv>
parents: 91
diff changeset
156 member.filename = os.path.relpath(target)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
157 self._zipfile.extract(member)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
158
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
159 def open(self, name):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
160 name = posixpath.normpath('/' + name)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
161 # FIXME: 2.5 lacks ZipFile.open
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
162 return self._zipfile.open(self._files[name])
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
163
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
164 def exists(self, name):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
165 return posixpath.normpath('/' + name) in self._names
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
166
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
167 def listdir(self, name):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
168 normname = posixpath.normpath('/' + name)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
169 if normname not in self._dirs:
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
170 raise KeyError('No such directory: %r' % name)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
171 if normname != '/':
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
172 normname += '/'
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
173 nnlen = len(normname)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
174 return [fname[nnlen:] for fname in self._names
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
175 if fname.startswith(normname) and
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
176 fname.find('/', nnlen) == -1]
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
177
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
178 def __enter__(self):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
179 if hasattr(self._zipfile, '__enter__'):
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
180 self._zipfile.__enter__()
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
181 return self
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
182
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
183 def __exit__(self, exc_type, exc_value, traceback):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
184 if hasattr(self._zipfile, '__exit__'):
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
185 return self._zipfile.__exit__(exc_type, exc_value, traceback)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
186 else:
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
187 return self._zipfile.close()
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
188
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
189 formats['zip'] = ZipArchive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
190
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
191 # Remove unsupported archive formats and replace full stops
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
192 # with the platform-dependent file name extension separator
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
193 def issupported(filename, formats=formats):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
194 ext = filename.partition('.')[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
195 while ext:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
196 if ext in formats: return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
197 ext = ext.partition('.')[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
198 return False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
199 archives = [filename.replace('.', os.path.extsep) for filename in filter(issupported, archives)]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
200 formats = dict((item[0].replace('.', os.path.extsep), item[1]) for item in items(formats))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
201
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
202 open_archives = {}
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
203
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
204 def open_archive(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
205 if path in open_archives:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
206 return open_archives[path]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
207 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
208 open_archives[path] = archive = Archive(path)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
209 return archive
16
f2279b7602d3 Initial 2.00 commit
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
210
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
211 class File(object):
208
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
212 __slots__ = ('virtual_path', 'archive',
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
213 '_external_path', '_internal_path', '_has_tests')
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
214
208
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
215 def __init__(self, _virtual_path='', _external_path='', _internal_path='',
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
216 _archive=None, _has_tests=False):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
217 self.virtual_path = _virtual_path
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
218 self._external_path = _external_path
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
219 self._internal_path = _internal_path
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
220 self.archive = _archive
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
221 self._has_tests = _has_tests
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
222 if not _archive:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
223 try:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
224 self.archive = open_archive(_external_path)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
225 except Exception:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
226 pass
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
227
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
228 @property
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
229 def full_real_path(self):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
230 intpath = self._internal_path.split('/') if self._internal_path else ()
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
231 return os.path.join(self._external_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
232 *(filename.replace('.', os.path.extsep)
219
7827e63cd148 Corrected a wrongly indented line
Oleg Oshmyan <chortos@inbox.lv>
parents: 212
diff changeset
233 for filename in intpath))
208
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
234
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
235 def exists(self):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
236 if self.archive:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
237 return self.archive.exists(self._internal_path)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
238 else:
208
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
239 return (not self._external_path or
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
240 os.path.exists(self._external_path))
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
241
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
242 def open(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
243 if self.archive:
208
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
244 file = self.archive.open(self._internal_path)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
245 if hasattr(file, '__exit__'):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
246 return file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
247 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
248 return contextlib.closing(file)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
249 else:
208
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
250 return open(self._external_path, 'rb')
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
251
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
252 def copy(self, target):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
253 if self.archive:
208
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
254 self.archive.extract(self._internal_path, target)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
255 else:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
256 shutil.copy(self._external_path, target)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
257
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
258 def listdir(self):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
259 if self.archive:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
260 return self.archive.listdir(self._internal_path)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
261 else:
208
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
262 return os.listdir(self._external_path)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
263
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
264 @classmethod
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
265 def from_virtual_path(cls, virtual_path, allow_root, msg):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
266 metafile = cls()._realize_path(virtual_path.split('/'), allow_root)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
267 if not metafile:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
268 raise IOError("%s file with virtual path %r could not be found" %
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
269 (msg, virtual_path))
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
270 assert metafile.virtual_path == virtual_path
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
271 return metafile
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
272
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
273 def _realize_path(self, virtpath, allow_root):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
274 if not self.exists():
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
275 return None
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
276 elif not virtpath:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
277 if allow_root or self._has_tests or self.archive:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
278 return self
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
279 return None
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
280 cand = (self + virtpath[0])._realize_path(virtpath[1:], allow_root)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
281 if cand: return cand
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
282 if not cand and not self._has_tests:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
283 for metafile in self._add_tests():
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
284 cand = metafile._realize_path(virtpath, allow_root)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
285 if cand: return cand
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
286 if not cand and len(virtpath) > 1:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
287 metafile = self._add_virtual(virtpath[0])
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
288 cand = metafile._realize_path(virtpath[1:], allow_root)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
289 if cand: return cand
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
290
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
291 def _add_tests(self):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
292 assert not self._has_tests
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
293 metafile = self.__add__('tests', False)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
294 metafile._has_tests = True
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
295 yield metafile
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
296 if not self.archive:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
297 for filename in archives:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
298 yield self.__add__(filename, False)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
299
246
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
300 def _also_add_tests(self):
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
301 yield self
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
302 if not self._has_tests:
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
303 for metafile in self._add_tests():
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
304 yield metafile
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
305
208
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
306 def _add_virtual(self, filename):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
307 return File(posixpath.join(self.virtual_path, filename),
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
308 self._external_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
309 self._internal_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
310 self.archive,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
311 self._has_tests)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
312
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
313 def __add__(self, filename, add_virtual=True):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
314 if not isinstance(filename, basestring):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
315 return NotImplemented
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
316 if add_virtual:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
317 virtual_path = posixpath.join(self.virtual_path, filename)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
318 else:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
319 virtual_path = self.virtual_path
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
320 if self.archive:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
321 return File(virtual_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
322 self._external_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
323 posixpath.join(self._internal_path, filename),
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
324 self.archive,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
325 self._has_tests)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
326 else:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
327 filename = filename.replace('.', os.path.extsep)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
328 return File(virtual_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
329 os.path.join(self._external_path, filename),
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
330 _has_tests=self._has_tests)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
331
209
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
332 @classmethod
246
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
333 def regexp(cls, pattern, _unique=True):
209
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
334 if not pattern:
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
335 yield cls('', os.curdir)
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
336 return
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
337 dirname, basename = posixpath.split(pattern)
246
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
338 dirs = cls.regexp(dirname, False)
209
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
339 reobj = re.compile(pattern + '$', re.UNICODE)
246
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
340 if _unique:
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
341 yielded = set()
209
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
342 while dirs:
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
343 newdirs = []
246
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
344 for testless_directory in dirs:
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
345 for directory in testless_directory._also_add_tests():
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
346 try:
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
347 names = directory.listdir()
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
348 except Exception:
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
349 continue
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
350 for name in names:
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
351 dir_entry = directory + name
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
352 if re.match(reobj, dir_entry.virtual_path):
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
353 if not _unique:
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
354 yield dir_entry
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
355 elif dir_entry.virtual_path not in yielded:
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
356 yield dir_entry
1bc89faac941 Fixed: match='re' could produce duplicate test identifiers
Oleg Oshmyan <chortos@inbox.lv>
parents: 219
diff changeset
357 yielded.add(dir_entry.virtual_path)
209
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
358 dirs = newdirs