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/
Date: Wed, 30 May 2012 16:10:07
Message-Id: 1338394110.0ab8e34e33388ff12025c4a05969a891a9dcb8c4.dywi@gentoo
1 commit: 0ab8e34e33388ff12025c4a05969a891a9dcb8c4
2 Author: Andre Erdmann <dywi <AT> mailerd <DOT> de>
3 AuthorDate: Wed May 30 16:08:30 2012 +0000
4 Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
5 CommitDate: Wed May 30 16:08:30 2012 +0000
6 URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=0ab8e34e
7
8 roverlay, fileio: refactored and @classmethod decorators removed
9
10 ---
11 roverlay/fileio.py | 457 +++++++++++++++++++++++++---------------------------
12 1 files changed, 223 insertions(+), 234 deletions(-)
13
14 diff --git a/roverlay/fileio.py b/roverlay/fileio.py
15 index 295d904..7c89356 100644
16 --- a/roverlay/fileio.py
17 +++ b/roverlay/fileio.py
18 @@ -15,217 +15,13 @@ from roverlay import tmpconst as const
19 class DescriptionReader:
20 """Description Reader"""
21
22 - @classmethod
23 def __init__ ( self ):
24 """Initializes a DESCRIPTION file reader."""
25 pass
26
27 - @classmethod
28 - def _get_fields_with_flag ( self, flag, foce_update=False ):
29 + # --- end of __init__ (...) ---
30
31 - matching_fields = []
32
33 - field = None
34 - for field in const.DESCRIPTION_FIELD_MAP.keys():
35 - if flag is None:
36 - matching_fields.append ( field )
37 -
38 - elif 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
39 - if flag in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
40 - matching_fields.append ( field )
41 -
42 - del field
43 - return matching_fields
44 -
45 -
46 - @classmethod
47 - def _find_field ( self , field_identifier ):
48 - """Determines the real name of a field.
49 -
50 - arguments:
51 - * field_identifier -- name of the field as it appears in the DESCRIPTION file
52 -
53 - At first, it is checked whether field_identifier matches the name of
54 - a field listed in DESCRIPTION_FIELD_MAP (any match results in immediate return).
55 - Then, a new iteration over the field map compares field_identifier
56 - with all aliases until the first case-(in)sensitive match (-> immediate return).
57 - None will be returned if none of the above searches succeed.
58 -
59 - In other words: this method decides whether a field_identifier will be used and if so,
60 - with which name.
61 - """
62 -
63 - # save some time by prevent searching if field_id is empty
64 - if not field_identifier:
65 - return None
66 -
67 - # search for real field names first
68 - for field in const.DESCRIPTION_FIELD_MAP.keys():
69 - if field_identifier == field:
70 - return field
71 -
72 - field_id_lower = field_identifier.lower()
73 -
74 - for field in const.DESCRIPTION_FIELD_MAP.keys():
75 -
76 - # does extra information (-> alias(es)) for this field exist?
77 - if 'alias' in const.DESCRIPTION_FIELD_MAP [field]:
78 -
79 - if 'withcase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
80 - for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['withcase']:
81 - if field_identifier == alias:
82 - return field
83 -
84 - if 'nocase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
85 - for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['nocase']:
86 - if field_id_lower == alias.lower():
87 - return field
88 -
89 - #if 'other_alias_type' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
90 -
91 - # returning None if no valid field identifier matches
92 - return None
93 -
94 - @classmethod
95 - def _make_values ( self, value_str, field_context=None ):
96 - """Extracts relevant data from value_str and returns them as list.
97 -
98 - arguments:
99 - * value_str -- string that represents the (just read) values
100 - * field_context -- field name the value belongs to; optional, defaults to None
101 -
102 - It's useful to set field_context 'cause several fields ('Depends') have
103 - multiple values arranged in a list (dep0, dep1 [, depK]*).
104 - """
105 -
106 - svalue_str = value_str.strip()
107 -
108 - if not svalue_str:
109 - # empty value(s)
110 - return []
111 -
112 - elif field_context is None:
113 - # default return if no context given
114 - return [ svalue_str ]
115 -
116 - elif self._check_fieldflag ( field_context ):
117 - # value str is not empty and have flags for field_context, check these
118 -
119 - if self._check_fieldflag ( field_context, 'isList' ):
120 - # split up this list (that is separated by commata and/or semicolons)
121 - return re.split (const.DESCRIPTION_LIST_SPLIT_REGEX, svalue_str, 0)
122 -
123 - elif self._check_fieldflag ( field_context, 'isWhitespaceList' ):
124 - # split up this list (that is separated whitespace)
125 - return re.split ( '\s+', svalue_str, 0 )
126 -
127 -
128 - # default return
129 - return [ svalue_str ]
130 -
131 - @classmethod
132 - def _check_fieldflag ( self, field, flag_to_check=None ):
133 - """Checks if the given field has the specified flag and returns a bool.
134 -
135 - arguments:
136 - * field -- name of the field that should be checked
137 - * flag_to_check -- name of the flag to check; optional, defaults to None
138 -
139 - This method acts as 'field has any flags?' if flag_to_check is None (its default value).
140 - """
141 -
142 - if field in const.DESCRIPTION_FIELD_MAP:
143 - if 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
144 - if flag_to_check in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
145 - return True
146 - elif flag_to_check is None:
147 - # 'flags' exist, return true
148 - return True
149 -
150 - return False
151 -
152 - @staticmethod
153 - def _get_desc_from_file ( filepath, pkg_name='.' ):
154 - """Reads a file returns the description data.
155 -
156 - arguments:
157 - * filepath -- file to read (str; path to tarball or file)
158 - * pkg_name -- name of the package, in tarballs the description file
159 - is located in <pkg_name>/ and thus this argument is required.
160 - Defaults to '.', set to None to disable.
161 -
162 - All exceptions are passed to the caller (TarError, IOErr, <custom>).
163 - <filepath> can either be a tarball in which case the real DESCRIPTION
164 - file is read (<pkg_name>/DESCRIPTION) or a normal file.
165 - """
166 -
167 - logging.write ( "Starting to read file '" + str ( filepath ) + "' ...\n" )
168 -
169 - if not ( isinstance ( filepath, str ) and filepath ):
170 - raise Exception ( "bad usage" )
171 -
172 - # read describes how to import the lines from a file (e.g. rstrip())
173 - # fh, th are file/tar handles
174 - read = th = fh = None
175 -
176 - if tarfile.is_tarfile ( filepath ):
177 - # filepath is a tarball, open tar handle + file handle
178 - th = tarfile.open ( filepath, 'r' )
179 - if pkg_name:
180 - fh = th.extractfile ( os.path.join ( pkg_name, const.DESCRIPTION_FILE_NAME ) )
181 - else:
182 - fh = th.extractfile ( const.DESCRIPTION_FILE_NAME )
183 -
184 - # have to decode the lines
185 - read = lambda lines : [ line.decode().rstrip() for line in lines ]
186 - else:
187 - # open file handle only
188 - fh = open ( filepath, 'r' )
189 - read = lambda lines : [ line.rstrip() for line in lines ]
190 -
191 - x = None
192 - read_lines = read ( fh.readlines() )
193 - del x, read
194 -
195 - fh.close()
196 - if not th is None: th.close()
197 - del fh, th
198 -
199 - return read_lines
200 -
201 - @staticmethod
202 - def _get_fileinfo ( filepath ):
203 - """Returns some info about the given filepath as dict whose contents are
204 - the file path, the file name ([as package_file with suffix and]
205 - as filename with tarball suffix removed), the package name
206 - and the package_version.
207 -
208 - arguments:
209 - * filepath --
210 - """
211 -
212 - package_file = os.path.basename ( filepath )
213 -
214 - filename = re.sub ( const.RPACKAGE_SUFFIX_REGEX + '$', '', package_file )
215 -
216 - # todo move that separator to const
217 - package_name, sepa, package_version = filename.partition ( '_' )
218 -
219 - if not sepa:
220 - # file name unexpected, tarball extraction will (probably) fail
221 - #raise Exception ("file name unexpected")
222 - logging.write ( "unexpected file name '" + filename + "'.\n" )
223 -
224 - return dict (
225 - filepath = filepath,
226 - filename = filename,
227 - package_file = package_file,
228 - package_name = package_name,
229 - #package_origin = ?,
230 - package_version = package_version,
231 - )
232 -
233 - @classmethod
234 def _parse_read_data ( self, read_data ):
235 """Verifies and parses/fixes read data.
236
237 @@ -233,16 +29,25 @@ class DescriptionReader:
238 * read_data -- data from file, will be modified
239 """
240
241 - def stats ( data ):
242 - """Temporary function that prints some info about the given data."""
243 + def get_fields_with_flag ( flag, foce_update=False ):
244 +
245 + matching_fields = []
246 +
247 field = None
248 - logging.write ( "=== this is the list of read data ===\n" )
249 - for field in read_data.keys():
250 - logging.write ( field + " = " + str ( read_data [field] ) + "\n" )
251 - logging.write ( "=== end of list ===\n" )
252 + for field in const.DESCRIPTION_FIELD_MAP.keys():
253 + if flag is None:
254 + matching_fields.append ( field )
255 +
256 + elif 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
257 + if flag in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
258 + matching_fields.append ( field )
259 +
260 del field
261 + return matching_fields
262
263 - def _value_in_strlist ( _val, _list, case_insensitive=True ):
264 + # --- end of get_fields_with_flag (...) ---
265 +
266 + def value_in_strlist ( _val, _list, case_insensitive=True ):
267 """Returns true if value is in the given list."""
268 el = None
269 if case_insensitive:
270 @@ -258,9 +63,7 @@ class DescriptionReader:
271
272 del el
273 return False
274 -
275 -
276 - stats ( read_data )
277 + # --- end of value_in_strlist (...) ---
278
279 field = None
280
281 @@ -270,14 +73,14 @@ class DescriptionReader:
282 read_data [field] = const.DESCRIPTION_FIELD_MAP [field] ['default_value']
283
284 # join values to a single string
285 - for field in self._get_fields_with_flag ( 'joinValues' ):
286 + for field in get_fields_with_flag ( 'joinValues' ):
287 if field in read_data.keys():
288 read_data [field] = ' ' . join ( read_data [field] )
289
290 # ensure that all mandatory fields are set
291 missing_fields = list()
292
293 - for field in self._get_fields_with_flag ( 'mandatory' ):
294 + for field in get_fields_with_flag ( 'mandatory' ):
295 if field in read_data:
296 if not len (read_data [field]):
297 missing_fields.append ( field )
298 @@ -294,15 +97,10 @@ class DescriptionReader:
299 # skip _fileinfo
300 if field != '_fileinfo':
301 if 'allowed_values' in const.DESCRIPTION_FIELD_MAP [field]:
302 - if not _value_in_strlist ( read_data [field],
303 + if not value_in_strlist ( read_data [field],
304 const.DESCRIPTION_FIELD_MAP [field] ['allowed_values']
305 ): unsuitable_fields.append ( field )
306
307 -
308 - stats ( read_data )
309 -
310 -
311 -
312 valid = True
313
314 if len ( missing_fields ):
315 @@ -328,8 +126,8 @@ class DescriptionReader:
316 del field
317
318 return valid
319 + # --- end of _parse_read_data (...) ---
320
321 - @classmethod
322 def readfile ( self, filepath ):
323 """Reads a DESCRIPTION file and returns the read data if successful, else None.
324
325 @@ -347,15 +145,205 @@ class DescriptionReader:
326 e.g. if OS_TYPE is not unix).
327 """
328
329 - read_data = dict ()
330 - fileinfo = DescriptionReader._get_fileinfo ( filepath )
331 + def get_fileinfo ( filepath ):
332 + """Returns some info about the given filepath as dict whose contents are
333 + the file path, the file name ([as package_file with suffix and]
334 + as filename with tarball suffix removed), the package name
335 + and the package_version.
336
337 + arguments:
338 + * filepath --
339 + """
340
341 - try:
342 - desc_lines = DescriptionReader._get_desc_from_file (
343 - filepath, fileinfo ['package_name']
344 + package_file = os.path.basename ( filepath )
345 +
346 + filename = re.sub ( const.RPACKAGE_SUFFIX_REGEX + '$', '', package_file )
347 +
348 + # todo move that separator to const
349 + package_name, sepa, package_version = filename.partition ( '_' )
350 +
351 + if not sepa:
352 + # file name unexpected, tarball extraction will (probably) fail
353 + #raise Exception ("file name unexpected")
354 + logging.write ( "unexpected file name '" + filename + "'.\n" )
355 +
356 + return dict (
357 + filepath = filepath,
358 + filename = filename,
359 + package_file = package_file,
360 + package_name = package_name,
361 + #package_origin = ?,
362 + package_version = package_version,
363 )
364
365 + # --- end of get_fileinfo (...) ---
366 +
367 +
368 + def make_values ( value_str, field_context=None ):
369 + """Extracts relevant data from value_str and returns them as list.
370 +
371 + arguments:
372 + * value_str -- string that represents the (just read) values
373 + * field_context -- field name the value belongs to; optional, defaults to None
374 +
375 + It's useful to set field_context 'cause several fields ('Depends') have
376 + multiple values arranged in a list (dep0, dep1 [, depK]*).
377 + """
378 +
379 + def check_fieldflag ( field, flag_to_check=None ):
380 + """Checks if the given field has the specified flag and returns a bool.
381 +
382 + arguments:
383 + * field -- name of the field that should be checked
384 + * flag_to_check -- name of the flag to check; optional, defaults to None
385 +
386 + This method acts as 'field has any flags?' if flag_to_check is None (its default value).
387 + """
388 +
389 + if field in const.DESCRIPTION_FIELD_MAP:
390 + if 'flags' in const.DESCRIPTION_FIELD_MAP [field]:
391 + if flag_to_check in const.DESCRIPTION_FIELD_MAP [field] ['flags']:
392 + return True
393 + elif flag_to_check is None:
394 + # 'flags' exist, return true
395 + return True
396 +
397 + return False
398 + # --- end of check_fieldflag (...) ---
399 +
400 + svalue_str = value_str.strip()
401 +
402 + if not svalue_str:
403 + # empty value(s)
404 + return []
405 +
406 + elif field_context is None:
407 + # default return if no context given
408 + return [ svalue_str ]
409 +
410 + elif check_fieldflag ( field_context ):
411 + # value str is not empty and have flags for field_context, check these
412 +
413 + if check_fieldflag ( field_context, 'isList' ):
414 + # split up this list (that is separated by commata and/or semicolons)
415 + return re.split (const.DESCRIPTION_LIST_SPLIT_REGEX, svalue_str, 0)
416 +
417 + elif check_fieldflag ( field_context, 'isWhitespaceList' ):
418 + # split up this list (that is separated whitespace)
419 + return re.split ( '\s+', svalue_str, 0 )
420 +
421 +
422 + # default return
423 + return [ svalue_str ]
424 +
425 + # --- end of make_values (...) ---
426 +
427 + def get_desc_from_file ( filepath, pkg_name='.' ):
428 + """Reads a file returns the description data.
429 +
430 + arguments:
431 + * filepath -- file to read (str; path to tarball or file)
432 + * pkg_name -- name of the package, in tarballs the description file
433 + is located in <pkg_name>/ and thus this argument is required.
434 + Defaults to '.', set to None to disable.
435 +
436 + All exceptions are passed to the caller (TarError, IOErr, <custom>).
437 + <filepath> can either be a tarball in which case the real DESCRIPTION
438 + file is read (<pkg_name>/DESCRIPTION) or a normal file.
439 + """
440 +
441 + logging.write ( "Starting to read file '" + str ( filepath ) + "' ...\n" )
442 +
443 + if not ( isinstance ( filepath, str ) and filepath ):
444 + raise Exception ( "bad usage" )
445 +
446 + # read describes how to import the lines from a file (e.g. rstrip())
447 + # fh, th are file/tar handles
448 + read = th = fh = None
449 +
450 + if tarfile.is_tarfile ( filepath ):
451 + # filepath is a tarball, open tar handle + file handle
452 + th = tarfile.open ( filepath, 'r' )
453 + if pkg_name:
454 + fh = th.extractfile ( os.path.join ( pkg_name, const.DESCRIPTION_FILE_NAME ) )
455 + else:
456 + fh = th.extractfile ( const.DESCRIPTION_FILE_NAME )
457 +
458 + # have to decode the lines
459 + read = lambda lines : [ line.decode().rstrip() for line in lines ]
460 + else:
461 + # open file handle only
462 + fh = open ( filepath, 'r' )
463 + read = lambda lines : [ line.rstrip() for line in lines ]
464 +
465 + x = None
466 + read_lines = read ( fh.readlines() )
467 + del x, read
468 +
469 + fh.close()
470 + if not th is None: th.close()
471 + del fh, th
472 +
473 + return read_lines
474 +
475 + # --- end of get_desc_from_file (...) ---
476 +
477 + def find_field ( field_identifier ):
478 + """Determines the real name of a field.
479 +
480 + arguments:
481 + * field_identifier -- name of the field as it appears in the DESCRIPTION file
482 +
483 + At first, it is checked whether field_identifier matches the name of
484 + a field listed in DESCRIPTION_FIELD_MAP (any match results in immediate return).
485 + Then, a new iteration over the field map compares field_identifier
486 + with all aliases until the first case-(in)sensitive match (-> immediate return).
487 + None will be returned if none of the above searches succeed.
488 +
489 + In other words: this method decides whether a field_identifier will be used and if so,
490 + with which name.
491 + """
492 +
493 + # save some time by prevent searching if field_id is empty
494 + if not field_identifier:
495 + return None
496 +
497 + # search for real field names first
498 + for field in const.DESCRIPTION_FIELD_MAP.keys():
499 + if field_identifier == field:
500 + return field
501 +
502 + field_id_lower = field_identifier.lower()
503 +
504 + for field in const.DESCRIPTION_FIELD_MAP.keys():
505 +
506 + # does extra information (-> alias(es)) for this field exist?
507 + if 'alias' in const.DESCRIPTION_FIELD_MAP [field]:
508 +
509 + if 'withcase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
510 + for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['withcase']:
511 + if field_identifier == alias:
512 + return field
513 +
514 + if 'nocase' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
515 + for alias in const.DESCRIPTION_FIELD_MAP [field] ['alias'] ['nocase']:
516 + if field_id_lower == alias.lower():
517 + return field
518 +
519 + #if 'other_alias_type' in const.DESCRIPTION_FIELD_MAP [field] ['alias']:
520 +
521 + # returning None if no valid field identifier matches
522 + return None
523 +
524 + # --- end of find_field (...) ---
525 +
526 +
527 + read_data = dict ()
528 + fileinfo = get_fileinfo ( filepath )
529 +
530 +
531 + try:
532 + desc_lines = get_desc_from_file ( filepath, fileinfo ['package_name'] )
533
534 except IOError as err:
535 # <todo>
536 @@ -378,7 +366,7 @@ class DescriptionReader:
537 if field_context:
538 # context is set => append values
539
540 - for val in self._make_values ( sline, field_context ):
541 + for val in make_values ( sline, field_context ):
542 read_data [field_context] . append ( val )
543 else:
544 # no valid context => ignore line
545 @@ -392,7 +380,7 @@ class DescriptionReader:
546
547 if line_components [1]:
548 # line contains a field separator, set field context
549 - field_context = self._find_field ( line_components [0] )
550 + field_context = find_field ( line_components [0] )
551
552 if field_context:
553 # create a new empty list for field_context
554 @@ -400,7 +388,7 @@ class DescriptionReader:
555
556 # add values to read_data
557 # no need to check line_components [2] 'cause [1] was a true str
558 - for val in self._make_values ( line_components [2], field_context ):
559 + for val in make_values ( line_components [2], field_context ):
560 read_data [field_context] . append ( val )
561
562 else:
563 @@ -424,8 +412,8 @@ class DescriptionReader:
564
565
566 if self._parse_read_data ( read_data ):
567 - logging.write ( '## success ##\n' )
568 - logging.write ( ( str ( read_data ) ) )
569 + #logging.write ( '## success ##\n' )
570 + #logging.write ( ( str ( read_data ) ) )
571 return dict (
572 fileinfo = fileinfo,
573 description_data = read_data
574 @@ -434,3 +422,4 @@ class DescriptionReader:
575 logging.write ( '## fail ##\n' )
576 return None
577
578 + # --- end of readfile (...) ---