From e0c44a29537eff743d03e520966f4e6c2ecb5486 Mon Sep 17 00:00:00 2001 From: André Erdmann Date: Wed, 20 Jun 2012 20:53:38 +0200 Subject: ebuild creation * using simpler/easier ebuild creation now * ebuild variables are now automatically sorted * ebuild is now a string, not an object * the common ebuild header is no longer stored in every ebuild, the overlay module handles this modified: roverlay/ebuild/__init__.py new file: roverlay/ebuild/abstractcomponents.py deleted: roverlay/ebuild/construction.py modified: roverlay/ebuild/creation.py new file: roverlay/ebuild/depres.py new file: roverlay/ebuild/ebuilder.py new file: roverlay/ebuild/evars.py --- roverlay/ebuild/__init__.py | 39 ---- roverlay/ebuild/abstractcomponents.py | 93 ++++++++++ roverlay/ebuild/construction.py | 333 ---------------------------------- roverlay/ebuild/creation.py | 237 ++++++++---------------- roverlay/ebuild/depres.py | 167 +++++++++++++++++ roverlay/ebuild/ebuilder.py | 36 ++++ roverlay/ebuild/evars.py | 70 +++++++ 7 files changed, 445 insertions(+), 530 deletions(-) create mode 100644 roverlay/ebuild/abstractcomponents.py delete mode 100644 roverlay/ebuild/construction.py create mode 100644 roverlay/ebuild/depres.py create mode 100644 roverlay/ebuild/ebuilder.py create mode 100644 roverlay/ebuild/evars.py diff --git a/roverlay/ebuild/__init__.py b/roverlay/ebuild/__init__.py index 17e9a8d..e69de29 100644 --- a/roverlay/ebuild/__init__.py +++ b/roverlay/ebuild/__init__.py @@ -1,39 +0,0 @@ -# R Overlay -- ebuild creation, ebuild class -# Copyright 2006-2012 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -class Ebuild ( object ): - - def __init__ ( self, content, header=None ): - """Initializes an Ebuild that has text content and optionally a - header (text, too). - - arguments: - * content -- - * header -- - """ - self.content = content - self.header = header - # --- end of __init__ (...) --- - - def write ( self, fh, header=None, header_is_fallback=False ): - """Write the ebuild into a file-like object. - - arguments: - * fh -- file handle - """ - if not self.content: - raise Exception ( "ebuild is empty!" ) - - header_order = ( self.header, header ) if header_is_fallback \ - else ( header, self.header ) - - for h in header_order: - if not h is None: - fh.write ( h ) - fh.write ( '\n\n' ) - break - - fh.write ( self.content ) - fh.write ( '\n' ) - # --- end of write_fh (...) --- diff --git a/roverlay/ebuild/abstractcomponents.py b/roverlay/ebuild/abstractcomponents.py new file mode 100644 index 0000000..73dac03 --- /dev/null +++ b/roverlay/ebuild/abstractcomponents.py @@ -0,0 +1,93 @@ +# R Overlay -- ebuild creation, +# Copyright 2006-2012 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +INDENT = '\t' + +def listlike ( ref ): + return hasattr ( ref, '__iter__' ) and not isinstance ( ref, str ) + + +class ListValue ( object ): + def __init__ ( self, value, indent_level=1, empty_value=None ): + self.set_level ( indent_level ) + + self.empty_value = empty_value + + + self.single_line = False + self.indent_lines = True + # only used in multi line mode + self.append_indented_newline = True + + self.val_join = ' ' + + self.set_value ( value ) + + + def __len__ ( self ): + l = len ( self.value ) + return l if self.empty_value is None else l - 1 + + def set_level ( self, level ): + self.level = level + self.var_indent = (level - 1) * INDENT + self.val_indent = level * INDENT + self.line_join = '\n' + self.val_indent + # --- end of set_level (...) --- + + def set_value ( self, value ): + self.value = list() + if self.empty_value is not None: + self.value.append ( self.empty_value ) + self.add_value ( value ) + # --- end of set_value (...) --- + + def add_value ( self, value ): + if value is None: + pass + elif listlike ( value ): + self.value.extend ( value ) + else: + self.value.append ( value ) + # --- end of add_value (...) --- + + add = add_value + + def to_str ( self ): + if len ( self.value ) == 0: + ret = "" + elif len ( self.value ) == 1: + ret = str ( self.value [0] ) + elif self.single_line: + ret = self.val_join.join ( self.value ) + else: + ret = self.line_join.join ( ( self.value ) ) + if self.append_indented_newline: + ret += self.var_indent + '\n' + + return ret + # --- end of to_str (...) --- + + __str__ = to_str + + +class EbuildVar ( object ): + + def __init__ ( self, name, value, priority ): + self.name = name + self.priority = priority + self.value = value + self.set_level ( 0 ) + + def set_level ( self, 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 __str__ ( self ): + return '%s%s="%s"' % ( self.indent, self.name, self.value ) diff --git a/roverlay/ebuild/construction.py b/roverlay/ebuild/construction.py deleted file mode 100644 index 3e858a0..0000000 --- a/roverlay/ebuild/construction.py +++ /dev/null @@ -1,333 +0,0 @@ -# R Overlay -- ebuild creation, ebuild class -# Copyright 2006-2012 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -import copy - -import roverlay.config - -from roverlay.util import shorten_str -from roverlay.ebuild import Ebuild - -EBUILD_INDENT = roverlay.config.get ( 'EBUILD.indent', '\t' ) - -ADD_REMAP = { - # pkg vs package - 'package_name' : 'pkg_name', - 'package_version' : 'pkg_version', - 'package_revision' : 'pkg_revision', - # TITLE is in DESCRIPTION - 'TITLE' : 'DESCRIPTION', - - # TODO: remove these entries by fixing ebuildcreator/ebuildjob - 'DEPENDS' : 'DEPEND', - 'RDEPENDS' : 'RDEPEND', - 'RSUGGESTS' : 'R_SUGGESTS', -} - -IUSE_SUGGESTS = "R_suggests" - - -class EbuildConstruction ( object ): - """Class that helps to create Ebuild objects.""" - - - - def __init__ ( self, logger ): - """Initializes an EbuildConstruction object. - - arguments: - * logger -- - """ - self.logger = logger - - self.has_rsuggests = False - - # elements in data are either a str or a list of str - self._data = dict () - # --- end of __init__ (...) --- - - def get_ebuild ( self ): - """Creates and returns an Ebuild.""" - lines = '\n'.join ( self._make_ebuild_lines() ) - return Ebuild ( lines, header=None ) - # --- end of get_ebuild (...) --- - - def add ( self, key, value, append=True ): - """Adds data. - - arguments: - * key -- identifier of the data (e.g. DEPEND). - May be remapped (e.g. merging 'Title' and 'Description') - or even refused here. - * value -- - * append -- whether to append values or overwrite existing ones, - defaults to True. - - returns: None (implicit) - """ - if self._data is None: - # -- todo - raise Exception ("Ebuild is readonly.") - - _key = ADD_REMAP [key] if key in ADD_REMAP else key - - if _key is None: - self.logger.debug ( "add (%s, %s): filtered key.", key, value ) - else: - if append and _key in self._data: - if not isinstance ( self._data [_key], list ): - self._data [_key] = [ self._data [_key] ] - - if isinstance ( value, list ): - self._data [_key].extend ( value ) - else: - self._data [_key].append ( value ) - - else: - self._data [_key] = value - - # --- end of add (...) --- - - def _make_ebuild_lines ( self ): - """Creates text lines for the Ebuild. - It assumes that enough data to do this are available. - Exceptions (KeyError, NameError, ...) are passed if that's not the case. - """ - - def get_dep_and_use(): - """Creates values for the DEPEND, RDEPEND, IUSE and, if possible, - R_SUGGESTS variables and returns them as dict { VARNAME -> VALUE }. - """ - - # have suggests if they're set and not empty - self.has_rsuggests = bool ( - 'R_SUGGESTS' in self._data and self._data ['R_SUGGESTS'] - ) - - # set defaults: inherit eclass + include depend in rdepend - # TODO: is ${DEPEND:-},... necessary? - ret = dict ( - DEPEND = [ '${DEPEND:-}' ], - # assuming that the eclass includes it's DEPEND in RDEPEND - RDEPEND = [ '${RDEPEND:-}' ], - IUSE = [ '${IUSE:-}' ], - ) - - for kw in ( x for x in ( 'DEPEND', 'RDEPEND' ) if x in self._data ): - if isinstance ( self._data [kw], list ): - ret [kw].extend ( self._data [kw] ) - else: - ret [kw].append ( self._data [kw] ) - - - if self.has_rsuggests: - ret ['R_SUGGESTS'] = self._data ['R_SUGGESTS'] - - # +R_SUGGESTS, -R_SUGGESTS? - ret ['IUSE'].append ( IUSE_SUGGESTS ) - # do these braces help or confuse? TODO FIXME - ret ['RDEPEND'].append ( '%s? ( ${R_SUGGESTS} )' % IUSE_SUGGESTS ) - - return ret - - # --- end of get_dep_and_use () --- - - def make_var ( - varname, - value=None, oneline_list=True, indent_list=True, indent_level=0 - ): - """Creates a = statement for ebuilds. - - arguments: - * varname -- name of the variable - * value -- value of the variable. - This has to be either None (the default), str, - or list of str. - * oneline_list -- if value is a list: controls whether its components - should be put into one line (True) or multiple. - Defaults to True. - * indent_list -- if value is a list and not oneline_list: - controls whether each value line should be - indentend (by indent_level + 1) or not ("by 0"). - Defaults to True. - * indent_level -- current indentation level, defaults to 0 - - """ - - # assumption: value is either None, - # scalar with str representation or list of str - var_value = None - - if not value: - var_value = "" - - elif isinstance ( value, list ): - if oneline_list: - var_value = ' '.join ( value ) - elif indent_list: - var_value = ( - '\n' + (indent_level + 1) * EBUILD_INDENT - ).join ( value ) - else: - '\n'.join ( value ) - - else: - var_value = str ( value ) - - - # (TODO) - # fixing ebuild var values here - - # cut DESCRIPTION line if too long - if varname == 'DESCRIPTION': - var_value = shorten_str ( var_value, 45, '... (see metadata)' ) - - - ret ='%s%s="%s"' % ( - indent_level * EBUILD_INDENT, - varname, - var_value - ) - - # (TODO) - # fixing ebuild var lines here - - return ret - - # --- end of make_var (...) --- - - def remove_newlines ( line_list ): - """Removes leading, ending and repeated blank lines in line_list. - - arguments: - * line_list -- - - returns: filtered lines - - TODO: check if a filter function could be used for this - """ - lines = [] - line = None - last_line_empty = True - - for line in line_list: - line = line.rstrip() - # re.sub \n{2,} \n :: FIXME? - - if line: - last_line_empty = False - elif not last_line_empty: - last_line_empty = True - else: - continue - - lines.append ( line ) - - # remove last line if empty - ##if last_line_empty: (?) - if len ( lines ) and not lines [-1]: - del lines [-1] - - return lines - - # --- end of remove_newlines (...) --- - - def add_easyvar ( - ebuild_content, varname, - value_key=None, add_newline=False - ): - """Adds a 'simple' variable to the ebuild lines. - This means that it can directly be taken from self._data [value_key]. - This method assumes that value_key exists in self._data, - any exceptions (KeyError) will be passed. - - arguments: - * ebuild_content -- list of ebuild text lines, will be modified - directly, so copy it before calling addvar if - you need the original list. - * varname -- name of the variable. - Nothing happens if this is None. - * value_key -- key of the value, - defaults to varname if it is None - * add_newline -- adds a newline after the var statement, - defaults to False - - returns: given+modified list (ebuild_content) - """ - - if not varname is None: - if value_key is None: - ebuild_content.append ( - make_var ( varname, self._data [varname] ) - ) - else: - ebuild_content.append ( - make_var ( varname, self._data [value_key] ) - ) - - if add_newline: - ebuild_content.append ( "" ) - - return ebuild_content - - # --- end of add_easyvar (...) --- - - # -- actual start of _make_ebuild_lines (...) -- - try: - ebuild_lines = [] - - #if 'ebuild_header' in self._data: - # ebuild_lines = copy.copy ( self._data ['ebuild_header'] ) - # ebuild_lines.append ( "" ) - - #add_easyvar ( ebuild_lines, "PKG_FILE" ) - #if 'PKG_ORIGIN' in self._data: - # add_easyvar ( ebuild_lines, "PKG_ORIGIN", None, False ) - - ebuild_lines.append ( "" ) - - # TODO/FIXME: this makes DESCRIPTION mandatory, maybe check with - # >if 'DESCRIPTION' in self._data< - add_easyvar ( ebuild_lines, "DESCRIPTION" ) - - add_easyvar ( ebuild_lines, "SRC_URI", add_newline=True ) - - # FIXME/TODO: LICENSE? - - dep_and_use = get_dep_and_use () - - # check that IUSE has more than one element, - # don't write IUSE="${IUSE:-}" etc. - if len ( dep_and_use ['IUSE'] ) > 1: - ebuild_lines.append ( - make_var ( "IUSE", dep_and_use ['IUSE'], True ) - ) - - if 'R_SUGGESTS' in dep_and_use: - ebuild_lines.append ( - make_var ( "R_SUGGESTS", dep_and_use ['R_SUGGESTS'], False ) - ) - - # see IUSE - if len ( dep_and_use ['DEPEND'] ) > 1: - ebuild_lines.append ( - make_var ( "DEPEND", dep_and_use ['DEPEND'], False ) - ) - - # see IUSE - if len ( dep_and_use ['RDEPEND'] ) > 1: - ebuild_lines.append ( - make_var ( "RDEPEND", dep_and_use ['RDEPEND'], False ) - ) - - del dep_and_use - return remove_newlines ( ebuild_lines ) - - except ( ValueError, KeyError, NameError ) as err: - #self.logger.exception ( err ) - self.logger.error ( "Cannot create ebuild text lines." ) - #return None - raise - - # --- end of make_ebuild_lines (...) --- diff --git a/roverlay/ebuild/creation.py b/roverlay/ebuild/creation.py index 5fa91ac..d202d78 100644 --- a/roverlay/ebuild/creation.py +++ b/roverlay/ebuild/creation.py @@ -1,34 +1,25 @@ -# R Overlay -- ebuild creation, "job" module +# R Overlay -- ebuild creation, # Copyright 2006-2012 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 import logging -import roverlay.static.depres +from roverlay.ebuild import depres, ebuilder, evars -from roverlay.ebuild.construction import EbuildConstruction +#from roverlay.ebuild.construction import EbuildConstruction from roverlay.rpackage.descriptionreader import DescriptionReader -# move this to const / config -DEPENDENCY_FIELDS = { - 'R_SUGGESTS' : [ 'Suggests' ], - 'DEPENDS' : [ 'Depends', 'Imports' ], - 'RDEPENDS' : [ 'LinkingTo', 'SystemRequirements' ] -} LOGGER = logging.getLogger ( 'EbuildCreation' ) + class EbuildCreation ( object ): - def __init__ ( self, package_info, depres_channel_spawner=None ): + def __init__ ( self, package_info ): - self.logger = LOGGER.getChild ( package_info ['name'] ) self.package_info = package_info - if depres_channel_spawner is None: - self.request_resolver = roverlay.static.depres.get_ebuild_channel - else: - self.request_resolver = depres_channel_spawner + self.logger = LOGGER.getChild ( package_info ['name'] ) # > 0 busy/working; 0 == done,success; < 0 done,fail self.status = 1 @@ -36,100 +27,51 @@ class EbuildCreation ( object ): self.package_info.set_readonly() # --- end of __init__ (...) --- - def done() : return self.status < 1 - def busy() : return self.status > 0 - def success() : return self.status == 0 - def fail() : return self.status < 0 + def done ( self ) : return self.status < 1 + def busy ( self ) : return self.status > 0 + def success ( self ) : return self.status == 0 + def fail ( self ) : return self.status < 0 + + def run ( self ): + if self.status < 1: + raise Exception ( "Cannot run again." ) + + try: + self._lazyimport_desc_data() + + self.package_info.set_readonly() + + if self._make_ebuild(): + self.logger.debug ( "Ebuild is ready." ) + self.status = 0 + else: + self.logger.info ( "Cannot create an ebuild for this package." ) + self.status = -1 + + except Exception as e: + # log this and set status to fail + self.status = -10 + self.logger.exception ( e ) + # --- end of run (...) --- + def _lazyimport_desc_data ( self ): + if self.package_info.get ( 'desc_data', + fallback_value=None, do_fallback=True ) is None: - def _resolve_dependencies ( self, ebuilder ): - if self.request_resolver is None: - self.logger.warning ( - "Cannot resolve dependencies, no resolver available!" + logging.warning ( 'Reading description data now.' ) + reader = DescriptionReader ( + self.package_info, + logger=self.logger, + read_now=True + ) + self.package_info.set_writeable() + self.package_info.update ( + desc_data=reader.get_desc ( run_if_unset=False ) ) - return True - - res = None - # -- end pre func block -- - - def init_channels(): - # collect dep strings and initialize resolver channels - desc = self.package_info ['desc_data'] - channels = dict() - - def get_resolver ( dependency_type ): - if dependency_type not in channels: - channels [dependency_type] = self.request_resolver ( - dependency_type, - self.logger - ) - return channels [dependency_type] - # --- end of get_resolver (...) --- - - dep_type = desc_field = None - - for dep_type in DEPENDENCY_FIELDS: - resolver = None - - for desc_field in DEPENDENCY_FIELDS [dep_type]: - if desc_field in desc: - if not resolver: - resolver = get_resolver ( dep_type ) - - if isinstance ( desc [desc_field], str ): - resolver.add_dependency ( desc [desc_field] ) - elif hasattr ( desc [desc_field], '__iter__' ): - resolver.add_dependencies ( desc [desc_field] ) - else: - logger.warning ( - "Cannot add dependency '%s'." % desc [desc_field] - ) - # -- if desc_field - # -- for desc_field - # -- for dep_type - return channels - # --- end of init_resolvers (...) --- - - def try_resolve(): - for r in res.values(): - if r.satisfy_request() is None: - return False - return True - # --- end of try_resolve (...) --- - - # TODO - # replace try_resolve with - # False in ( r.satisfy_request() for r in res.values() ) - # ? - res = init_channels() - if not res: return True - success = False - - - if try_resolve(): - for dep_type, resolver in res.items(): - deplist = list ( filter ( None, resolver.collect_dependencies() ) ) - - if deplist is None: - ## FIXME: false positive: "empty" channel - raise Exception ( - 'dep_resolver is broken: ' - 'lookup() returns None but satisfy_request() says ok.' - ) - elif hasattr ( deplist, '__iter__' ): - # add dependencies in no_append/override mode - self.logger.debug ( "adding %s to %s", deplist, dep_type ) - ebuilder.add ( dep_type, deplist, False ) - else: - raise Exception ( "dep_resolver is broken: iterable expected!" ) - # -- for dep_type,.. - - success = True - - # tell the dep resolver channels that we're done - for r in res.values(): r.close() - return success - # --- end of resolve_dependencies (...) --- + del reader + + # --- end of _lazyimport_desc_data (...) --- + def _make_ebuild ( self ): desc = self.package_info ['desc_data'] @@ -137,69 +79,48 @@ class EbuildCreation ( object ): self.logger ( 'desc empty- cannot create an ebuild for this package.' ) - return None + return False + + ebuild = ebuilder.Ebuilder() + + _dep_resolution = depres.EbuildDepRes ( + self.package_info, self.logger, + create_iuse=True, run_now=True + ) + + if not _dep_resolution.success(): + # log here? + return False + - ebuilder = EbuildConstruction ( self.logger ) + dep_result = _dep_resolution.get_result() - have_desc = False + # add *DEPEND, IUSE to the ebuild + ebuild.use ( *dep_result [1] ) + + description = None if 'Title' in desc: - ebuilder.add ( 'DESCRIPTION', desc ['Title'] ) - have_desc = True + description = desc ['Title'] if 'Description' in desc: - if have_desc: - ebuilder.add ( 'DESCRIPTION', '// ' + desc ['Description'] ) + if description is None: + description = desc ['Description'] else: - ebuilder.add ( 'DESCRIPTION', desc ['Description'] ) + description += '// ' + desc ['Description'] + if description is not None: + ebuild.use ( evars.DESCRIPTION ( description ) ) - ebuilder.add ( 'SRC_URI', self.package_info ['package_url'] ) + ebuild.use ( evars.SRC_URI ( self.package_info ['SRC_URI'] ) ) - if self._resolve_dependencies ( ebuilder ): - return ( ebuilder.get_ebuild(), ebuilder.has_rsuggests ) + ebuild_text = ebuild.to_str() - return None - # --- end of _make_ebuild (...) --- + self.package_info.update_now ( + ebuild=ebuild_text, + depres_result=dep_result + ) - def run ( self ): - if self.status < 1: - raise Exception ( "Cannot run again." ) + return True - try: - if self.package_info.get ( 'desc_data', - fallback_value=None, do_fallback=True ) is None: - - logging.warning ( 'Reading description data now.' ) - reader = DescriptionReader ( - self.package_info, - logger=self.logger, - read_now=True - ) - self.package_info.set_writeable() - self.package_info.update ( - desc_data=reader.get_desc ( run_if_unset=False ) - ) - del reader - # -- if - self.package_info.set_readonly() - - ebuild_info = self._make_ebuild() - if ebuild_info is None: - self.logger.info ( "Cannot create an ebuild for this package." ) - self.status = -1 - else: - self.package_info.set_writeable() - self.package_info.update ( - ebuild=ebuild_info [0], - suggests=ebuild_info [1] - ) - self.package_info.set_readonly() - self.logger.debug ( "Ebuild is ready." ) - self.status = 0 - except Exception as e: - # log this and set status to fail - self.status = -10 - self.logger.exception ( e ) - # --- end of run (...) --- diff --git a/roverlay/ebuild/depres.py b/roverlay/ebuild/depres.py new file mode 100644 index 0000000..f0ec712 --- /dev/null +++ b/roverlay/ebuild/depres.py @@ -0,0 +1,167 @@ +# R Overlay -- ebuild creation, +# Copyright 2006-2012 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +import roverlay.static.depres + +from roverlay.ebuild import evars + +# move this to const / config +FIELDS = { + 'R_SUGGESTS' : [ 'Suggests' ], + 'DEPENDS' : [ 'Depends', 'Imports' ], + 'RDEPENDS' : [ 'LinkingTo', 'SystemRequirements' ] +} + +EBUILDVARS = { + 'R_SUGGESTS' : evars.R_SUGGESTS, + 'DEPENDS' : evars.DEPEND, + 'RDEPENDS' : evars.RDEPEND, +} + + +class EbuildDepRes ( object ): + + def __init__ ( + self, package_info, logger, + depres_channel_spawner=None, create_iuse=True, run_now=True + ): + self.logger = logger + self.package_info = package_info + + if depres_channel_spawner is None: + self.request_resolver = roverlay.static.depres.get_ebuild_channel + else: + self.request_resolver = depres_channel_spawner + + # > 0 busy/working; 0 == done,success; < 0 done,fail + self.status = 1 + self.result = None + self.has_suggests = None + self.create_iuse = create_iuse + + self._channels = None + + if run_now: + self.resolve() + + # --- end of __init__ (...) --- + + def done ( self ) : return self.status < 1 + def busy ( self ) : return self.status > 0 + def success ( self ) : return self.status == 0 + def fail ( self ) : return self.status < 0 + + def get_result ( self ): + return ( self.status, self.result, self.has_suggests ) + # --- end of get_result (...) --- + + def resolve ( self ): + try: + self.result = None + self._init_channels() + + if self._wait_resolve(): + self._make_result() + self.status = 0 + + else: + # unresolvable + self.logger.info ( "Cannot satisfy dependencies!" ) + + self.result = None + self.status = -5 + + finally: + self._close_channels() + # --- end of resolve (...) --- + + def _get_channel ( self, dependency_type ): + if dependency_type not in self._channels: + self._channels [dependency_type] = self.request_resolver ( + dependency_type, + self.logger + ) + return self._channels [dependency_type] + # --- end of get_channel (...) --- + + def _init_channels ( self ): + # collect dep strings and initialize resolver channels + + if self.request_resolver is None: + self.logger.warning ( + "Cannot resolve dependencies, no resolver available!" + ) + return True + + desc = self.package_info ['desc_data'] + self._channels = dict() + + dep_type = desc_field = None + + for dep_type in FIELDS: + resolver = None + + for desc_field in FIELDS [dep_type]: + if desc_field in desc: + if not resolver: + resolver = self._get_channel ( dep_type ) + + if isinstance ( desc [desc_field], str ): + resolver.add_dependency ( desc [desc_field] ) + elif hasattr ( desc [desc_field], '__iter__' ): + resolver.add_dependencies ( desc [desc_field] ) + else: + logger.warning ( + "Cannot add dependency '%s'." % desc [desc_field] + ) + # -- for dep_type + + self.has_suggests = bool ( 'R_SUGGESTS' in self._channels ) + + # --- end of _init_channels (...) --- + + def _close_channels ( self ): + if self._channels is None: return + + for channel in self._channels.values(): channel.close() + del self._channels + # --- end of _close_channels (...) --- + + def _wait_resolve ( self ): + # True if no channels + for c in self._channels.values(): + if c.satisfy_request() is None: + return False + return True + # --- end of _wait_resolve (...) --- + + def _make_result ( self ): + _result = list() + for dep_type, channel in self._channels.items(): + deplist = list ( filter ( None, channel.collect_dependencies() ) ) + + if deplist is None: + ## FIXME: false positive: "empty" channel + raise Exception ( + 'dep_resolver is broken: ' + 'lookup() returns None but satisfy_request() says ok.' + ) + elif hasattr ( deplist, '__iter__' ): + # add dependencies in no_append/override mode + self.logger.debug ( "adding %s to %s", deplist, dep_type ) + _result.append ( + EBUILDVARS [dep_type] ( + deplist, + using_suggests=self.has_suggests + ) + ) + else: + raise Exception ( "dep_resolver is broken: iterable expected!" ) + # -- for dep_type,.. + + if self.create_iuse: + _result.append ( evars.IUSE ( using_suggests=self.has_suggests ) ) + + self.result = tuple ( _result ) + # --- end of _make_result (...) --- diff --git a/roverlay/ebuild/ebuilder.py b/roverlay/ebuild/ebuilder.py new file mode 100644 index 0000000..275c6d2 --- /dev/null +++ b/roverlay/ebuild/ebuilder.py @@ -0,0 +1,36 @@ +# R Overlay -- ebuild creation, +# Copyright 2006-2012 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +class Ebuilder ( object ): + + def __init__ ( self ): + self._evars = list() + + def sort ( self ): + self._evars.sort ( key=lambda e: e.priority ) + + def get_lines ( self ): + self.sort() + last = len ( self._evars ) - 1 + + newline = lambda i, k=1 : \ + abs ( self._evars [i + k].priority - self._evars [i].priority ) >= 20 + + + lines = list() + for index, e in enumerate ( self._evars ): + if e.active(): + lines.append ( str ( e ) ) + if index < last and newline ( index ): lines.append ( '' ) + + return lines + + def to_str ( self ): + return '\n'.join ( self.get_lines() ) + + __str__ = to_str + + def use ( self, *evar_list ): + for e in evar_list: + self._evars.append ( e ) diff --git a/roverlay/ebuild/evars.py b/roverlay/ebuild/evars.py new file mode 100644 index 0000000..095f375 --- /dev/null +++ b/roverlay/ebuild/evars.py @@ -0,0 +1,70 @@ +# R Overlay -- ebuild creation, +# Copyright 2006-2012 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +from roverlay.util import shorten_str + +from roverlay.ebuild.abstractcomponents import ListValue, EbuildVar + +IUSE_SUGGESTS = 'R_suggests' + +# ignoring case policies here (camel case,..) + +class DESCRIPTION ( EbuildVar ): + def __init__ ( self, description ): + super ( DESCRIPTION, self ) . __init__ ( 'DESCRIPTION', description, 80 ) + + def __str__ ( self ): + return '%s%s="%s"' % ( + self.indent, + self.name, + shorten_str ( str ( self.value ) , 45, '... (see metadata)' ) + ) + + +class SRC_URI ( EbuildVar ): + def __init__ ( self, src_uri ): + super ( SRC_URI, self ) . __init__ ( 'SRC_URI', src_uri, 90 ) + + +class IUSE ( EbuildVar ): + def __init__ ( self, use_flags=None, using_suggests=False ): + super ( IUSE, self ) . __init__ ( + 'IUSE', + ListValue ( use_flags, empty_value='${IUSE:-}' ), + 130 + ) + self.value.single_line = True + if using_suggests: + self.value.add ( IUSE_SUGGESTS ) + + +class R_SUGGESTS ( EbuildVar ): + def __init__ ( self, deps, **kw ): + super ( R_SUGGESTS, self ) . __init__ ( + 'R_SUGGESTS', + ListValue ( deps ), + 140 + ) + + +class DEPEND ( EbuildVar ): + def __init__ ( self, deps, **kw ): + super ( DEPEND, self ) . __init__ ( + 'DEPEND', + ListValue ( deps ), + 150 + ) + + +class RDEPEND ( EbuildVar ): + def __init__ ( self, deps, using_suggests=False, **kw ): + super ( RDEPEND, self ) . __init__ ( + 'RDEPEND', + ListValue ( deps, empty_value="${DEPEND:-}" ), + 160 + ) + if using_suggests: self.enable_suggests() + + def enable_suggests ( self ): + self.value.add ( '%s? ( ${R_SUGGESTS} )' % IUSE_SUGGESTS ) -- cgit v1.2.3-65-gdbad