diff options
author | André Erdmann <dywi@mailerd.de> | 2012-06-22 20:08:17 +0200 |
---|---|---|
committer | André Erdmann <dywi@mailerd.de> | 2012-06-22 20:08:17 +0200 |
commit | 7bcd6b886d402fda204ffe87c3e89b64207b4c88 (patch) | |
tree | 3966e0b8ab65b36f24e8990186fc2d691ef92898 /roverlay | |
parent | fix wait() in overlay creation (diff) | |
download | R_overlay-7bcd6b886d402fda204ffe87c3e89b64207b4c88.tar.gz R_overlay-7bcd6b886d402fda204ffe87c3e89b64207b4c88.tar.bz2 R_overlay-7bcd6b886d402fda204ffe87c3e89b64207b4c88.zip |
comments and minor fixes
deleted: roverlay/Makefile
modified: roverlay/config/const.py
modified: roverlay/config/loader.py
modified: roverlay/config/tree.py
modified: roverlay/config/util.py
deleted: roverlay/depres/Makefile
modified: roverlay/depres/channels.py
modified: roverlay/depres/communication.py
modified: roverlay/depres/depenv.py
modified: roverlay/depres/depresolver.py
modified: roverlay/depres/deprule.py
modified: roverlay/depres/listeners.py
modified: roverlay/depres/simpledeprule.py
modified: roverlay/ebuild/abstractcomponents.py
modified: roverlay/ebuild/creation.py
modified: roverlay/ebuild/depres.py
modified: roverlay/ebuild/ebuilder.py
modified: roverlay/ebuild/evars.py
modified: roverlay/manifest/helpers.py
modified: roverlay/metadata/__init__.py
modified: roverlay/metadata/abstractnodes.py
modified: roverlay/metadata/nodes.py
modified: roverlay/overlay/__init__.py
modified: roverlay/overlay/category.py
modified: roverlay/overlay/package.py
modified: roverlay/rpackage/descriptionfields.py
modified: roverlay/rpackage/descriptionreader.py
Diffstat (limited to 'roverlay')
27 files changed, 376 insertions, 162 deletions
diff --git a/roverlay/Makefile b/roverlay/Makefile deleted file mode 100644 index bfbbe98..0000000 --- a/roverlay/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -.PHONY: default -default: ../Makefile - cd .. && make diff --git a/roverlay/config/const.py b/roverlay/config/const.py index a69a33a..18e4614 100644 --- a/roverlay/config/const.py +++ b/roverlay/config/const.py @@ -8,7 +8,7 @@ import time _CONSTANTS = dict ( DESCRIPTION = dict ( field_separator = ':', - comment_char = '#', + comment_chars = '#;', list_split_regex = '\s*[,;]{1}\s*', file_name = 'DESCRIPTION', ), diff --git a/roverlay/config/loader.py b/roverlay/config/loader.py index 62f0980..5983b72 100644 --- a/roverlay/config/loader.py +++ b/roverlay/config/loader.py @@ -1,4 +1,4 @@ -# R overlay -- config module +# R overlay -- config module, config file loader # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -18,6 +18,12 @@ class ConfigLoader ( object ): def __init__ ( self, config_tree, logger=None ): + """Initializes a ConfigLoader. + + arguments: + * config_tree -- ConfigTree + * logger -- logger to use, defaults to config_tree's logger + """ self.ctree = config_tree self.config_root = None @@ -28,6 +34,13 @@ class ConfigLoader ( object ): # --- end of __init__ (...) --- def _setval ( self, path, value, allow_empty_value=False ): + """Sets a value in the config tree. + + arguments: + * path -- config path + * value -- config value + * allow_empty_value -- + """ self.ctree._findpath ( path, value=value, @@ -39,6 +52,15 @@ class ConfigLoader ( object ): # --- end of _setval (...) --- def _config_entry ( self, cref, option, value, config_root ): + """Adds a normal config entry to the assigned ConfigTree. + + arguments: + * cref -- reference to the config option's entry in the + CONFIG_ENTRY_MAP + * option -- name of the config option + * value -- value read from a config file (will be verified here) + * config_root -- ignored; + """ # determine the config path path = None if 'path' in cref: @@ -196,12 +218,12 @@ class ConfigLoader ( object ): def _make_and_verify_value ( self, value_type, value ): """Prepares the value of a config option so that it can be used - in the ConfigLoader. + in the config. arguments: - * value_type -- type of the value, - look above for explanation concerning this - * value -- value to verify and transform + * value_type -- type of the value, + look above for explanation concerning this + * value -- value to verify and transform """ def to_int ( val, fallback_value=-1 ): @@ -289,6 +311,7 @@ class ConfigLoader ( object ): # --- end of fs_dir (...) --- def repo ( val ): + """To be removed. (FIXME)""" if not val: return None name, sepa, remainder = val.partition ( ':' ) diff --git a/roverlay/config/tree.py b/roverlay/config/tree.py index b38bc2c..707aa8a 100644 --- a/roverlay/config/tree.py +++ b/roverlay/config/tree.py @@ -55,10 +55,12 @@ class ConfigTree ( object ): # --- end of __init__ (...) --- def get_loader ( self ): + """Returns a ConfigLoader for this ConfigTree.""" return ConfigLoader ( self ) # --- end of get_loader (...) --- - def _findpath ( self, path, + def _findpath ( + self, path, root=None, create=False, value=None, forcepath=False, forceval=False ): """All-in-one method that searches for a config path. @@ -66,13 +68,13 @@ class ConfigTree ( object ): value to it. arguments: - * path -- config path as path list ([a,b,c]) or as path str (a.b.c) - * root -- config root (dict expected). - Uses self._config if None (the default) - * create -- create path if nonexistent - * value -- assign value to the last path element - an empty dict will be created if this is None and - create is True + * path -- config path as path list ([a,b,c]) or as path str (a.b.c) + * root -- config root (dict expected). + Uses self._config if None (the default) + * create -- create path if nonexistent + * value -- assign value to the last path element + an empty dict will be created if this is None and + create is True * forcepath -- if set and True: do not 'normalize' path if path is a list * forceval -- if set and True: accept None as value """ diff --git a/roverlay/config/util.py b/roverlay/config/util.py index c1aef66..ea70465 100644 --- a/roverlay/config/util.py +++ b/roverlay/config/util.py @@ -1,9 +1,14 @@ -# R Overlay -- config, <?> +# R Overlay -- config, utility functions # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 def get_config_path ( key ): - """Creates a config path for key.""" + """Creates a config path for key. + + arguments: + * key -- + + """ _path = key.split ( '.' ) if isinstance ( key, str ) else key if isinstance ( _path, ( list, tuple ) ): # config paths are [ CAPSLOCK, CAPSLOCK,.... , lowercase item ] @@ -12,14 +17,19 @@ def get_config_path ( key ): return _path # --- end of get_config_path (...) --- -def unquote ( _str ): +def unquote ( _str, keep_going=False): + """Removes enclosing quotes from a string. + + arguments: + * _str -- + * keep_going -- remove all enclosing quotes ("'"a"'" -> a) + """ if len ( _str ) < 2: return _str - chars = '"' - chars += "'" + chars = '\"\'' for c in chars: if _str [0] == c and _str [-1] == c: - return _str[1:-1] + return unquote ( _str[1:-1] ) if keep_going else _str[1:-1] return _str # --- end of unquote (...) --- diff --git a/roverlay/depres/Makefile b/roverlay/depres/Makefile deleted file mode 120000 index d0b0e8e..0000000 --- a/roverlay/depres/Makefile +++ /dev/null @@ -1 +0,0 @@ -../Makefile
\ No newline at end of file diff --git a/roverlay/depres/channels.py b/roverlay/depres/channels.py index 765d241..65d4d45 100644 --- a/roverlay/depres/channels.py +++ b/roverlay/depres/channels.py @@ -52,6 +52,7 @@ class EbuildJobChannel ( DependencyResolverChannel ): # --- end of __init__ (...) --- def close ( self ): + """Closes this channel.""" if self._depdone >= 0: # else already closed @@ -64,7 +65,13 @@ class EbuildJobChannel ( DependencyResolverChannel ): # --- end of close (...) --- def set_resolver ( self, resolver, channel_queue, **extra ): - """ comment todo """ + """Assigns a resolver to this channel. + + arguments: + * resolver -- + * channel_queue -- the queue where the resolver puts processed DepEnvs in + * **extra -- ignored; + """ if self._depres_master is None: self._depres_master = resolver self._depres_queue = channel_queue @@ -180,6 +187,10 @@ class EbuildJobChannel ( DependencyResolverChannel ): return False # --- end of handle_queue_item (...) --- + + # loop until + # (a) at least one dependency could not be resolved or + # (b) all deps processed while self._depdone < len ( self.dep_env_list ) and satisfiable: # tell the resolver to start self._depres_master.start() @@ -187,6 +198,7 @@ class EbuildJobChannel ( DependencyResolverChannel ): # wait for one result at least satisfiable = handle_queue_item ( self._depres_queue.get() ) + # and process all available results while not self._depres_queue.empty() and satisfiable: satisfiable = handle_queue_item ( self._depres_queue.get_nowait() ) # --- end while @@ -197,6 +209,4 @@ class EbuildJobChannel ( DependencyResolverChannel ): else: if close_if_unresolvable: self.close() return None - - - # --- end of join (...) --- + # --- end of satisfy_request (...) --- diff --git a/roverlay/depres/communication.py b/roverlay/depres/communication.py index 33e1e8f..943e2ca 100644 --- a/roverlay/depres/communication.py +++ b/roverlay/depres/communication.py @@ -65,7 +65,13 @@ class DependencyResolverChannel ( object ): # --- end of __init__ (...) --- def set_resolver ( self, resolver, channel_queue=None, **extra ): - """comment todo.""" + """Assigns a resolver to this channel. + + arguments: + * resolver -- + * channel_queue -- ignored; + * **extra -- ignored + """ self._depres_master = resolver # --- end of set_resolver (...) --- diff --git a/roverlay/depres/depenv.py b/roverlay/depres/depenv.py index 889af9c..0cb81e8 100644 --- a/roverlay/depres/depenv.py +++ b/roverlay/depres/depenv.py @@ -22,12 +22,14 @@ class DepEnv ( object ): self.status = DepEnv.STATUS_UNDONE self.resolved_by = None - # TODO: analyze dep_str: extract dep name, dep version, useless comments,... + # TODO: analyze dep_str: + # extract dep name, dep version, useless comments,... # --- end of __init__ (...) --- def set_resolved ( self, resolved_by, append=False ): - """Marks this DepEnv as resolved with resolved_by as corresponding portage package. + """Marks this DepEnv as resolved with resolved_by as corresponding + portage package. arguments: * resolved_by -- resolving portage package @@ -39,7 +41,9 @@ class DepEnv ( object ): # useful? raise Exception ( "appending is not supported..." ) else: - raise Exception ( "dependency is already resolved and append is disabled." ) + raise Exception ( + "dependency is already resolved and append is disabled." + ) # add RESOLVED status self.status |= DepEnv.STATUS_RESOLVED @@ -50,7 +54,8 @@ class DepEnv ( object ): """Marks this DepEnv as unresolvable. arguments: - force -- force unresolvable status even if this DepEnv is already resolved + force -- force unresolvable status even if this DepEnv + is already resolved """ if force or not self.status & DepEnv.STATUS_RESOLVED: self.resolved_by = None diff --git a/roverlay/depres/depresolver.py b/roverlay/depres/depresolver.py index cb70c14..3b0e481 100644 --- a/roverlay/depres/depresolver.py +++ b/roverlay/depres/depresolver.py @@ -294,8 +294,8 @@ class DependencyResolver ( object ): self._report_event ( 'UNRESOLVABLE', dep_env ) if channel_id in self._depqueue_done: - ## todo/fixme/whatever: this 'if' can filter out channels that have - ## been added again + ## todo/fixme/whatever: this 'if' can filter out channels + ## that have been added again self._depqueue_done [channel_id].put ( dep_env ) except queue.Empty: diff --git a/roverlay/depres/deprule.py b/roverlay/depres/deprule.py index a585de3..b02213c 100644 --- a/roverlay/depres/deprule.py +++ b/roverlay/depres/deprule.py @@ -36,14 +36,16 @@ class DependencyRulePool ( object ): self.rules = list () self.name = name self.priority = priority - # the "rule weight" is the sum of the rules' priorities - it's used to - # compare/sort dependency pools with the same priority (lesser weight is better) + # the "rule weight" is the sum of the rules' priorities + # it's used to compare/sort dependency pools with + # the same priority (lesser weight is better) self.rule_weight = 0 # --- end of __init__ (...) --- def sort ( self ): - """Sorts this rule pool and determines its weight which is used to compare - rule pools.""" + """Sorts this rule pool and determines its weight which is used + to compare rule pools. + """ self.rules.sort ( key=lambda rule : rule.priority ) diff --git a/roverlay/depres/listeners.py b/roverlay/depres/listeners.py index 5034a70..0c123c0 100644 --- a/roverlay/depres/listeners.py +++ b/roverlay/depres/listeners.py @@ -9,8 +9,16 @@ from roverlay.depres.depenv import DepEnv from roverlay.depres.communication import DependencyResolverListener class FileListener ( DependencyResolverListener ): + """A dependency resolution listener that writes events to a file.""" def __init__ ( self, _file, listen_mask ): + """Initializes a FileListener. + + arguments: + * _file -- file to write + * listen_mask -- a bit mask (int) that defines the events to be + processed. + """ super ( FileListener, self ) . __init__ () self.fh = None @@ -22,6 +30,7 @@ class FileListener ( DependencyResolverListener ): # --- end of __init__ (...) --- def _event ( self, event_type, to_write ): + """Writes to_write if event_type is accepted by self.listen_mask.""" if self.mask & event_type: if not self.fh: self.fh = open ( self._file, 'a' ) # or w? self.fh.write ( to_write + "\n" ) @@ -29,11 +38,13 @@ class FileListener ( DependencyResolverListener ): # --- end of _event (...) --- def close ( self ): + """Closes this listener (closes the file handle if open).""" if self.fh: self.fh.close() # --- end of close (...) --- class ResolvedFileListener ( FileListener ): + """A FileListener that listens to 'dependency resolved' events.""" def __init__ ( self, _file ): super ( ResolvedFileListener, self ) . __init__ ( @@ -48,6 +59,7 @@ class ResolvedFileListener ( FileListener ): # --- end of notify (...) --- class UnresolvableFileListener ( FileListener ): + """A FileListener that listens to 'dependency unresolvable' events.""" def __init__ ( self, _file ): super ( UnresolvableFileListener, self ) . __init__ ( _file, events.DEPRES_EVENTS ['UNRESOLVABLE'] diff --git a/roverlay/depres/simpledeprule.py b/roverlay/depres/simpledeprule.py index 55732c4..ee40045 100644 --- a/roverlay/depres/simpledeprule.py +++ b/roverlay/depres/simpledeprule.py @@ -103,7 +103,7 @@ class SimpleIgnoreDependencyRule ( deprule.DependencyRule ): else: resolving_package = resolving_to - # todo hardcoded here + # todo hardcoded rule format here if alias_count > 1: retlist = [ resolving_package + ' {\n' ] + \ @@ -219,7 +219,7 @@ class SimpleDependencyRuleReader ( object ): one_line_separator = re.compile ( '\s+::\s+' ) multiline_start = '{' multiline_stop = '}' - comment_chars = list ( '#;' ) + comment_chars = "#;" # todo: const/config? package_ignore = [ '!' ] diff --git a/roverlay/ebuild/abstractcomponents.py b/roverlay/ebuild/abstractcomponents.py index 73dac03..019c252 100644 --- a/roverlay/ebuild/abstractcomponents.py +++ b/roverlay/ebuild/abstractcomponents.py @@ -5,11 +5,23 @@ INDENT = '\t' def listlike ( ref ): + """Returns True if ref is listlike (a non-str iterable).""" return hasattr ( ref, '__iter__' ) and not isinstance ( ref, str ) class ListValue ( object ): + """An evar value with a list of elements.""" def __init__ ( self, value, indent_level=1, empty_value=None ): + """Initializes a ListValue. + + arguments: + * value -- + * indent_level -- indention level ('\t') for extra value lines + * empty_value -- if set: a string value that is always part + of this ListValue's elements but ignored + by len(). + Use cases are '${IUSE:-}' in the IUSE var etc. + """ self.set_level ( indent_level ) self.empty_value = empty_value @@ -23,13 +35,14 @@ class ListValue ( object ): self.val_join = ' ' self.set_value ( value ) - + # --- end of __init__ (...) --- def __len__ ( self ): l = len ( self.value ) return l if self.empty_value is None else l - 1 def set_level ( self, level ): + """Sets the indention level.""" self.level = level self.var_indent = (level - 1) * INDENT self.val_indent = level * INDENT @@ -37,6 +50,7 @@ class ListValue ( object ): # --- end of set_level (...) --- def set_value ( self, value ): + """Sets the value.""" self.value = list() if self.empty_value is not None: self.value.append ( self.empty_value ) @@ -44,6 +58,7 @@ class ListValue ( object ): # --- end of set_value (...) --- def add_value ( self, value ): + """Adds/Appends a value.""" if value is None: pass elif listlike ( value ): @@ -55,6 +70,7 @@ class ListValue ( object ): add = add_value def to_str ( self ): + """Returns a string representing this ListValue.""" if len ( self.value ) == 0: ret = "" elif len ( self.value ) == 1: @@ -73,21 +89,37 @@ class ListValue ( object ): class EbuildVar ( object ): + """An ebuild variable.""" def __init__ ( self, name, value, priority ): + """Initializes an EbuildVar. + + arguments: + * name -- e.g. 'SRC_URI' + * value -- + * priority -- used for sorting (e.g. 'R_SUGGESTS' before 'DEPEND'), + lower means higher priority + """ self.name = name self.priority = priority self.value = value self.set_level ( 0 ) def set_level ( self, level ): + """Sets the indention level.""" self.level = level self.indent = self.level * INDENT if hasattr ( self.value, 'set_level' ): self.value.set_level ( level + 1 ) # --- end of set_level (...) --- - def active ( self ): return True + def active ( self ): + """Returns True if this EbuildVar is enabled and has a string to + return. + (EbuildVar's active() returns always True, derived classes may + override this.) + """ + return True def __str__ ( self ): return '%s%s="%s"' % ( self.indent, self.name, self.value ) diff --git a/roverlay/ebuild/creation.py b/roverlay/ebuild/creation.py index e2f4872..fca864d 100644 --- a/roverlay/ebuild/creation.py +++ b/roverlay/ebuild/creation.py @@ -1,4 +1,4 @@ -# R Overlay -- ebuild creation, <?> +# R Overlay -- ebuild creation # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -10,13 +10,26 @@ from roverlay.rpackage.descriptionreader import DescriptionReader LOGGER = logging.getLogger ( 'EbuildCreation' ) +# USE_FULL_DESCRIPTION +# * True: use Title and Description for ebuild's DESCRIPTION variable +# * else: use Title _or_ Description USE_FULL_DESCRIPTION = False +# FALLBACK_DESCRIPTION is used as DESCRIPTION= value if not empty and +# the R package has no Title/Description +FALLBACK_DESCRIPTION = "<none>" class EbuildCreation ( object ): + """Used to create an ebuild using DESCRIPTION data.""" def __init__ ( self, package_info, depres_channel_spawner=None ): + """Initializes the creation of an ebuild. + arguments: + * package_info -- + * depres_channel_spawner -- function that returns a communication + channel to the resolver + """ self.package_info = package_info self.logger = LOGGER.getChild ( package_info ['name'] ) @@ -24,7 +37,6 @@ class EbuildCreation ( object ): # > 0 busy/working; 0 == done,success; < 0 done,fail self.status = 1 - self.depres_channel_spawner = depres_channel_spawner self.package_info.set_readonly() @@ -36,6 +48,7 @@ class EbuildCreation ( object ): def fail ( self ) : return self.status < 0 def run ( self ): + """Creates an ebuild. Returns None (implicit).""" if self.status < 1: raise Exception ( "Cannot run again." ) @@ -58,6 +71,8 @@ class EbuildCreation ( object ): # --- end of run (...) --- def _lazyimport_desc_data ( self ): + """Reads R package description data.""" + # TODO/FIXME: read this somewhere else? if self.package_info.get ( 'desc_data', fallback_value=None, do_fallback=True ) is None: @@ -75,23 +90,51 @@ class EbuildCreation ( object ): # --- end of _lazyimport_desc_data (...) --- + def _get_ebuild_description ( self ): + """Creates a DESCRIPTION variable.""" + desc = self.package_info ['desc_data'] + + description = None + if USE_FULL_DESCRIPTION: + # use Title and Description for DESCRIPTION= + if 'Title' in desc: + description = desc ['Title'] + + if 'Description' in desc: + if description is None: + description = desc ['Description'] + else: + description += '// ' + desc ['Description'] + else: + # use either Title or Description for DESCRIPTION= + # (Title preferred 'cause it should be shorter) + if 'Title' in desc: + description = desc ['Title'] + elif 'Description' in desc: + description = desc ['Description'] + + + if description is not None: + return evars.DESCRIPTION ( description ) + elif FALLBACK_DESCRIPTION: + return evars.DESCRIPTION ( FALLBACK_DESCRIPTION ) + else: + return None + # --- end of _get_ebuild_description (...) --- def _make_ebuild ( self ): - desc = self.package_info ['desc_data'] - if desc is None: + """Tries to create ebuild data.""" + if self.package_info ['desc_data'] is None: self.logger ( 'desc empty - cannot create an ebuild for this package.' ) return False - ebuild = ebuilder.Ebuilder() - _dep_resolution = depres.EbuildDepRes ( self.package_info, self.logger, create_iuse=True, run_now=True, depres_channel_spawner=self.depres_channel_spawner ) - if not _dep_resolution.success(): # log here? (FIXME) return False @@ -99,29 +142,15 @@ class EbuildCreation ( object ): dep_result = _dep_resolution.get_result() + ebuild = ebuilder.Ebuilder() + # add *DEPEND, IUSE to the ebuild ebuild.use ( *dep_result [1] ) - description = None - if USE_FULL_DESCRIPTION: - if 'Title' in desc: - description = desc ['Title'] - - if 'Description' in desc: - if description is None: - description = desc ['Description'] - else: - description += '// ' + desc ['Description'] - else: - if 'Title' in desc: - description = desc ['Title'] - elif 'Description' in desc: - description = desc ['Description'] - - - if description is not None: - ebuild.use ( evars.DESCRIPTION ( description ) ) + # DESCRIPTION + ebuild.use ( self._get_ebuild_description() ) + # SRC_URI ebuild.use ( evars.SRC_URI ( self.package_info ['SRC_URI'] ) ) ebuild_text = ebuild.to_str() @@ -132,3 +161,4 @@ class EbuildCreation ( object ): ) return True + # --- end of _make_ebuild (...) --- diff --git a/roverlay/ebuild/depres.py b/roverlay/ebuild/depres.py index db0f906..3838060 100644 --- a/roverlay/ebuild/depres.py +++ b/roverlay/ebuild/depres.py @@ -6,7 +6,7 @@ import roverlay.static.depres from roverlay.ebuild import evars -# move this to const / config +# TODO/FIXME/IGNORE move this to const / config FIELDS = { 'R_SUGGESTS' : [ 'Suggests' ], 'DEPENDS' : [ 'Depends', 'Imports' ], @@ -21,11 +21,21 @@ EBUILDVARS = { class EbuildDepRes ( object ): + """Handles dependency resolution for a single ebuild.""" def __init__ ( self, package_info, logger, depres_channel_spawner, create_iuse=True, run_now=True ): + """Initializes an EbuildDepRes. + + arguments: + * package_info -- + * logger -- parent logger + * depres_channel_spawner -- used to get channels to the dep resolver + * create_iuse -- create an IUSE evar (if True) + * run_now -- immediately start after initialization + """ self.logger = logger.getChild ( 'depres' ) self.package_info = package_info @@ -56,10 +66,14 @@ class EbuildDepRes ( object ): def fail ( self ) : return self.status < 0 def get_result ( self ): + """Returns the result of dependency resolution, + as tuple ( <status>, <evars>, <has R suggests> ) + """ return ( self.status, self.result, self.has_suggests ) # --- end of get_result (...) --- def resolve ( self ): + """Try to make/get dependency resolution results. Returns None.""" try: self.result = None self._init_channels() @@ -80,6 +94,7 @@ class EbuildDepRes ( object ): # --- end of resolve (...) --- def _get_channel ( self, dependency_type ): + """Creates and returns a communication channel to the dep resolver.""" if dependency_type not in self._channels: self._channels [dependency_type] = self.request_resolver ( name=dependency_type, @@ -89,6 +104,9 @@ class EbuildDepRes ( object ): # --- end of get_channel (...) --- def _init_channels ( self ): + """Initializes the resolver channels, one for each existing + dependency type. Queues dependencies, too. + """ # collect dep strings and initialize resolver channels if self.request_resolver is None: @@ -125,6 +143,7 @@ class EbuildDepRes ( object ): # --- end of _init_channels (...) --- def _close_channels ( self ): + """Closes the resolver channels.""" if self._channels is None: return for channel in self._channels.values(): channel.close() @@ -132,6 +151,7 @@ class EbuildDepRes ( object ): # --- end of _close_channels (...) --- def _wait_resolve ( self ): + """Wait for dep resolution.""" # True if no channels for c in self._channels.values(): if c.satisfy_request() is None: @@ -140,6 +160,7 @@ class EbuildDepRes ( object ): # --- end of _wait_resolve (...) --- def _make_result ( self ): + """Make evars using the depres result.""" _result = list() for dep_type, channel in self._channels.items(): deplist = list ( filter ( None, channel.collect_dependencies() ) ) diff --git a/roverlay/ebuild/ebuilder.py b/roverlay/ebuild/ebuilder.py index 275c6d2..aa7d8f5 100644 --- a/roverlay/ebuild/ebuilder.py +++ b/roverlay/ebuild/ebuilder.py @@ -1,22 +1,31 @@ -# R Overlay -- ebuild creation, <?> +# R Overlay -- ebuild construction # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 class Ebuilder ( object ): + """Used to create ebuilds.""" def __init__ ( self ): self._evars = list() + # newlines \n will be inserted after an evar if the priority + # delta (current evar, next evar) is >= this value. + # <= 0 means newline after each statement + self.min_newline_distance = 20 def sort ( self ): - self._evars.sort ( key=lambda e: e.priority ) + """Sorts the content of the Ebuilder.""" + self._evars.sort ( key=lambda e: ( e.priority, e.name ) ) + #self._evars.sort ( key=lambda e: e.priority ) def get_lines ( self ): + """Creates and returns (ordered) text lines.""" + self.sort() last = len ( self._evars ) - 1 - newline = lambda i, k=1 : \ - abs ( self._evars [i + k].priority - self._evars [i].priority ) >= 20 - + newline = lambda i, k=1 : abs ( + self._evars [i + k].priority - self._evars [i].priority + ) >= self.min_newline_distance lines = list() for index, e in enumerate ( self._evars ): @@ -25,12 +34,17 @@ class Ebuilder ( object ): if index < last and newline ( index ): lines.append ( '' ) return lines + # --- end of get_lines (...) --- - def to_str ( self ): - return '\n'.join ( self.get_lines() ) + def to_str ( self ): return '\n'.join ( self.get_lines() ) __str__ = to_str def use ( self, *evar_list ): + """Adds evars to this Ebuilder. + + arguments: + * *evar_list -- + """ for e in evar_list: - self._evars.append ( e ) + if e is not None: self._evars.append ( e ) diff --git a/roverlay/ebuild/evars.py b/roverlay/ebuild/evars.py index 78a7326..da34c68 100644 --- a/roverlay/ebuild/evars.py +++ b/roverlay/ebuild/evars.py @@ -1,4 +1,4 @@ -# R Overlay -- ebuild creation, <?> +# R Overlay -- ebuild construction, ebuild variables # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -12,24 +12,40 @@ RSUGGESTS_NAME = "R_SUGGESTS" # ignoring case policies here (camel case,..) class DESCRIPTION ( EbuildVar ): - def __init__ ( self, description ): + """A DESCRIPTION="..." statement.""" + def __init__ ( self, description, maxlen=50 ): + """A DESCRIPTION="..." statement. Long values will be truncated. + + arguments: + * description -- description text + * maxlen -- maximum value length (defaults to 50 chars) + """ super ( DESCRIPTION, self ) . __init__ ( 'DESCRIPTION', description, 80 ) + self.maxlen = 50 if maxlen is None else maxlen def __str__ ( self ): return '%s%s="%s"' % ( self.indent, self.name, - shorten_str ( str ( self.value ) , 50, '... (see metadata)' ) + shorten_str ( str ( self.value ) , self.maxlen, '... (see metadata)' ) ) class SRC_URI ( EbuildVar ): + """A SRC_URI="..." statement.""" def __init__ ( self, src_uri ): super ( SRC_URI, self ) . __init__ ( 'SRC_URI', src_uri, 90 ) class IUSE ( EbuildVar ): + """An IUSE="..." statement.""" def __init__ ( self, use_flags=None, using_suggests=False ): + """An IUSE="..." statement. + + arguments: + * use_flags -- IUSE value + * using_suggests -- if True: enable R_Suggests USE flag + """ super ( IUSE, self ) . __init__ ( 'IUSE', ListValue ( use_flags, empty_value='${IUSE:-}' ), @@ -41,6 +57,7 @@ class IUSE ( EbuildVar ): class R_SUGGESTS ( EbuildVar ): + """A R_SUGGESTS="..." statement.""" def __init__ ( self, deps, **kw ): super ( R_SUGGESTS, self ) . __init__ ( RSUGGESTS_NAME, @@ -50,6 +67,7 @@ class R_SUGGESTS ( EbuildVar ): class DEPEND ( EbuildVar ): + """A DEPEND="..." statement.""" def __init__ ( self, deps, **kw ): super ( DEPEND, self ) . __init__ ( 'DEPEND', @@ -59,6 +77,7 @@ class DEPEND ( EbuildVar ): class RDEPEND ( EbuildVar ): + """A RDEPEND="..." statement.""" def __init__ ( self, deps, using_suggests=False, **kw ): super ( RDEPEND, self ) . __init__ ( 'RDEPEND', @@ -68,4 +87,5 @@ class RDEPEND ( EbuildVar ): if using_suggests: self.enable_suggests() def enable_suggests ( self ): + """Adds the optional R_SUGGESTS dependencies to RDEPEND.""" self.value.add ( '%s? ( ${%s} )' % ( IUSE_SUGGESTS, RSUGGESTS_NAME ) ) diff --git a/roverlay/manifest/helpers.py b/roverlay/manifest/helpers.py index 09f3296..5e2919c 100644 --- a/roverlay/manifest/helpers.py +++ b/roverlay/manifest/helpers.py @@ -77,8 +77,6 @@ class ExternalManifestCreation ( _ManifestCreation ): ) output = ebuild_call.communicate() - # necessary? (probably not, FIXME/TODO) - ebuild_call.wait() # log stdout? #for line in util.pipe_lines ( output [0] ): diff --git a/roverlay/metadata/__init__.py b/roverlay/metadata/__init__.py index 074cce3..8d94325 100644 --- a/roverlay/metadata/__init__.py +++ b/roverlay/metadata/__init__.py @@ -13,7 +13,6 @@ class MetadataJob ( object ): """Initializes a MetadataJob. arguments: - (((* package_info -- reserved for future usage))) * logger -- parent logger to use """ self.logger = logger.getChild ( 'metadata' ) diff --git a/roverlay/metadata/abstractnodes.py b/roverlay/metadata/abstractnodes.py index 50c9f56..f5a5c31 100644 --- a/roverlay/metadata/abstractnodes.py +++ b/roverlay/metadata/abstractnodes.py @@ -130,9 +130,9 @@ class MetadataNode ( _MetadataBasicNode ): def _nodelist ( self ): """Returns a list of strings representing the child nodes.""" - return list ( + return tuple ( filter ( - None, + lambda k: k is not None, [ node.to_str() for node in self.nodes if node.active() ] ), ) @@ -141,7 +141,6 @@ class MetadataNode ( _MetadataBasicNode ): def _nodestr ( self ): """Returns a string representing all child nodes.""" self._sort_nodes() - # todo filter only None? node_repr = self._nodelist() if len ( node_repr ): # add newlines before/after and indent after node_repr! diff --git a/roverlay/metadata/nodes.py b/roverlay/metadata/nodes.py index f35f8da..4d4d5fd 100644 --- a/roverlay/metadata/nodes.py +++ b/roverlay/metadata/nodes.py @@ -108,13 +108,12 @@ class DescriptionNode ( MetadataLeaf ): arguments: * description -- description text * is_long -- if this is a longdescription or a description node - * linewidth -- max text line width, TODO/FIXME: is this ignored? + * linewidth -- max text line width """ super ( DescriptionNode, self ) . __init__ ( 'longdescription' if is_long else 'description', value=description, ) - # self.value_format = "break lines after 80c, ..." if not linewidth is None and linewidth > 0: self.linewidth = linewidth @@ -163,9 +162,8 @@ class UseFlagListNode ( MetadataNode ): one UseFlag child node is active. """ # generator should stop after first True - # todo/fixme: could use super ( UseFlagListNode, self ).active() instead - # of self._enabled - return True in ( node.active() for node in self.nodes ) and self._enabled + return self._enabled and \ + True in ( node.active() for node in self.nodes ) # --- end of active (...) --- def _sort_nodes ( self ): diff --git a/roverlay/overlay/__init__.py b/roverlay/overlay/__init__.py index dadf998..0686ed8 100644 --- a/roverlay/overlay/__init__.py +++ b/roverlay/overlay/__init__.py @@ -1,4 +1,4 @@ -# R Overlay -- <comment TODO> +# R Overlay -- overlay module # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -119,16 +119,15 @@ class Overlay ( object ): def write ( self, **write_kw ): """Writes the overlay to its physical location (filesystem), including metadata and Manifest files. - TODO include Manifest generation in package.py arguments: * **write_kw -- ignored! (keywords for package.PackageDir.write(...)) returns: None (implicit) - raises: !! TODO + raises: IOError - TODO/FIXME/DOC: This is not thread-safe, it's expected to be called + ! TODO/FIXME/DOC: This is not thread-safe, it's expected to be called when ebuild creation is done. """ # writing profiles/ here, rewriting categories/ later @@ -244,7 +243,6 @@ class Overlay ( object ): def _write_usedesc ( self ): """Writes profiles/use.desc.""" - # TODO: config entry use_desc = config.get ( 'OVERLAY.use_desc', fallback_value=DEFAULT_USE_DESC @@ -278,7 +276,6 @@ class Overlay ( object ): except Exception as e: - #self.logger.exception ( e ) TODO try-catch blocks self.logger.critical ( "Cannot import eclass files!" ) raise # --- end of _import_eclass (...) --- @@ -293,7 +290,7 @@ class Overlay ( object ): raises: * Exception if no physical location assigned - * <TODO> passes IOError,... + * IOError """ if self.physical_location is None: raise Exception ( "no directory assigned." ) diff --git a/roverlay/overlay/category.py b/roverlay/overlay/category.py index 10e57c2..910f194 100644 --- a/roverlay/overlay/category.py +++ b/roverlay/overlay/category.py @@ -1,4 +1,4 @@ -# R Overlay -- <comment TODO> +# R Overlay -- overlay module, portage category # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -41,7 +41,6 @@ class Category ( object ): returns: None (implicit) """ - # TODO make keys available pkg_name = package_info ['name'] if not pkg_name in self._subdirs: diff --git a/roverlay/overlay/package.py b/roverlay/overlay/package.py index b571ad9..e77d4a2 100644 --- a/roverlay/overlay/package.py +++ b/roverlay/overlay/package.py @@ -1,4 +1,4 @@ -# R Overlay -- <comment TODO> +# R Overlay -- overlay module, package dir (subdir of category) # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 @@ -61,7 +61,9 @@ class PackageDir ( object ): returns: None (implicit) - raises: !! TODO + raises: + * Exception if no directory assigned + * IOError """ if self.physical_location is None: raise Exception ( "cannot write - no directory assigned!" ) @@ -98,7 +100,6 @@ class PackageDir ( object ): # chown 250.250 # this marks the package as 'written to fs' - # TODO update PackageInfo p_info.set_writeable() p_info ['ebuild_file'] = efile p_info.set_readonly() @@ -136,7 +137,8 @@ class PackageDir ( object ): returns: None (implicit) - raises: !! TODO + raises: + * IOError """ self._lock.acquire() self._regen_metadata() @@ -206,7 +208,6 @@ class PackageDir ( object ): raises: Exception when ebuild already exists. """ - # !! p info key TODO shortver = package_info ['ebuild_verstr'] def already_exists ( release=False ): @@ -254,8 +255,8 @@ class PackageDir ( object ): arguments: * skip_if_existent -- do not create if metadata already exist - * use_all_packages -- TODO - * use_old_metadata -- TODO + * use_all_packages -- TODO in metadata + * use_old_metadata -- TODO in metadata """ if use_old_metadata or use_all_packages: raise Exception ( "using >1 package for metadata.xml is TODO!" ) @@ -285,8 +286,9 @@ class PackageDir ( object ): returns: None (implicit) - raises: !! TODO + raises: * Exception if not physical + * Exception if no ebuild exists """ if self.physical_location is None: raise Exception ( "no directory assigned." ) diff --git a/roverlay/rpackage/descriptionfields.py b/roverlay/rpackage/descriptionfields.py index bccc3df..dcb0803 100644 --- a/roverlay/rpackage/descriptionfields.py +++ b/roverlay/rpackage/descriptionfields.py @@ -132,7 +132,9 @@ class DescriptionField ( object ): # --- end of set_default_value (...) --- def get_flags ( self ): - """Returns the flags of this DescriptionField or an empty list (=no flags).""" + """Returns the flags of this DescriptionField or + an empty list (=no flags). + """ return self.flags # --- end of get_flags (...) --- @@ -146,17 +148,19 @@ class DescriptionField ( object ): # --- end of get_allowed_values (...) --- def matches ( self, field_identifier ): - """Returns whether field_identifier equals the name of this DescriptionField. + """Returns whether field_identifier equals the name of this field. arguments: * field_identifier -- """ - return bool ( self.name == field_identifier ) if field_identifier else False - + if field_indentifier: + return bool ( self.name == field_identifier ) + else: + return False # --- end of matches (...) --- def matches_alias ( self, field_identifier ): - """Returns whether field_identifier equals any alias of this DescriptionField. + """Returns whether field_identifier equals any alias of this field. arguments: * field_identifier -- @@ -215,8 +219,8 @@ class DescriptionField ( object ): class DescriptionFields ( object ): - """DescriptionFields stores several instances of DescriptionField and provides - 'search in all' methods such as get_fields_with_flag (<flag>). + """DescriptionFields stores several instances of DescriptionField and + provides 'search in all' methods such as get_fields_with_flag (<flag>). """ def __init__ ( self ): @@ -266,8 +270,8 @@ class DescriptionFields ( object ): # --- end of get (...) --- def find_field ( self, field_name ): - """Determines the name of the DescriptionField to which field_name belongs - to. Returns the name of the matching field or None. + """Determines the name of the DescriptionField to which field_name + belongs to. Returns the name of the matching field or None. arguments: * field_name -- diff --git a/roverlay/rpackage/descriptionreader.py b/roverlay/rpackage/descriptionreader.py index e700907..c9daeb8 100644 --- a/roverlay/rpackage/descriptionreader.py +++ b/roverlay/rpackage/descriptionreader.py @@ -51,23 +51,29 @@ class DescriptionReader ( object ): # insert default values default_values = self.field_definition.get_fields_with_default_value() + for field_name in default_values.keys(): if not field_name in read_data: read_data [field_name] = default_values [field_name] # join values to a single string - for field_name in self.field_definition.get_fields_with_flag ( 'joinValues' ): - + for field_name in \ + self.field_definition.get_fields_with_flag ( 'joinValues' ) \ + : if field_name in read_data: read_data [field_name] = ' ' . join ( read_data [field_name] ) # ensure that all mandatory fields are set missing_fields = set () - for field_name in self.field_definition.get_fields_with_flag ( 'mandatory' ): + for field_name in \ + self.field_definition.get_fields_with_flag ( 'mandatory' ): + if field_name in read_data: - if read_data [field_name] is None or len ( read_data [field_name] ) < 1: + if read_data [field_name] is None or \ + len ( read_data [field_name] ) < 1 \ + : missing_fields.add ( field_name ) #else: ok else: @@ -77,10 +83,14 @@ class DescriptionReader ( object ): # check for fields that allow only certain values unsuitable_fields = set() - restricted_fields = self.field_definition.get_fields_with_allowed_values() + restricted_fields = \ + self.field_definition.get_fields_with_allowed_values() + for field_name in restricted_fields: if field_name in read_data: - if not self.field_definition.get ( field_name ).value_allowed ( read_data [field_name] ): + if not self.field_definition.get ( field_name ) . value_allowed ( + read_data [field_name] + ): unsuitable_fields.add ( field_name ) # summarize results @@ -88,16 +98,23 @@ class DescriptionReader ( object ): if not valid: self.logger.info ( "Cannot use R package" ) # name? if len ( missing_fields ): - self.logger.debug ( "The following mandatory description fields are missing: %s.", str ( missing_fields ) ) + self.logger.debug ( + "The following mandatory description fields are missing: %s." + % missing_fields + ) if len ( unsuitable_fields ): - self.logger.debug ( "The following fields have unsuitable values: %s.", str ( unsuitable_fields ) ) + self.logger.debug ( + "The following fields have unsuitable values: %s." + % unsuitable_fields + ) return valid # --- end of _parse_read_data (...) --- def run ( self ): - """Reads a DESCRIPTION file and returns the read data if successful, else None. + """Reads a DESCRIPTION file and returns the read data if successful, + else None. arguments: * file -- path to the tarball file (containing the description file) @@ -117,11 +134,12 @@ class DescriptionReader ( object ): """Extracts relevant data from value_str and returns them as list. arguments: - * value_str -- string that represents the (just read) values - * field_context -- field name the value belongs to; optional, defaults to None + * value_str -- string that represents the (just read) values + * field_context -- field name the value belongs to; + optional, defaults to None - It's useful to set field_context 'cause several fields ('Depends') have - multiple values arranged in a list (dep0, dep1 [, depK]*). + It's useful to set field_context 'cause several fields ('Depends') + have multiple values arranged in a list (dep0, dep1 [, depK]*). """ svalue_str = value_str.strip() @@ -134,20 +152,22 @@ class DescriptionReader ( object ): # default return if no context given return [ svalue_str ] - elif field_context in self.field_definition.get_fields_with_flag ( 'isList' ): - # split up this list (that is separated by commata and/or semicolons) - # *beware*/fixme: py3, filter returns filter object - return filter ( None, re.split ( - config.get ( 'DESCRIPTION.list_split_regex' ), - svalue_str, - 0 - ) ) - - elif field_context in self.field_definition.get_fields_with_flag ( 'isWhitespaceList' ): - # split up this list (that is separated whitespace) - return filter ( None, re.split ( '\s+', svalue_str, 0 ) ) - - + elif field_context in \ + self.field_definition.get_fields_with_flag ( 'isList' ) \ + : + # split up this list (separated by commata and/or semicolons) + # *beware*/fixme: py3, filter returns filter object + return filter ( None, re.split ( + config.get ( 'DESCRIPTION.list_split_regex' ), + svalue_str, + 0 + ) ) + + elif field_context in \ + self.field_definition.get_fields_with_flag ( 'isWhitespaceList' ) \ + : + # split up this list (separated by whitespace) + return filter ( None, re.split ( '\s+', svalue_str, 0 ) ) # default return return [ svalue_str ] @@ -160,15 +180,15 @@ class DescriptionReader ( object ): arguments: * filepath -- file to read (str; path to tarball or file) * pkg_name -- name of the package, in tarballs the description file - is located in <pkg_name>/ and thus this argument is required. - Defaults to '.', set to None to disable. + is located in <pkg_name>/ and thus this argument + is required. Defaults to '.', set to None to disable. All exceptions are passed to the caller (TarError, IOErr, <custom>). <filepath> can either be a tarball in which case the real DESCRIPTION file is read (<pkg_name>/DESCRIPTION) or a normal file. """ - self.logger.debug ( "Starting to read file '" + str ( filepath ) + "' ...\n" ) + self.logger.debug ( "Starting to read file '%s' ...\n" % filepath ) if not ( isinstance ( filepath, str ) and filepath ): raise Exception ( "bad usage" ) @@ -222,13 +242,15 @@ class DescriptionReader ( object ): field_context = None + comment_chars = config.get ( 'DESCRIPTION.comment_chars', '#' ) + for line in desc_lines: field_context_ref = None # using s(tripped)line whenever whitespace doesn't matter sline = line.lstrip() - if (not sline) or (line [0] == config.get ( 'DESCRIPTION.comment_char' ) ): + if not sline or line [0] in comment_chars: # empty line or comment pass @@ -248,15 +270,21 @@ class DescriptionReader ( object ): # line introduces a new field context, forget last one field_context = None - line_components = sline.partition ( config.get ( 'DESCRIPTION.field_separator' ) ) + line_components = sline.partition ( + config.get ( 'DESCRIPTION.field_separator' ) + ) if line_components [1]: # line contains a field separator, set field context - field_context_ref = self.field_definition.get ( line_components [0] ) + field_context_ref = self.field_definition.get ( + line_components [0] + ) if field_context_ref is None: # useless line, skip - self.logger.info ( "Skipped a description field: '%s'.", line_components [0] ) + self.logger.info ( + "Skipped a description field: '%s'.", line_components [0] + ) elif field_context_ref.has_flag ( 'ignore' ): # field ignored self.logger.debug ( "Ignored field '%s'.", field_context ) @@ -265,31 +293,38 @@ class DescriptionReader ( object ): field_context = field_context_ref.get_name() if not field_context: - raise Exception ( "Field name is not valid! This should've already been catched in DescriptionField..." ) + raise Exception ( + 'Field name is not valid! This should\'ve ' + 'already been catched in DescriptionField...' + ) # create a new empty list for this field_context read_data [field_context] = [] - # add values to read_data - # no need to check line_components [2] 'cause [1] was a true str - for val in make_values ( line_components [2], field_context ): + # add values to read_data, no need to check + # line_components [2] 'cause [1] was a true str + for val in \ + make_values ( line_components [2], field_context ) \ + : read_data [field_context] . append ( val ) - - else: # reaching this branch means that # (a) line has no leading whitespace # (b) line has no separator (:) # this should not occur in description files (bad syntax?) - self.logger.warning ( "Unexpected line in description file: '%s'.", line_components [0] ) + self.logger.warning ( + "Unexpected line in description file: '%s'." + % line_components [0] + ) # -- end for -- if self._parse_read_data ( read_data ): - self.logger.debug ( "Successfully read file '%s' with data = %s.", - self.fileinfo ['package_file'], str ( read_data ) - ) + self.logger.debug ( + "Successfully read file '%s' with data = %s." + % ( self.fileinfo ['package_file'], read_data ) + ) self.desc_data = read_data # get_desc() is preferred, but this method returns the desc data, too |