annotate upreckon/files.py @ 196:67088c1765b4

Regexps now work with test archives Excuse me while I rewrite files.{File,regexp} almost from scratch...
author Oleg Oshmyan <chortos@inbox.lv>
date Mon, 15 Aug 2011 19:52:58 +0300
parents c2490e39fd70
children 79f4f2fdeead
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 *
193
a76cdc26ba9d Added conf. var. match and match='regexp' for non-archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 178
diff changeset
8 import contextlib, itertools, os, posixpath, re, shutil, sys
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)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
137 if cutname == '/':
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
138 continue
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
139 if not member.filename.endswith('/'):
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
140 files[cutname] = member
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
141 cutname = posixpath.dirname(cutname)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
142 while cutname != '/':
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
143 dirs.add(cutname)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
144 cutname = posixpath.dirname(cutname)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
145 self._files = files
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
146 self._dirs = frozenset(dirs)
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
147 self._names = self._dirs | frozenset(files)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
148
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
149 def extract(self, name, target):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
150 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
151 # FIXME: 2.5 lacks ZipFile.extract
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
152 if os.path.isabs(target):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
153 # To my knowledge, this is as portable as it gets
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
154 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
155 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
156 self._zipfile.extract(member, path)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
157 else:
98
62a96d51bf94 Fixed ZipArchive.extract with relative paths on Windows
Oleg Oshmyan <chortos@inbox.lv>
parents: 91
diff changeset
158 member.filename = os.path.relpath(target)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
159 self._zipfile.extract(member)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
160
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
161 def open(self, name):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
162 name = posixpath.normpath('/' + name)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
163 # FIXME: 2.5 lacks ZipFile.open
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
164 return self._zipfile.open(self._files[name])
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
165
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
166 def exists(self, name):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
167 return posixpath.normpath('/' + name) in self._names
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
168
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
169 def listdir(self, name):
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
170 normname = posixpath.normpath('/' + name)
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
171 if normname not in self._dirs:
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
172 raise KeyError('No such directory: %r' % name)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
173 if normname != '/':
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
174 normname += '/'
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
175 nnlen = len(normname)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
176 return [fname[nnlen:] for fname in self._names
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
177 if fname.startswith(normname) and
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
178 fname.find('/', nnlen) == -1]
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
179
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
180 def __enter__(self):
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
181 if hasattr(self._zipfile, '__enter__'):
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
182 self._zipfile.__enter__()
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
183 return self
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
184
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
185 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
186 if hasattr(self._zipfile, '__exit__'):
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
187 return self._zipfile.__exit__(exc_type, exc_value, traceback)
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
188 else:
195
c2490e39fd70 Revamped the implementation of files.Archive subclasses
Oleg Oshmyan <chortos@inbox.lv>
parents: 194
diff changeset
189 return self._zipfile.close()
21
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 formats['zip'] = ZipArchive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
192
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
193 # Remove unsupported archive formats and replace full stops
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
194 # with the platform-dependent file name extension separator
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
195 def issupported(filename, formats=formats):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
196 ext = filename.partition('.')[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
197 while ext:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
198 if ext in formats: return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
199 ext = ext.partition('.')[2]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
200 return False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
201 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
202 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
203
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
204 open_archives = {}
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
205
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
206 def open_archive(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
207 if path in open_archives:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
208 return open_archives[path]
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
209 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
210 open_archives[path] = archive = Archive(path)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
211 return archive
16
f2279b7602d3 Initial 2.00 commit
Oleg Oshmyan <chortos@inbox.lv>
parents:
diff changeset
212
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
213 class File(object):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
214 __slots__ = 'virtual_path', 'real_path', 'full_real_path', 'archive'
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
215
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
216 def __init__(self, virtpath, allow_root=False, msg='test data'):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
217 self.virtual_path = virtpath
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
218 self.archive = None
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
219 if not self.realize_path('', tuple(comp.replace('.', os.path.extsep) for comp in virtpath.split('/')), allow_root):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
220 raise IOError("%s file '%s' could not be found" % (msg, virtpath))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
221
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
222 def realize_path(self, root, virtpath, allow_root=False, hastests=False):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
223 if root and not os.path.exists(root):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
224 return False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
225 if len(virtpath) > 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
226 if self.realize_path(os.path.join(root, virtpath[0]), virtpath[1:], allow_root, hastests):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
227 return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
228 elif not hastests:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
229 if self.realize_path(os.path.join(root, 'tests'), virtpath, allow_root, True):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
230 return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
231 for archive in archives:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
232 path = os.path.join(root, archive)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
233 if os.path.exists(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
234 if self.realize_path_archive(open_archive(path), '', virtpath, path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
235 return True
23
c1f52b5d80d6 Compatibility and bug fixes
Oleg Oshmyan <chortos@inbox.lv>
parents: 21
diff changeset
236 if self.realize_path(root, virtpath[1:], allow_root, hastests):
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
237 return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
238 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
239 if not hastests:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
240 path = os.path.join(root, 'tests', virtpath[0])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
241 if os.path.exists(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
242 self.full_real_path = self.real_path = path
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
243 return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
244 for archive in archives:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
245 path = os.path.join(root, archive)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
246 if os.path.exists(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
247 if self.realize_path_archive(open_archive(path), '', virtpath, path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
248 return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
249 if hastests or allow_root:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
250 path = os.path.join(root, virtpath[0])
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
251 if os.path.exists(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
252 self.full_real_path = self.real_path = path
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
253 return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
254 return False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
255
178
0d657576b1ac tests directories are now searched for within archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 174
diff changeset
256 def realize_path_archive(self, archive, root, virtpath, archpath, hastests=False):
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
257 if root and not archive.exists(root):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
258 return False
178
0d657576b1ac tests directories are now searched for within archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 174
diff changeset
259 path = posixpath.join(root, virtpath[0])
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
260 if len(virtpath) > 1:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
261 if self.realize_path_archive(archive, path, virtpath[1:], archpath):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
262 return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
263 elif self.realize_path_archive(archive, root, virtpath[1:], archpath):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
264 return True
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
265 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
266 if archive.exists(path):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
267 self.archive = archive
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
268 self.real_path = path
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
269 self.full_real_path = os.path.join(archpath, *path.split('/'))
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
270 return True
178
0d657576b1ac tests directories are now searched for within archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 174
diff changeset
271 if not hastests:
0d657576b1ac tests directories are now searched for within archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 174
diff changeset
272 if self.realize_path_archive(archive, posixpath.join(root, 'tests'), virtpath, archpath, True):
0d657576b1ac tests directories are now searched for within archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 174
diff changeset
273 return True
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
274 return False
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
275
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
276 def open(self):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
277 if self.archive:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
278 file = self.archive.open(self.real_path)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
279 if hasattr(file, '__exit__'):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
280 return file
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
281 else:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
282 return contextlib.closing(file)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
283 else:
174
e0b2fbd7ebe0 Improved built-in output validator; added conf. var. binary
Oleg Oshmyan <chortos@inbox.lv>
parents: 155
diff changeset
284 return open(self.real_path, 'rb')
21
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
285
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
286 def copy(self, target):
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
287 if self.archive:
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
288 self.archive.extract(self.real_path, target)
ec6f1a132109 A pretty usable version
Oleg Oshmyan <chortos@inbox.lv>
parents: 16
diff changeset
289 else:
193
a76cdc26ba9d Added conf. var. match and match='regexp' for non-archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 178
diff changeset
290 shutil.copy(self.real_path, target)
a76cdc26ba9d Added conf. var. match and match='regexp' for non-archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 178
diff changeset
291
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
292 class RegexpMatchFile(object):
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
293 __slots__ = 'virtual_path', 'real_path', 'hastests', 'archive'
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
294
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
295 def __init__(self, virtual_path, real_path, hastests=False, archive=None):
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
296 self.virtual_path = virtual_path
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
297 self.real_path = real_path
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
298 self.hastests = hastests
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
299 self.archive = archive
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
300
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
301 def regexp(pattern):
193
a76cdc26ba9d Added conf. var. match and match='regexp' for non-archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 178
diff changeset
302 if not pattern:
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
303 yield RegexpMatchFile('', os.curdir)
193
a76cdc26ba9d Added conf. var. match and match='regexp' for non-archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 178
diff changeset
304 return
a76cdc26ba9d Added conf. var. match and match='regexp' for non-archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 178
diff changeset
305 dirname, basename = posixpath.split(pattern)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
306 dirs = regexp(dirname)
193
a76cdc26ba9d Added conf. var. match and match='regexp' for non-archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 178
diff changeset
307 reobj = re.compile(pattern + '$', re.UNICODE)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
308 while dirs:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
309 newdirs = []
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
310 for directory in dirs:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
311 if directory.archive:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
312 try:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
313 names = directory.archive.listdir(directory.real_path)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
314 except KeyError:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
315 continue
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
316 join = posixpath.join
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
317 else:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
318 try:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
319 names = os.listdir(directory.real_path)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
320 except OSError:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
321 continue
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
322 join = posixpath.join
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
323 for name in names:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
324 path = join(directory.real_path, name)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
325 vpath = posixpath.join(directory.virtual_path, name)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
326 if re.match(reobj, vpath):
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
327 yield RegexpMatchFile(vpath, path, directory.hastests, directory.archive)
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
328 if not directory.hastests:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
329 if name == 'tests':
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
330 newdirs.append(RegexpMatchFile(directory.virtual_path, path, True, directory.archive))
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
331 if not directory.archive and name in archives:
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
332 newdirs.append(RegexpMatchFile(directory.virtual_path, '', False, open_archive(path)))
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
333 dirs = newdirs