annotate upreckon/files.py @ 209:c03a8113685d

Rewrote files.regexp as files.File.regexp (a class method) I still dislike the iterative code though.
author Oleg Oshmyan <chortos@inbox.lv>
date Thu, 18 Aug 2011 02:41:46 +0300
parents ede78fbd509a
children 1cbe2c428942
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)
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)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
233 for filename in intpath))
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
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
300 def _add_virtual(self, filename):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
301 return File(posixpath.join(self.virtual_path, filename),
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
302 self._external_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
303 self._internal_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
304 self.archive,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
305 self._has_tests)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
306
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
307 def __add__(self, filename, add_virtual=True):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
308 if not isinstance(filename, basestring):
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
309 return NotImplemented
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
310 if add_virtual:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
311 virtual_path = posixpath.join(self.virtual_path, filename)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
312 else:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
313 virtual_path = self.virtual_path
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
314 if self.archive:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
315 return File(virtual_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
316 self._external_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
317 posixpath.join(self._internal_path, filename),
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
318 self.archive,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
319 self._has_tests)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
320 else:
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
321 filename = filename.replace('.', os.path.extsep)
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
322 return File(virtual_path,
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
323 os.path.join(self._external_path, filename),
ede78fbd509a Revamped files.File
Oleg Oshmyan <chortos@inbox.lv>
parents: 197
diff changeset
324 _has_tests=self._has_tests)
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
325
209
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
326 @classmethod
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
327 def regexp(cls, pattern):
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
328 if not pattern:
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
329 yield cls('', os.curdir)
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
330 return
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
331 dirname, basename = posixpath.split(pattern)
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
332 dirs = cls.regexp(dirname)
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
333 reobj = re.compile(pattern + '$', re.UNICODE)
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
334 while dirs:
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
335 newdirs = []
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
336 for directory in dirs:
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
337 try:
209
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
338 names = directory.listdir()
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
339 except Exception:
196
67088c1765b4 Regexps now work with test archives
Oleg Oshmyan <chortos@inbox.lv>
parents: 195
diff changeset
340 continue
209
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
341 for name in names:
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
342 dir_entry = directory + name
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
343 if re.match(reobj, dir_entry.virtual_path):
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
344 yield dir_entry
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
345 if not directory._has_tests:
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
346 if name == 'tests':
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
347 dir_entry = directory.__add__(name, False)
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
348 dir_entry._has_tests = True
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
349 newdirs.append(dir_entry)
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
350 elif not directory.archive and name in archives:
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
351 newdirs.append(directory.__add__(name, False))
c03a8113685d Rewrote files.regexp as files.File.regexp (a class method)
Oleg Oshmyan <chortos@inbox.lv>
parents: 208
diff changeset
352 dirs = newdirs