1 |
commit: d824fed46faebd39b81983a8f8938bd69970c307 |
2 |
Author: André Erdmann <dywi <AT> mailerd <DOT> de> |
3 |
AuthorDate: Fri Aug 30 13:47:49 2013 +0000 |
4 |
Commit: André Erdmann <dywi <AT> mailerd <DOT> de> |
5 |
CommitDate: Fri Aug 30 13:49:58 2013 +0000 |
6 |
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=d824fed4 |
7 |
|
8 |
distmap: volatile entries, use roverlay.util.fileio |
9 |
|
10 |
* 'volatile' status indicator for distmap info entries that are not (yet) |
11 |
persistent |
12 |
* use common (un)compressed file read/write code from roverlay.util.fileio |
13 |
|
14 |
--- |
15 |
roverlay/db/distmap.py | 253 ++++++++++++++++++--------------------------- |
16 |
roverlay/recipe/distmap.py | 2 +- |
17 |
2 files changed, 99 insertions(+), 156 deletions(-) |
18 |
|
19 |
diff --git a/roverlay/db/distmap.py b/roverlay/db/distmap.py |
20 |
index b3b285c..47cfa27 100644 |
21 |
--- a/roverlay/db/distmap.py |
22 |
+++ b/roverlay/db/distmap.py |
23 |
@@ -14,6 +14,7 @@ import shutil |
24 |
|
25 |
import roverlay.digest |
26 |
import roverlay.util |
27 |
+import roverlay.util.fileio |
28 |
import roverlay.util.objects |
29 |
import roverlay.stats.collector |
30 |
|
31 |
@@ -38,7 +39,9 @@ class DistMapInfo ( object ): |
32 |
return key, cls ( *value ) |
33 |
# --- end of from_package_info (...) --- |
34 |
|
35 |
- def __init__ ( self, distfile, repo_name, repo_file, sha256 ): |
36 |
+ def __init__ ( |
37 |
+ self, distfile, repo_name, repo_file, sha256, volatile=False |
38 |
+ ): |
39 |
"""Distmap entry constructor. |
40 |
|
41 |
arguments: |
42 |
@@ -46,11 +49,14 @@ class DistMapInfo ( object ): |
43 |
* repo_name -- name of the repo that owns the package file |
44 |
* repo_file -- path of the package file relative to the repo |
45 |
* sha256 -- file checksum |
46 |
+ * volatile -- whether this entry should be persistent (False) or |
47 |
+ not (True). Defaults to False. |
48 |
""" |
49 |
super ( DistMapInfo, self ).__init__() |
50 |
|
51 |
self.repo_name = repo_name if repo_name is not None else self.UNSET |
52 |
self.sha256 = sha256 |
53 |
+ self.volatile = volatile |
54 |
|
55 |
# references to objects that "own" (use, ...) this distfile |
56 |
self.backrefs = set() |
57 |
@@ -113,6 +119,7 @@ class DistMapInfo ( object ): |
58 |
* field_delimiter -- char (or char sequence) that is used to separate |
59 |
values |
60 |
""" |
61 |
+ assert not self.volatile |
62 |
return ( field_delimiter.join (( |
63 |
distfile, |
64 |
self.repo_name, |
65 |
@@ -127,37 +134,6 @@ class DistMapInfo ( object ): |
66 |
# --- end of DistMapInfo --- |
67 |
|
68 |
|
69 |
-def get_distmap ( distmap_file, distmap_compression, ignore_missing=False ): |
70 |
- """Returns a new distmap instance. |
71 |
- |
72 |
- arguments: |
73 |
- * distmap_file -- file with distmap info entries |
74 |
- * distmap_compression -- distmap file compression format (None: disable) |
75 |
- * ignore_missing -- do not fail if distmap file does not exist? |
76 |
- |
77 |
- raises: ValueError if distmap_compression not supported. |
78 |
- """ |
79 |
- if not distmap_compression or ( |
80 |
- distmap_compression in { 'default', 'none' } |
81 |
- ): |
82 |
- return FileDistMap ( |
83 |
- distmap_file, ignore_missing=ignore_missing |
84 |
- ) |
85 |
- elif distmap_compression in { 'bz2', 'bzip2' }: |
86 |
- return Bzip2CompressedFileDistMap ( |
87 |
- distmap_file, ignore_missing=ignore_missing |
88 |
- ) |
89 |
- elif distmap_compression in { 'gz', 'gzip' }: |
90 |
- return GzipCompressedFileDistMap ( |
91 |
- distmap_file, ignore_missing=ignore_missing |
92 |
- ) |
93 |
- else: |
94 |
- raise ValueError ( |
95 |
- "unknown distmap_compression {!r}".format ( distmap_compression ) |
96 |
- ) |
97 |
-# --- end of get_distmap (...) --- |
98 |
- |
99 |
- |
100 |
class _DistMapBase ( object ): |
101 |
|
102 |
# { attr[, as_attr] } |
103 |
@@ -219,6 +195,18 @@ class _DistMapBase ( object ): |
104 |
self.dirty = True |
105 |
# --- end of _file_removed (...) --- |
106 |
|
107 |
+ def _iter_persistent ( self ): |
108 |
+ for distfile, info in self._distmap.items(): |
109 |
+ if not info.volatile: |
110 |
+ yield ( distfile, info ) |
111 |
+ # --- end of _iter_persistent (...) --- |
112 |
+ |
113 |
+ def _iter_volatile ( self ): |
114 |
+ for distfile, info in self._distmap.items(): |
115 |
+ if info.volatile: |
116 |
+ yield ( distfile, info ) |
117 |
+ # --- end of _iter_volatile (...) --- |
118 |
+ |
119 |
def _rebind_distmap ( self ): |
120 |
for attr in self.DISTMAP_BIND_ATTR: |
121 |
if isinstance ( attr, str ): |
122 |
@@ -239,12 +227,19 @@ class _DistMapBase ( object ): |
123 |
new_entry.add_backref ( backref ) |
124 |
# --- end of add_distfile_owner (...) --- |
125 |
|
126 |
+ def gen_info_lines ( self, field_delimiter ): |
127 |
+ for distfile, info in self._distmap.items(): |
128 |
+ if not info.volatile: |
129 |
+ yield info.to_str ( str ( distfile ), field_delimiter ) |
130 |
+ # --- end of gen_info_lines (...) --- |
131 |
+ |
132 |
def get_distfile_slot ( self, backref, distfile ): |
133 |
entry = self.get_entry ( distfile ) |
134 |
if entry is None: |
135 |
raise NotImplementedError ( "backref gets new 'slot'." ) |
136 |
return 1 |
137 |
elif entry.has_backref_to ( backref.deref_safe() ): |
138 |
+ # revbump check might be necessary |
139 |
return 2 |
140 |
else: |
141 |
raise NotImplementedError ( "handle file collision." ) |
142 |
@@ -461,7 +456,7 @@ class _DistMapBase ( object ): |
143 |
# --- end of _DistMapBase --- |
144 |
|
145 |
|
146 |
-class _FileDistMapBase ( _DistMapBase ): |
147 |
+class FileDistMap ( _DistMapBase ): |
148 |
"""A distmap that is read from / written to a file.""" |
149 |
|
150 |
# the default info field separator |
151 |
@@ -471,9 +466,35 @@ class _FileDistMapBase ( _DistMapBase ): |
152 |
# file format (reserved for future usage) |
153 |
FILE_FORMAT = '0' |
154 |
|
155 |
- def __init__ ( self, filepath, ignore_missing=False ): |
156 |
- super ( _FileDistMapBase, self ).__init__ () |
157 |
- self.dbfile = filepath |
158 |
+ def set_compression ( self, compression ): |
159 |
+ if not compression or compression in { 'default', 'none' }: |
160 |
+ self.compression = None |
161 |
+ elif compression in roverlay.util.fileio.SUPPORTED_COMPRESSION: |
162 |
+ self.compression = compression |
163 |
+ else: |
164 |
+ raise ValueError ( |
165 |
+ "unknown distmap compression {!r}".format ( compression ) |
166 |
+ ) |
167 |
+ # --- end of set_compression (...) --- |
168 |
+ |
169 |
+ def __init__ ( |
170 |
+ self, distmap_file, distmap_compression=None, ignore_missing=False |
171 |
+ ): |
172 |
+ """Constructor for a distmap that stores its information to a file, |
173 |
+ optionally compressed. |
174 |
+ |
175 |
+ arguments: |
176 |
+ * distmap_file -- file with distmap info entries |
177 |
+ * distmap_compression -- distmap file compression format (None: disable) |
178 |
+ * ignore_missing -- do not fail if distmap file does not exist? |
179 |
+ |
180 |
+ raises: ValueError if distmap_compression not supported. |
181 |
+ """ |
182 |
+ super ( FileDistMap, self ).__init__ () |
183 |
+ self.dbfile = distmap_file |
184 |
+ self.compression = None |
185 |
+ self.set_compression ( distmap_compression ) |
186 |
+ |
187 |
if ignore_missing: |
188 |
self.try_read() |
189 |
else: |
190 |
@@ -547,24 +568,24 @@ class _FileDistMapBase ( _DistMapBase ): |
191 |
raise |
192 |
# --- end of try_read (...) --- |
193 |
|
194 |
- def _file_written ( self, filepath ): |
195 |
- """Method that should be called after writing a distmap file.""" |
196 |
- self.dirty = self.dirty and ( filepath is not self.dbfile ) |
197 |
- # --- end of _file_written (...) --- |
198 |
+ def get_header ( self ): |
199 |
+ return "<{d}<{fmt}".format ( |
200 |
+ d=self.FIELD_DELIMITER, fmt=self.FILE_FORMAT |
201 |
+ ) |
202 |
+ # --- end of get_header (...) --- |
203 |
|
204 |
- def _file_read ( self, filepath ): |
205 |
- """Method that should be called after reading a distmap file.""" |
206 |
- self.dirty = self.dirty or ( filepath is not self.dbfile ) |
207 |
- # --- end of _file_read (...) --- |
208 |
+ def gen_info_lines ( self ): |
209 |
+ for distfile, info in self._distmap.items(): |
210 |
+ if not info.volatile: |
211 |
+ yield info.to_str ( str ( distfile ), self.FIELD_DELIMITER ) |
212 |
+ # --- end of gen_info_lines (...) --- |
213 |
|
214 |
def gen_lines ( self ): |
215 |
"""Generator that creates distmap file text lines.""" |
216 |
# header |
217 |
- yield "<{d}<{fmt}".format ( |
218 |
- d=self.FIELD_DELIMITER, fmt=self.FILE_FORMAT |
219 |
- ) |
220 |
- for distfile, info in self._distmap.items(): |
221 |
- yield info.to_str ( str ( distfile ), self.FIELD_DELIMITER ) |
222 |
+ yield self.get_header() |
223 |
+ for line in self.gen_info_lines(): |
224 |
+ yield line |
225 |
# --- end of gen_lines (...) --- |
226 |
|
227 |
def _read_header ( self, line ): |
228 |
@@ -584,17 +605,35 @@ class _FileDistMapBase ( _DistMapBase ): |
229 |
return False |
230 |
# --- end of _read_header (...) --- |
231 |
|
232 |
- @roverlay.util.objects.abstractmethod |
233 |
def read ( self, filepath=None ): |
234 |
"""Reads the distmap. |
235 |
|
236 |
arguments: |
237 |
* filepath -- path to the distmap file (defaults to self.dbfile) |
238 |
""" |
239 |
- pass |
240 |
+ dbfile = self.dbfile if filepath is None else filepath |
241 |
+ first = True |
242 |
+ |
243 |
+ for line in roverlay.util.fileio.read_text_file ( |
244 |
+ dbfile, preparse=True, try_harder=True |
245 |
+ ): |
246 |
+ if first: |
247 |
+ first = False |
248 |
+ if self._read_header ( line ): |
249 |
+ continue |
250 |
+ # else no header |
251 |
+ # -- end if |
252 |
+ |
253 |
+ distfile, info = roverlay.util.headtail ( |
254 |
+ line.split ( self.FIELD_DELIMITER ) |
255 |
+ ) |
256 |
+ self._distmap [distfile] = DistMapInfo ( distfile, *info ) |
257 |
+ self._nondirty_file_added ( distfile ) |
258 |
+ # -- end for |
259 |
+ self.dirty = self.dirty or filepath is not None |
260 |
+ print( list(self.gen_info_lines()) ) |
261 |
# --- end of read (...) --- |
262 |
|
263 |
- @roverlay.util.objects.abstractmethod |
264 |
def write ( self, filepath=None, force=False ): |
265 |
"""Writes the distmap. |
266 |
|
267 |
@@ -602,112 +641,16 @@ class _FileDistMapBase ( _DistMapBase ): |
268 |
* filepath -- path to the distmap file (defaults to self.dbfile) |
269 |
* force -- enforce writing even if distmap not modified |
270 |
""" |
271 |
- pass |
272 |
- # --- end of write (...) --- |
273 |
- |
274 |
-# --- end of _FileDistMapBase --- |
275 |
- |
276 |
- |
277 |
-class FileDistMap ( _FileDistMapBase ): |
278 |
- |
279 |
- def read ( self, filepath=None ): |
280 |
- f = filepath or self.dbfile |
281 |
- first = True |
282 |
- with open ( f, 'rt') as FH: |
283 |
- for line in FH.readlines(): |
284 |
- rsline = line.rstrip('\n') |
285 |
- |
286 |
- if first: |
287 |
- first = False |
288 |
- if self._read_header ( rsline ): |
289 |
- continue |
290 |
- # else no header |
291 |
- # -- end if |
292 |
- |
293 |
- distfile, info = roverlay.util.headtail ( |
294 |
- rsline.split ( self.FIELD_DELIMITER ) |
295 |
- ) |
296 |
- self._distmap [distfile] = DistMapInfo ( distfile, *info ) |
297 |
- self._nondirty_file_added ( distfile ) |
298 |
- # -- end for |
299 |
- self._file_read ( f ) |
300 |
- # --- end of read_file (...) --- |
301 |
- |
302 |
- def write ( self, filepath=None, force=False ): |
303 |
- if force or self.dirty: |
304 |
- f = filepath or self.dbfile |
305 |
- roverlay.util.dodir ( os.path.dirname ( f ), mkdir_p=True ) |
306 |
- with open ( f, 'wt' ) as FH: |
307 |
- for line in self.gen_lines(): |
308 |
- FH.write ( line ) |
309 |
- FH.write ( '\n' ) |
310 |
- self._file_written ( f ) |
311 |
+ if force or self.dirty or filepath is not None: |
312 |
+ dbfile = self.dbfile if filepath is None else filepath |
313 |
+ roverlay.util.fileio.write_text_file ( |
314 |
+ dbfile, self.gen_lines(), |
315 |
+ compression=self.compression, create_dir=True |
316 |
+ ) |
317 |
+ self.dirty = self.dirty and filepath is not None |
318 |
return True |
319 |
else: |
320 |
return False |
321 |
# --- end of write (...) --- |
322 |
|
323 |
# --- end of FileDistMap --- |
324 |
- |
325 |
-class _CompressedFileDistMap ( _FileDistMapBase ): |
326 |
- |
327 |
- # _OPEN_COMPRESSED: |
328 |
- # callable that returns a file handle for reading compressed files |
329 |
- # |
330 |
- _OPEN_COMPRESSED = None |
331 |
- |
332 |
- def read ( self, filepath=None ): |
333 |
- f = filepath or self.dbfile |
334 |
- first = True |
335 |
- with self._OPEN_COMPRESSED ( f, mode='r' ) as FH: |
336 |
- for compressed in FH.readlines(): |
337 |
- rsline = compressed.decode().rstrip('\n') |
338 |
- |
339 |
- if first: |
340 |
- first = False |
341 |
- if self._read_header ( rsline ): |
342 |
- continue |
343 |
- # else no header |
344 |
- # -- end if |
345 |
- |
346 |
- distfile, info = roverlay.util.headtail ( |
347 |
- rsline.split ( self.FIELD_DELIMITER ) |
348 |
- ) |
349 |
- self._distmap [distfile] = DistMapInfo ( distfile, *info ) |
350 |
- self._nondirty_file_added ( distfile ) |
351 |
- # -- end for |
352 |
- self._file_read ( f ) |
353 |
- # --- end of read (...) --- |
354 |
- |
355 |
- def write ( self, filepath=None, force=False ): |
356 |
- if force or self.dirty: |
357 |
- f = filepath or self.dbfile |
358 |
- nl = '\n'.encode() |
359 |
- roverlay.util.dodir ( os.path.dirname ( f ), mkdir_p=True ) |
360 |
- with self._OPEN_COMPRESSED ( f, mode='w' ) as FH: |
361 |
- for line in self.gen_lines(): |
362 |
- FH.write ( line.encode() ) |
363 |
- FH.write ( nl ) |
364 |
- self._file_written ( f ) |
365 |
- return True |
366 |
- else: |
367 |
- return False |
368 |
- # --- end of write (...) --- |
369 |
- |
370 |
-# --- end of _CompressedFileDistMap --- |
371 |
- |
372 |
-def create_CompressedFileDistMap ( open_compressed ): |
373 |
- """Creates a CompressedFileDistMap class. |
374 |
- |
375 |
- arguments: |
376 |
- * open_compressed -- function that returns a file handle for reading |
377 |
- """ |
378 |
- class CompressedFileDistMap ( _CompressedFileDistMap ): |
379 |
- _OPEN_COMPRESSED = open_compressed |
380 |
- # --- end of CompressedFileDistMap --- |
381 |
- return CompressedFileDistMap |
382 |
-# --- end of create_CompressedFileDistMap (...) --- |
383 |
- |
384 |
-# bzip2, gzip |
385 |
-Bzip2CompressedFileDistMap = create_CompressedFileDistMap ( bz2.BZ2File ) |
386 |
-GzipCompressedFileDistMap = create_CompressedFileDistMap ( gzip.GzipFile ) |
387 |
|
388 |
diff --git a/roverlay/recipe/distmap.py b/roverlay/recipe/distmap.py |
389 |
index 00f3348..27a67bf 100644 |
390 |
--- a/roverlay/recipe/distmap.py |
391 |
+++ b/roverlay/recipe/distmap.py |
392 |
@@ -24,7 +24,7 @@ def setup(): |
393 |
) |
394 |
|
395 |
if distmap_file: |
396 |
- DISTMAP = roverlay.db.distmap.get_distmap ( |
397 |
+ DISTMAP = roverlay.db.distmap.FileDistMap ( |
398 |
distmap_file = distmap_file, |
399 |
distmap_compression = roverlay.config.get ( |
400 |
'OVERLAY.DISTMAP.compression', 'bz2' |