diff options
author | André Erdmann <dywi@mailerd.de> | 2013-06-04 12:09:32 +0200 |
---|---|---|
committer | André Erdmann <dywi@mailerd.de> | 2013-06-04 12:09:32 +0200 |
commit | 1f81d380522b5e81614fb20bc8af1667b5865006 (patch) | |
tree | 5b7fba7ed3329ddc70e3734c8f5583bcb4fe2d3a /roverlay/packageinfo.py | |
parent | fix AttributeError in depres/simpledeprule (diff) | |
download | R_overlay-1f81d380522b5e81614fb20bc8af1667b5865006.tar.gz R_overlay-1f81d380522b5e81614fb20bc8af1667b5865006.tar.bz2 R_overlay-1f81d380522b5e81614fb20bc8af1667b5865006.zip |
Consistently use spaces instead of tabs for indention.
Diffstat (limited to 'roverlay/packageinfo.py')
-rw-r--r-- | roverlay/packageinfo.py | 1101 |
1 files changed, 551 insertions, 550 deletions
diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py index 414fc07..da3e5f1 100644 --- a/roverlay/packageinfo.py +++ b/roverlay/packageinfo.py @@ -40,553 +40,554 @@ from roverlay.rpackage import descriptionreader LOGGER = logging.getLogger ( 'PackageInfo' ) class PackageInfo ( object ): - """PackageInfo offers easy, subscriptable access to package - information, whether stored or calculated. - - class-wide variables: - * EBUILDVER_REGEX -- a regex containing chars that will be replaced by - a dot '.'. (e.g. 2-3 becomes 2.3) - * PKGSUFFIX_REGEX -- a regex that matches the suffix of an R package file - name. The regex str is retrieved from the config - module (which also means that the config has to be - loaded before import this module) - * ALWAYS_FALLBACK -- a set of keys for which get() always returns a - fallback value (None) - - * _UPDATE_KEYS_SIMPLE -- a set of keys that can be added - without further checks - * _UPDATE_KEYS_SIMPLE_INITIAL -- like _UPDATE_KEYS_SIMPLE, but only used - on the first update() call (as long as - no keys have been stored) - * _UPDATE_KEYS_FILTER_NONE -- like _UPDATE_KEYS_SIMPLE, but stores - key's value only if it is not None - * _REMOVE_KEYS_EBUILD -- a set of keys that will be removed when - _remove_auto ( 'ebuild_written' ) is - called. - """ - - EBUILDVER_REGEX = re.compile ( '[-]{1,}' ) - PKGSUFFIX_REGEX = re.compile ( - config.get_or_fail ( 'R_PACKAGE.suffix_regex' ) + '$' - ) - ALWAYS_FALLBACK = frozenset ( ( 'ebuild', 'ebuild_file' ) ) - - _UPDATE_KEYS_SIMPLE = frozenset (( - 'origin', - 'ebuild', - 'ebuild_file', - 'physical_only', - 'src_uri', - )) - _UPDATE_KEYS_SIMPLE_INITIAL = frozenset (( - 'package_filename', - )) - _UPDATE_KEYS_FILTER_NONE = frozenset (( - 'src_uri_base', - 'distdir', - )) - - _REMOVE_KEYS_EBUILD = frozenset (( - 'ebuild' - )) - - def __init__ ( self, **initial_info ): - """Initializes a PackageInfo. - - arguments: - * **initial_info -- passed to update ( **kw ) - """ - self._info = dict() - self.readonly = False - self._update_lock = threading.RLock() - self.overlay_package_ref = None - self.logger = LOGGER - - self.update ( **initial_info ) - # --- end of __init__ (...) --- - - def set_readonly ( self, immediate=False, final=False ): - """Makes the package info readonly. - - arguments: - * immediate -- do not acquire lock, set readonly directly, - defaults to False - * final -- if set and True: make this decision final - """ - self._set_mode ( True, immediate, final ) - # --- end of set_readonly (...) --- - - def set_writeable ( self, immediate=False ): - """Makes the package info writeable. - - arguments: - * immediate -- do not acquire lock, set writeable directly, - defaults to False - """ - self._set_mode ( False, immediate ) - # --- end of set_writeable (...) --- - - def _set_mode ( self, readonly_val, immediate=False, final=False ): - """Sets readonly to True/False. - - arguments: - * readonly_val -- new value for readonly - * immediate -- do not acquire lock - * final -- only if readonly_val is True: make this decision final, - - raises: Exception if self.readonly is a constant (_readonly_final is set) - """ - if hasattr ( self, '_readonly_final' ): - raise Exception ( "cannot modify readonly - it's a constant." ) - elif immediate: - self.readonly = readonly_val - if final and readonly_val: - self._readonly_final = True - elif not self.readonly is readonly_val: - self._update_lock.acquire() - self.readonly = readonly_val - if final and readonly_val: - self._readonly_final = True - self._update_lock.release() - # --- end of _set_mode (...) --- - - def _writelock_acquire ( self ): - """Acquires the lock required for adding new information. - - raises: Exception if readonly (writing not allowed) - """ - if self.readonly or hasattr ( self, '_readonly_final' ): - raise Exception ( "package info is readonly!" ) - - self._update_lock.acquire() - - if self.readonly or hasattr ( self, '_readonly_final' ): - self._update_lock.release() - raise Exception ( "package info is readonly!" ) - - return True - # --- end of _writelock_acquire (...) --- - - def _has_log_keyerror_unexpected ( self, key, error ): - self.logger.error ( - 'FIXME: PackageInfo.get( {!r}, do_fallback=True ) ' - 'raised KeyError'.format ( key ) - ) - self.logger.exception ( error ) - # --- end of _has_log_keyerror_unexpected (...) --- - - def has_key ( self, *keys ): - """Returns False if at least one key out of keys is not accessible, - i.e. its data cannot be retrieved using get()/__getitem__(). - - arguments: - * *keys -- keys to check - """ - for k in keys: - if k not in self._info: - # try harder - use get() with fallback value to see if value - # can be calculated - try: - if self.get ( k, do_fallback=True ) is None: - return False - except KeyError as kerr: - self._has_log_keyerror_unexpected ( k, kerr ) - return False - return True - # --- end of has_key (...) --- - - has = has_key - - def has_key_or ( self, *keys ): - """Returns True if at least one key out of keys is accessible. - - arguments: - * *keys -- keys to check - """ - for k in keys: - try: - if k in self._info: - return True - elif self.get ( k, do_fallback=True ) is not None: - return True - except KeyError as kerr: - self._has_log_keyerror_unexpected ( k, kerr ) - return False - # --- end of has_key_or (...) --- - - has_or = has_key_or - - def compare_version ( self, other_package ): - """Compares the version of two PackageInfo objects. - Returns 1 if self's version is higher, -1 if lower and 0 if equal. - - arguments: - * other_package -- - """ - if other_package is None: return 1 - - my_ver = self.get ( 'version', fallback_value=0 ) - other_ver = other_package.get ( 'version', fallback_value=0 ) - - if my_ver > other_ver: - return 1 - elif my_ver == other_ver: - return 0 - else: - return -1 - # --- end of compare_version (...) --- - - def get ( self, key, fallback_value=None, do_fallback=False ): - """Returns the value specified by key. - The value is either calculated or taken from dict self._info. - - arguments: - * key -- - * fallback_value -- fallback value if key not found / unknown - * do_fallback -- if True: return fallback_value, else raise KeyError - - raises: KeyError - """ - # normal dict access shouldn't be slowed down here - if key in self._info: return self._info [key] - - key_low = key.lower() - - if key_low in self._info: - return self._info [key_low] - - # 'virtual' keys - calculate result - elif key_low == 'name': - # no special name, using package_name - return self._info ['package_name'] - - elif key_low == 'package_file': - distdir = self.get ( 'distdir', do_fallback=True ) - if distdir: - fname = self._info.get ( 'package_filename', None ) - if fname: - return distdir + os.path.sep + fname - - elif key_low == 'distdir': - if 'origin' in self._info: - # this doesn't work if the package is in a sub directory - # of the repo's distdir - return self._info ['origin'].distdir - elif 'package_file' in self._info: - return os.path.dirname ( self._info ['package_file'] ) - # else fallback/KeyError - - elif key_low == 'has_suggests': - # 'has_suggests' not in self._info -> assume False - return False - - elif key_low == 'physical_only': - # 'physical_only' not in self._info -> assume False - return False - - elif key_low == 'src_uri': - if 'src_uri_base' in self._info: - return \ - self._info ['src_uri_base'] + '/' + \ - self._info ['package_filename'] - - elif 'origin' in self._info: - return self._info ['origin'].get_src_uri ( - self._info ['package_filename'] - ) - else: - return "http://localhost/R-packages/" + \ - self._info ['package_filename'] - - elif key_low == 'ebuild_dir': - ebuild_file = self._info ['ebuild_file'] - if ebuild_file is not None: - return os.path.dirname ( ebuild_file ) - - elif key_low == 'ebuild_filename': - ebuild_file = self._info ['ebuild_file'] - if ebuild_file is not None: - return os.path.basename ( ebuild_file ) - - # end if <key matches ...> - - - # fallback - if do_fallback or fallback_value is not None: - return fallback_value - - elif key_low in self.__class__.ALWAYS_FALLBACK: - return None - - else: - raise KeyError ( key ) - # --- end of get (...) --- - - def get_desc_data ( self ): - """Returns the DESCRIPTION data for this PackageInfo (by reading the - R package file if necessary). - """ - if 'desc_data' in self._info: - return self._info ['desc_data'] - - self._writelock_acquire() - if 'desc_data' not in self._info: - self._info ['desc_data'] = descriptionreader.read ( self ) - - self._update_lock.release() - return self._info ['desc_data'] - # --- end of get_desc_data (...) --- - - def __getitem__ ( self, key ): - """Returns an item.""" - return self.get ( key, do_fallback=False ) - # --- end of __getitem__ (...) --- - - def __setitem__ ( self, key, value ): - """Sets an item. - - arguments: - * key -- - * value -- - - raises: Exception when readonly - """ - self._writelock_acquire() - self._info [key] = value - self._update_lock.release() - # --- end of __setitem__ (...) --- - - def update_now ( self, **info ): - """Updates the package info data with temporarily enabling write access. - Data will be readonly after calling this method. - - arguments: - * **info -- - """ - if len ( info ) == 0: return - with self._update_lock: - self.set_writeable() - self.update ( **info ) - self.set_readonly() - # --- end of update_now (...) --- - - def update_unsafe ( self, **info ): - """Updates the package info data without retrieving any locks or - checking writability. - Meant for usage with "package actions" (packagerules module). - - arguments: - * **info -- - """ - self._update ( info ) - # --- end of update_unsafe (...) --- - - def update ( self, **info ): - """Uses **info to update the package info data. - - arguments: - * **info -- - - raises: Exception when readonly - """ - if len ( info ) == 0: - # nothing to do - return - - # remove_auto has to be the last action (keyword order is not "stable") - remove_auto = info.pop ( 'remove_auto', None ) - - self._writelock_acquire() - - try: - self._update ( info ) - - if remove_auto: - self._remove_auto ( remove_auto ) - finally: - self._update_lock.release() - # --- end of update (**kw) --- - - def add_evar ( self, evar, unsafe=False ): - """Adds an ebuild variable. - - arguments: - * evar -- - """ -# if self.readonly or hasattr ( self, '_readonly_final' ): -# raise Exception ( "package info is readonly!" ) -# else: - - if unsafe: - if not hasattr ( self, '_evars' ): - self._evars = dict() - - self._evars [evar.get_pseudo_hash()] = evar - else: - raise Exception ( "unsafe=False is deprecated" ) - # --- end of add_evar (...) --- - - def get_evars ( self ): - """Returns all ebuild variables.""" - if hasattr ( self, '_evars' ): - return list ( self._evars.values() ) - else: - return None - # --- end of get_evars (...) --- - - def _update ( self, info ): - """Updates self._info using the given info dict. - - arguments: - * info -- - """ - initial = len ( self._info ) == 0 - - for key, value in info.items(): - - if key in self.__class__._UPDATE_KEYS_SIMPLE: - self [key] = value - - elif initial and key in self.__class__._UPDATE_KEYS_SIMPLE_INITIAL: - self [key] = value - - elif key in self.__class__._UPDATE_KEYS_FILTER_NONE: - if value is not None: - self [key] = value - - elif key == 'filename': - self._use_filename ( value ) - - elif key == 'pvr': - self._use_pvr ( value ) - - elif key == 'suggests': - self ['has_suggests'] = value - - elif key == 'depres_result': - self ['has_suggests'] = value [2] - - elif key == 'filepath': - self._use_filepath ( value ) - - elif key == 'remove': - for k in value: - try: - if k in self._info: del self._info [k] - except KeyError: - pass - - elif key == 'make_desc_data': - if value: - self.get_desc_data() - - else: - self.logger.error ( - "in _update(): unknown info key {}!".format ( key ) - ) - # -- end for; - # --- end of _update (...) --- - - def _use_filename ( self, _filename ): - """auxiliary method for update(**kw) - - arguments: - * _filename -- - """ - filename_with_ext = _filename - - # remove .tar.gz .tar.bz2 etc. - filename = PackageInfo.PKGSUFFIX_REGEX.sub ( '', filename_with_ext ) - - self.logger = logging.getLogger ( filename ) - - package_name, sepa, package_version = filename.partition ( - config.get ( 'R_PACKAGE.name_ver_separator', '_' ) - ) - - if not sepa: - # file name unexpected, tarball extraction will (probably) fail - self.logger.error ( "unexpected file name {!r}.".format ( filename ) ) - raise Exception ( "cannot use file {!r}.".format ( filename ) ) - return - - version_str = PackageInfo.EBUILDVER_REGEX.sub ( '.', package_version ) - - try: - version = tuple ( int ( z ) for z in version_str.split ( '.' ) ) - self ['version'] = version - except ValueError as ve: - # version string is malformed, cannot use it - self.logger.error ( - "Cannot parse version string {!r} for {!r}".format ( - _filename, version_str - ) - ) - raise - - # using package name as name (unless modified later), - # using pkg_version for the ebuild version - - # removing illegal chars from the package_name - ebuild_name = strutil.fix_ebuild_name ( package_name ) - - if ebuild_name != package_name: - self ['name'] = ebuild_name - - self ['ebuild_verstr'] = version_str - - # for DescriptionReader - self ['package_name'] = package_name - - self ['package_filename'] = filename_with_ext - # --- end of _use_filename (...) --- - - def _use_pvr ( self, pvr ): - # 0.1_pre2-r17 -> ( 0, 1 ) - pv = pvr.partition ( '-' ) [0] - self ['version'] = tuple ( - int ( z ) for z in ( pv.partition ( '_' ) [0].split ( '.' ) ) - ) - self ['ebuild_verstr'] = pvr - # --- end of _use_pvr (...) --- - - def _remove_auto ( self, ebuild_status ): - """Removes all keys from this PackageInfo instance that are useless - after entering status 'ebuild_status' (like ebuild in overlay and - written -> don't need the ebuild string etc.) - """ - with self._update_lock: - - if ebuild_status == 'ebuild_written': - - # selectively deleting entries that are no longer required - - for key in self.__class__._REMOVE_KEYS_EBUILD: - try: - del self._info [key] - except KeyError: - pass - # -- if - # -- lock - # --- end of _remove_auto (...) --- - - def _use_filepath ( self, _filepath ): - """auxiliary method for update(**kw) - - arguments: - * _filepath -- - """ - self.logger.warn ( - 'Please note that _use_filepath is only meant for testing.' - ) - filepath = os.path.abspath ( _filepath ) - self ['package_file'] = filepath - self._use_filename ( os.path.basename ( filepath ) ) - # --- end of _use_filepath (...) --- - - def __str__ ( self ): - return "<PackageInfo for {pkg}>".format ( - pkg=self.get ( - 'package_file', fallback_value='[unknown file]', do_fallback=True - ) ) - # --- end of __str__ (...) --- + """PackageInfo offers easy, subscriptable access to package + information, whether stored or calculated. + + class-wide variables: + * EBUILDVER_REGEX -- a regex containing chars that will be replaced by + a dot '.'. (e.g. 2-3 becomes 2.3) + * PKGSUFFIX_REGEX -- a regex that matches the suffix of an R package file + name. The regex str is retrieved from the config + module (which also means that the config has to be + loaded before import this module) + * ALWAYS_FALLBACK -- a set of keys for which get() always returns a + fallback value (None) + + * _UPDATE_KEYS_SIMPLE -- a set of keys that can be added + without further checks + * _UPDATE_KEYS_SIMPLE_INITIAL -- like _UPDATE_KEYS_SIMPLE, but only used + on the first update() call (as long as + no keys have been stored) + * _UPDATE_KEYS_FILTER_NONE -- like _UPDATE_KEYS_SIMPLE, but stores + key's value only if it is not None + * _REMOVE_KEYS_EBUILD -- a set of keys that will be removed when + _remove_auto ( 'ebuild_written' ) is + called. + """ + + EBUILDVER_REGEX = re.compile ( '[-]{1,}' ) + PKGSUFFIX_REGEX = re.compile ( + config.get_or_fail ( 'R_PACKAGE.suffix_regex' ) + '$' + ) + ALWAYS_FALLBACK = frozenset ( ( 'ebuild', 'ebuild_file' ) ) + + _UPDATE_KEYS_SIMPLE = frozenset (( + 'origin', + 'ebuild', + 'ebuild_file', + 'physical_only', + 'src_uri', + )) + _UPDATE_KEYS_SIMPLE_INITIAL = frozenset (( + 'package_filename', + )) + _UPDATE_KEYS_FILTER_NONE = frozenset (( + 'src_uri_base', + 'distdir', + )) + + _REMOVE_KEYS_EBUILD = frozenset (( + 'ebuild' + )) + + def __init__ ( self, **initial_info ): + """Initializes a PackageInfo. + + arguments: + * **initial_info -- passed to update ( **kw ) + """ + self._info = dict() + #self._evars = dict() + self.readonly = False + self._update_lock = threading.RLock() + self.overlay_package_ref = None + self.logger = LOGGER + + self.update ( **initial_info ) + # --- end of __init__ (...) --- + + def set_readonly ( self, immediate=False, final=False ): + """Makes the package info readonly. + + arguments: + * immediate -- do not acquire lock, set readonly directly, + defaults to False + * final -- if set and True: make this decision final + """ + self._set_mode ( True, immediate, final ) + # --- end of set_readonly (...) --- + + def set_writeable ( self, immediate=False ): + """Makes the package info writeable. + + arguments: + * immediate -- do not acquire lock, set writeable directly, + defaults to False + """ + self._set_mode ( False, immediate ) + # --- end of set_writeable (...) --- + + def _set_mode ( self, readonly_val, immediate=False, final=False ): + """Sets readonly to True/False. + + arguments: + * readonly_val -- new value for readonly + * immediate -- do not acquire lock + * final -- only if readonly_val is True: make this decision final, + + raises: Exception if self.readonly is a constant (_readonly_final is set) + """ + if hasattr ( self, '_readonly_final' ): + raise Exception ( "cannot modify readonly - it's a constant." ) + elif immediate: + self.readonly = readonly_val + if final and readonly_val: + self._readonly_final = True + elif not self.readonly is readonly_val: + self._update_lock.acquire() + self.readonly = readonly_val + if final and readonly_val: + self._readonly_final = True + self._update_lock.release() + # --- end of _set_mode (...) --- + + def _writelock_acquire ( self ): + """Acquires the lock required for adding new information. + + raises: Exception if readonly (writing not allowed) + """ + if self.readonly or hasattr ( self, '_readonly_final' ): + raise Exception ( "package info is readonly!" ) + + self._update_lock.acquire() + + if self.readonly or hasattr ( self, '_readonly_final' ): + self._update_lock.release() + raise Exception ( "package info is readonly!" ) + + return True + # --- end of _writelock_acquire (...) --- + + def _has_log_keyerror_unexpected ( self, key, error ): + self.logger.error ( + 'FIXME: PackageInfo.get( {!r}, do_fallback=True ) ' + 'raised KeyError'.format ( key ) + ) + self.logger.exception ( error ) + # --- end of _has_log_keyerror_unexpected (...) --- + + def has_key ( self, *keys ): + """Returns False if at least one key out of keys is not accessible, + i.e. its data cannot be retrieved using get()/__getitem__(). + + arguments: + * *keys -- keys to check + """ + for k in keys: + if k not in self._info: + # try harder - use get() with fallback value to see if value + # can be calculated + try: + if self.get ( k, do_fallback=True ) is None: + return False + except KeyError as kerr: + self._has_log_keyerror_unexpected ( k, kerr ) + return False + return True + # --- end of has_key (...) --- + + has = has_key + + def has_key_or ( self, *keys ): + """Returns True if at least one key out of keys is accessible. + + arguments: + * *keys -- keys to check + """ + for k in keys: + try: + if k in self._info: + return True + elif self.get ( k, do_fallback=True ) is not None: + return True + except KeyError as kerr: + self._has_log_keyerror_unexpected ( k, kerr ) + return False + # --- end of has_key_or (...) --- + + has_or = has_key_or + + def compare_version ( self, other_package ): + """Compares the version of two PackageInfo objects. + Returns 1 if self's version is higher, -1 if lower and 0 if equal. + + arguments: + * other_package -- + """ + if other_package is None: return 1 + + my_ver = self.get ( 'version', fallback_value=0 ) + other_ver = other_package.get ( 'version', fallback_value=0 ) + + if my_ver > other_ver: + return 1 + elif my_ver == other_ver: + return 0 + else: + return -1 + # --- end of compare_version (...) --- + + def get ( self, key, fallback_value=None, do_fallback=False ): + """Returns the value specified by key. + The value is either calculated or taken from dict self._info. + + arguments: + * key -- + * fallback_value -- fallback value if key not found / unknown + * do_fallback -- if True: return fallback_value, else raise KeyError + + raises: KeyError + """ + # normal dict access shouldn't be slowed down here + if key in self._info: return self._info [key] + + key_low = key.lower() + + if key_low in self._info: + return self._info [key_low] + + # 'virtual' keys - calculate result + elif key_low == 'name': + # no special name, using package_name + return self._info ['package_name'] + + elif key_low == 'package_file': + distdir = self.get ( 'distdir', do_fallback=True ) + if distdir: + fname = self._info.get ( 'package_filename', None ) + if fname: + return distdir + os.path.sep + fname + + elif key_low == 'distdir': + if 'origin' in self._info: + # this doesn't work if the package is in a sub directory + # of the repo's distdir + return self._info ['origin'].distdir + elif 'package_file' in self._info: + return os.path.dirname ( self._info ['package_file'] ) + # else fallback/KeyError + + elif key_low == 'has_suggests': + # 'has_suggests' not in self._info -> assume False + return False + + elif key_low == 'physical_only': + # 'physical_only' not in self._info -> assume False + return False + + elif key_low == 'src_uri': + if 'src_uri_base' in self._info: + return \ + self._info ['src_uri_base'] + '/' + \ + self._info ['package_filename'] + + elif 'origin' in self._info: + return self._info ['origin'].get_src_uri ( + self._info ['package_filename'] + ) + else: + return "http://localhost/R-packages/" + \ + self._info ['package_filename'] + + elif key_low == 'ebuild_dir': + ebuild_file = self._info ['ebuild_file'] + if ebuild_file is not None: + return os.path.dirname ( ebuild_file ) + + elif key_low == 'ebuild_filename': + ebuild_file = self._info ['ebuild_file'] + if ebuild_file is not None: + return os.path.basename ( ebuild_file ) + + # end if <key matches ...> + + + # fallback + if do_fallback or fallback_value is not None: + return fallback_value + + elif key_low in self.__class__.ALWAYS_FALLBACK: + return None + + else: + raise KeyError ( key ) + # --- end of get (...) --- + + def get_desc_data ( self ): + """Returns the DESCRIPTION data for this PackageInfo (by reading the + R package file if necessary). + """ + if 'desc_data' in self._info: + return self._info ['desc_data'] + + self._writelock_acquire() + if 'desc_data' not in self._info: + self._info ['desc_data'] = descriptionreader.read ( self ) + + self._update_lock.release() + return self._info ['desc_data'] + # --- end of get_desc_data (...) --- + + def __getitem__ ( self, key ): + """Returns an item.""" + return self.get ( key, do_fallback=False ) + # --- end of __getitem__ (...) --- + + def __setitem__ ( self, key, value ): + """Sets an item. + + arguments: + * key -- + * value -- + + raises: Exception when readonly + """ + self._writelock_acquire() + self._info [key] = value + self._update_lock.release() + # --- end of __setitem__ (...) --- + + def update_now ( self, **info ): + """Updates the package info data with temporarily enabling write access. + Data will be readonly after calling this method. + + arguments: + * **info -- + """ + if len ( info ) == 0: return + with self._update_lock: + self.set_writeable() + self.update ( **info ) + self.set_readonly() + # --- end of update_now (...) --- + + def update_unsafe ( self, **info ): + """Updates the package info data without retrieving any locks or + checking writability. + Meant for usage with "package actions" (packagerules module). + + arguments: + * **info -- + """ + self._update ( info ) + # --- end of update_unsafe (...) --- + + def update ( self, **info ): + """Uses **info to update the package info data. + + arguments: + * **info -- + + raises: Exception when readonly + """ + if len ( info ) == 0: + # nothing to do + return + + # remove_auto has to be the last action (keyword order is not "stable") + remove_auto = info.pop ( 'remove_auto', None ) + + self._writelock_acquire() + + try: + self._update ( info ) + + if remove_auto: + self._remove_auto ( remove_auto ) + finally: + self._update_lock.release() + # --- end of update (**kw) --- + + def add_evar ( self, evar, unsafe=False ): + """Adds an ebuild variable. + + arguments: + * evar -- + """ +# if self.readonly or hasattr ( self, '_readonly_final' ): +# raise Exception ( "package info is readonly!" ) +# else: + + if unsafe: + if not hasattr ( self, '_evars' ): + self._evars = dict() + + self._evars [evar.get_pseudo_hash()] = evar + else: + raise Exception ( "unsafe=False is deprecated" ) + # --- end of add_evar (...) --- + + def get_evars ( self ): + """Returns all ebuild variables.""" + if hasattr ( self, '_evars' ): + return list ( self._evars.values() ) + else: + return None + # --- end of get_evars (...) --- + + def _update ( self, info ): + """Updates self._info using the given info dict. + + arguments: + * info -- + """ + initial = len ( self._info ) == 0 + + for key, value in info.items(): + + if key in self.__class__._UPDATE_KEYS_SIMPLE: + self [key] = value + + elif initial and key in self.__class__._UPDATE_KEYS_SIMPLE_INITIAL: + self [key] = value + + elif key in self.__class__._UPDATE_KEYS_FILTER_NONE: + if value is not None: + self [key] = value + + elif key == 'filename': + self._use_filename ( value ) + + elif key == 'pvr': + self._use_pvr ( value ) + + elif key == 'suggests': + self ['has_suggests'] = value + + elif key == 'depres_result': + self ['has_suggests'] = value [2] + + elif key == 'filepath': + self._use_filepath ( value ) + + elif key == 'remove': + for k in value: + try: + if k in self._info: del self._info [k] + except KeyError: + pass + + elif key == 'make_desc_data': + if value: + self.get_desc_data() + + else: + self.logger.error ( + "in _update(): unknown info key {}!".format ( key ) + ) + # -- end for; + # --- end of _update (...) --- + + def _use_filename ( self, _filename ): + """auxiliary method for update(**kw) + + arguments: + * _filename -- + """ + filename_with_ext = _filename + + # remove .tar.gz .tar.bz2 etc. + filename = PackageInfo.PKGSUFFIX_REGEX.sub ( '', filename_with_ext ) + + self.logger = logging.getLogger ( filename ) + + package_name, sepa, package_version = filename.partition ( + config.get ( 'R_PACKAGE.name_ver_separator', '_' ) + ) + + if not sepa: + # file name unexpected, tarball extraction will (probably) fail + self.logger.error ( "unexpected file name {!r}.".format ( filename ) ) + raise Exception ( "cannot use file {!r}.".format ( filename ) ) + return + + version_str = PackageInfo.EBUILDVER_REGEX.sub ( '.', package_version ) + + try: + version = tuple ( int ( z ) for z in version_str.split ( '.' ) ) + self ['version'] = version + except ValueError as ve: + # version string is malformed, cannot use it + self.logger.error ( + "Cannot parse version string {!r} for {!r}".format ( + _filename, version_str + ) + ) + raise + + # using package name as name (unless modified later), + # using pkg_version for the ebuild version + + # removing illegal chars from the package_name + ebuild_name = strutil.fix_ebuild_name ( package_name ) + + if ebuild_name != package_name: + self ['name'] = ebuild_name + + self ['ebuild_verstr'] = version_str + + # for DescriptionReader + self ['package_name'] = package_name + + self ['package_filename'] = filename_with_ext + # --- end of _use_filename (...) --- + + def _use_pvr ( self, pvr ): + # 0.1_pre2-r17 -> ( 0, 1 ) + pv = pvr.partition ( '-' ) [0] + self ['version'] = tuple ( + int ( z ) for z in ( pv.partition ( '_' ) [0].split ( '.' ) ) + ) + self ['ebuild_verstr'] = pvr + # --- end of _use_pvr (...) --- + + def _remove_auto ( self, ebuild_status ): + """Removes all keys from this PackageInfo instance that are useless + after entering status 'ebuild_status' (like ebuild in overlay and + written -> don't need the ebuild string etc.) + """ + with self._update_lock: + + if ebuild_status == 'ebuild_written': + + # selectively deleting entries that are no longer required + + for key in self.__class__._REMOVE_KEYS_EBUILD: + try: + del self._info [key] + except KeyError: + pass + # -- if + # -- lock + # --- end of _remove_auto (...) --- + + def _use_filepath ( self, _filepath ): + """auxiliary method for update(**kw) + + arguments: + * _filepath -- + """ + self.logger.warn ( + 'Please note that _use_filepath is only meant for testing.' + ) + filepath = os.path.abspath ( _filepath ) + self ['package_file'] = filepath + self._use_filename ( os.path.basename ( filepath ) ) + # --- end of _use_filepath (...) --- + + def __str__ ( self ): + return "<PackageInfo for {pkg}>".format ( + pkg=self.get ( + 'package_file', fallback_value='[unknown file]', do_fallback=True + ) ) + # --- end of __str__ (...) --- |