From 09dca3f1c3677a834841c1d2c9e2ac40e54459b2 Mon Sep 17 00:00:00 2001 From: André Erdmann Date: Fri, 15 Jun 2012 22:21:26 +0200 Subject: metadata: comments/fixes/enhancements modified: roverlay/portage/metadata/abstractnodes.py modified: roverlay/portage/metadata/creation.py modified: roverlay/portage/metadata/nodes.py --- roverlay/portage/metadata/abstractnodes.py | 92 ++++++++++++++++++++++++++++-- roverlay/portage/metadata/creation.py | 21 ++++++- roverlay/portage/metadata/nodes.py | 83 +++++++++++++++++++++++++-- 3 files changed, 182 insertions(+), 14 deletions(-) diff --git a/roverlay/portage/metadata/abstractnodes.py b/roverlay/portage/metadata/abstractnodes.py index 487d26d..50c9f56 100644 --- a/roverlay/portage/metadata/abstractnodes.py +++ b/roverlay/portage/metadata/abstractnodes.py @@ -10,19 +10,37 @@ get_indent = lambda k : k * INDENT # -- "abstract" metadata nodes -- class _MetadataBasicNode ( object ): + """ + This is the most basic metadata node that should never be used directly. + """ def __init__ ( self, name, flags ): + """Initializes a _MetadataBasicNode. + + arguments: + * name -- name of this node, e.g. 'flag' + * flags -- flags of this node, e.g. 'name=byte-compile' + """ self.name = name self.flags = flags + # priority is used to sort nodes (e.g. longdescription after description) self.priority = 1000 self._enabled = True self._set_level ( 0 ) # --- end of __init__ (...) --- def active ( self ): + """Returns True if this node is active.""" return self._enabled + # --- end of active (...) --- def _set_level ( self, _level, has_indent=True ): + """Sets the level (depth) of this node. + + arguments: + * _level -- level to set + * has_indent -- if this node should indent its subnodes (or text) + """ self.level = _level if has_indent: self.indent = get_indent ( self.level ) @@ -31,14 +49,25 @@ class _MetadataBasicNode ( object ): # --- end of _set_level (...) --- def set_flag ( self, flagname, flagvalue=None ): + """Sets the specified flag. + + arguments: + * flagname -- flag name + * flagvalue -- flag value, defaults to None->'' + """ self.flags [flagname] = '' if flagvalue is None else flagvalue # --- end of set_flag (...) --- def _flaglist ( self ): - return [ '%s="%s"' % ftup for ftup in self.flags.items() ] + """Returns a "flagname=flagvalue" list.""" + return [ '%s="%s"' % ftup for ftup in self.flags.items() ] # --- end of _flaglist (...) --- + def _flagstr ( self ): + """Returns the string representation of this node's flags, including + a leading whitespace char. + """ if self.flags is None: return '' @@ -51,12 +80,17 @@ class _MetadataBasicNode ( object ): # --- end of _flagstr (...) --- def _do_verify ( self ): + """Verifies this node. + Does nothing if self._verify is not implemented, else dies on error. + """ if hasattr ( self, '_verify' ) and not self._verify(): # todo, verify could return ( Status, ErrorMessages ) etc. raise Exception ( "verification failed for a metadata node." ) + # --- end of _do_verify (...) --- - # not using __repr__, make (recursive) node calls explicit + # not using __str__, make (recursive) node calls explicit def to_str ( self ): + """Returns a string representing this node.""" self._do_verify() return "%s<%s%s>" % ( @@ -65,9 +99,11 @@ class _MetadataBasicNode ( object ): self._flagstr(), self.name ) + # --- end of to_str (...) --- class MetadataNode ( _MetadataBasicNode ): + """A _MetadataBasicNode with child nodes.""" def __init__ ( self, name, flags=dict() ): super ( MetadataNode, self ) . __init__ ( name, flags ) @@ -75,15 +111,25 @@ class MetadataNode ( _MetadataBasicNode ): # --- end of __init__ (...) --- def add ( self, node ): + """Adds a child node to this node. Fixes/sets the level of this node. + + arguments: + * node -- + """ node._set_level ( self.level + 1 ) self.nodes.append ( node ) + # --- end of add (...) --- + # copy add to _add_node _add_node = add def _sort_nodes ( self ): + """Sorts the child nodes of this node.""" self.nodes.sort ( key=lambda node : node.priority ) + # --- end of _sort_nodes (...) --- def _nodelist ( self ): + """Returns a list of strings representing the child nodes.""" return list ( filter ( None, @@ -93,16 +139,19 @@ class MetadataNode ( _MetadataBasicNode ): # --- end of _nodelist (...) --- 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! return "\n%s\n%s" % ( '\n'.join ( node_repr ), self.indent ) else: return '' # --- end of _nodestr (...) --- def to_str ( self ): + """Returns a string representing this node and all of its child nodes.""" self._do_verify() return "%s<%s%s>%s" % ( self.indent, @@ -142,10 +191,17 @@ class MetadataLeaf ( _MetadataBasicNode ): self._text_wrapper.subsequent_indent = self.text_indent def _value_str ( self ): + """Returns the value string. Derived classes may override this.""" #if self.value_format == ?: format value ~ - return self.value + return str ( self.value ) + # --- end of _value_str (...) --- def _pretty_value_str ( self ): + """Returns a formatted value string (max line length etc.). + Not used here, but subclasses can use it by simply writing + '_value_str = MetadataLeaf._pretty_value_str' in the class body. + """ + # FIXME/TODO: could move this func to util if not self.value: return "" if self._text_wrapper is None: @@ -160,14 +216,15 @@ class MetadataLeaf ( _MetadataBasicNode ): # why? return "" elif len ( val_lines ) == 1: + # single line, no indent/newline return val_lines [0] else: + # add newline before/after, add indent after val_lines [0] = '\n' + self.text_indent + val_lines [0] val_lines.append ( self.indent ) return '\n'.join ( val_lines ) # --- end of _pretty_value_str (...) --- - def to_str ( self ): self._do_verify() if self.print_node_name: @@ -181,7 +238,7 @@ class MetadataLeaf ( _MetadataBasicNode ): else: # not very useful, but allows to insert strings as nodes return self.indent + self._value_str() - + # --- end of to_str (...) --- class MetadataNodeNamedAccess ( MetadataNode ): """A metadata node that offers key-based (dictionary) access to some of @@ -189,16 +246,39 @@ class MetadataNodeNamedAccess ( MetadataNode ): def __init__ ( self, name, flags=dict() ): super ( MetadataNodeNamedAccess, self ) . __init__ ( name, flags ) + # the access dict self.node_dict = dict() def add ( self, node, with_dict_entry=True, fail_if_existent=True ): - """comment TODO; overwrites old dict entries!""" + """Adds a child node. + + arguments: + * node -- node to add + * with_dict_entry -- add node to the access dict, defaults to True + * fail_if_existent -- fail if node's name already in the access dict, + defaults to True + """ + super ( MetadataNodeNamedAccess, self ) . add ( node ) if with_dict_entry: if fail_if_existent and node.name in self.node_dict: raise Exception ( "key exists." ) else: self.node_dict [node.name] = node + # --- end of add (...) --- def get ( self, node_name ): + """Returns node by name. + + arguments: + * node_name + + raises: KeyError if node_name not in the access dict + """ return self.node_dict [node_name] + # --- end of get (...) --- + + def has_named ( self, node_name ): + """Returns True if node_name in the access dict else False.""" + return node_name in self.node_dict + # --- end of has_named (...) --- diff --git a/roverlay/portage/metadata/creation.py b/roverlay/portage/metadata/creation.py index d582d9e..d2f133c 100644 --- a/roverlay/portage/metadata/creation.py +++ b/roverlay/portage/metadata/creation.py @@ -7,8 +7,15 @@ import roverlay.config from roverlay.portage.metadata import nodes class MetadataJob ( object ): + """R package description data -> metadata.xml interface.""" def __init__ ( self, package_info, logger ): + """Initializes a MetadataJob. + + arguments: + * package_info -- reserved for future usage + * logger -- logger to use (this instance won't call getChild) + """ self.logger = logger self._metadata = nodes.MetadataRoot() # reserved for future usage ("dominant ebuilds": when ebuildjobs @@ -16,7 +23,7 @@ class MetadataJob ( object ): self.package_info = None # --- end of __init__ (...) --- - def update_metadata ( self, desc_data, package_info ): + def update ( self, desc_data, package_info ): """Updates the metadata using the given description data. It's expected that this method is called when Ebuild creation is done. @@ -31,7 +38,7 @@ class MetadataJob ( object ): mref = self._metadata - max_textline_width = config.get ( 'METADATA.linewidth', 25 ) + max_textline_width = roverlay.config.get ( 'METADATA.linewidth', 65 ) have_desc = False @@ -53,7 +60,15 @@ class MetadataJob ( object ): ) ) have_desc = True - # --- end of update_metadata (...) --- + mref.add_useflag ( 'byte-compile', 'enable byte-compiling' ) + + if package_info ['has_suggests']: + mref.add_useflag ( 'R_suggests', 'install optional dependencies' ) + + # --- end of update (...) --- + + # used in some test scripts + update_metadata = update def write ( self, _file ): """Writes the metadata into a file. diff --git a/roverlay/portage/metadata/nodes.py b/roverlay/portage/metadata/nodes.py index 7c3b890..36bf22d 100644 --- a/roverlay/portage/metadata/nodes.py +++ b/roverlay/portage/metadata/nodes.py @@ -2,8 +2,7 @@ # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 -# -- concrete metadata nodes -- - +# import abstract nodes from roverlay.portage.metadata.abstractnodes import \ MetadataNode, MetadataNodeNamedAccess, MetadataLeaf @@ -13,21 +12,60 @@ class MetadataRoot ( MetadataNodeNamedAccess ): Intended usage is metadata file creation. """ + # the common metadata.xml header HEADER = '\n'.join ( [ '', '' ] ) + def __init__ ( self ): super ( MetadataRoot, self ) . __init__ ( 'pkgmetadata' ) self.priority = 0 + # --- end of __init__ (...) --- def empty ( self ): + """Returns True if this node has no child nodes.""" #return 0 == len ( self.nodes ) or \ # True in ( node.empty() for node in self.nodes ) return 0 == len ( self.nodes ) + # --- end of empty (...) --- + + def add_useflag ( self, flag_name, flag_description ): + """Adds a USE Flag to the metadata. + A UseFlagListNode 'use' will be created if required and a new UseFlagNode + will then be created an added to 'use'. + + arguments: + * flag_name -- see UseFlagNode.__init__ + * flag_description -- see UseFlagNode.__init__ + + returns: the created UseFlagNode for further editing + """ + if not self.has_named ( 'use' ): + # passing fail_if_existent, this node shouldn't be used in parallel + self.add ( + UseFlagListNode(), + with_dict_entry=True, fail_if_existent=True + ) + + node = self.get ( 'use' ) + use_node = UseFlagNode ( flag_name, flag_description ) + node.add ( use_node ) + + return use_node + # --- end of add_useflag (...) --- def write_file ( self, _file ): + """Writes the metadata to a file. + + arguments: + * _file -- either a File object or a string + + returns: success True/False + + raises: *passes IOError + """ to_write = self.to_str() own_fh = False @@ -62,7 +100,16 @@ class MetadataRoot ( MetadataNodeNamedAccess ): class DescriptionNode ( MetadataLeaf ): + """A description (, ) node.""" + def __init__ ( self, description, is_long=False, linewidth=None ): + """Initializes a DescriptionNode. + + 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? + """ super ( DescriptionNode, self ) . __init__ ( 'longdescription' if is_long else 'description', value=description, @@ -73,11 +120,21 @@ class DescriptionNode ( MetadataLeaf ): self.linewidth = linewidth self.priority = 150 if is_long else 149 + # --- end of __init__ (...) --- + # using value formatting _value_str = MetadataLeaf._pretty_value_str + class UseFlagNode ( MetadataLeaf ): + """A USE Flag node, this flag does...""" def __init__ ( self, flag_name, flag_description ): + """Initializes an USE Flag node. + + arguments: + * flag_name -- name of the use flag + * flag_description -- flag description + """ super ( UseFlagNode, self ) . __init__ ( 'flag', flags=dict ( name = flag_name ), @@ -85,12 +142,21 @@ class UseFlagNode ( MetadataLeaf ): ) # priority shouldn't be used for this node self.priority = -1 + # --- end of __init__ (...) --- class UseFlagListNode ( MetadataNode ): + """A USE Flag list node, ....""" + def __init__ ( self, flags=dict() ): + """Initializes an USE Flag list node. + + arguments: + * flags -- optional + """ super ( UseFlagListNode, self ) . __init__ ( 'use', flags=flags ) self.priority = 850 + # --- end of __init__ (...) --- def active ( self ): """The UseFlag list is only active if it is enabled and at least @@ -100,21 +166,28 @@ class UseFlagListNode ( MetadataNode ): # 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 - + # --- end of active (...) --- def _sort_nodes ( self ): """UseFlags are sorted by lowercase flag name, not priority.""" self.nodes.sort ( key=lambda node : node.flags ['name'].lower() ) + # --- end of _sort_nodes (...) --- def add ( self, node ): + """Adds a child node only if it is a UseFlagNode. + + arguments: + * node -- + """ if isinstance ( node, UseFlagNode ): super ( UseFlagListNode, self ) . add ( node ) else: raise Exception ( "UseFlagListNode accepts UseFlagNodes only." ) - - + # --- end of add (...) --- class NopNode ( MetadataNode ): + """This node is meant for testing only.""" def __init__ ( self ): super ( NopNode, self ) . __init__ ( 'nop', flags=dict() ) + # --- end of __init__ (...) --- -- cgit v1.2.3-65-gdbad