Gentoo Archives: gentoo-commits

From: "André Erdmann" <dywi@×××××××.de>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/db/, roverlay/recipe/
Date: Fri, 30 Aug 2013 14:49:42
Message-Id: 1377870598.d824fed46faebd39b81983a8f8938bd69970c307.dywi@gentoo
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'