aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndré Erdmann <dywi@mailerd.de>2012-06-20 20:53:38 +0200
committerAndré Erdmann <dywi@mailerd.de>2012-06-20 20:53:38 +0200
commite0c44a29537eff743d03e520966f4e6c2ecb5486 (patch)
treea7e030ae051373500fc4e03db8178b1ebee0a8e0
parentremove global USE flags from metadata creation (diff)
downloadR_overlay-e0c44a29537eff743d03e520966f4e6c2ecb5486.tar.gz
R_overlay-e0c44a29537eff743d03e520966f4e6c2ecb5486.tar.bz2
R_overlay-e0c44a29537eff743d03e520966f4e6c2ecb5486.zip
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
-rw-r--r--roverlay/ebuild/__init__.py39
-rw-r--r--roverlay/ebuild/abstractcomponents.py93
-rw-r--r--roverlay/ebuild/construction.py333
-rw-r--r--roverlay/ebuild/creation.py237
-rw-r--r--roverlay/ebuild/depres.py167
-rw-r--r--roverlay/ebuild/ebuilder.py36
-rw-r--r--roverlay/ebuild/evars.py70
7 files changed, 445 insertions, 530 deletions
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 <name>=<value> 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 )