public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/ebuild/, roverlay/depres/simpledeprule/, roverlay/depres/, roverlay/, ...
@ 2013-07-04 17:02 André Erdmann
  0 siblings, 0 replies; only message in thread
From: André Erdmann @ 2013-07-04 17:02 UTC (permalink / raw
  To: gentoo-commits

commit:     3187207842e4c7022f3129bf5343924a1e33b594
Author:     André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jul  4 16:53:51 2013 +0000
Commit:     André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jul  4 16:53:51 2013 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=31872078

roverlay/depres: return depresult objects

Dependency resolution now creates depresult objects if a rule matches a
dependency string. Previously, it returned a 2-tuple (score,resolving_dep).

This is "necessary" for selfdep reduction (also see pseudocode in
overlay/root.py).

Additionally, this commit allows to define selfdeps that don't belong to the
default category ("sci-R") in rule files, either by OR-ing a deptype with
"#deptype <deptype>,selfdep" or by prefixing a single rule with "@selfdep".
The rule stub syntax ("zoo") is mostly unaffected by this change, but roverlay
is able to detect (non-)default-category selfdeps now.

---
 roverlay/depres/channels.py                    |   8 +-
 roverlay/depres/depenv.py                      |   3 +
 roverlay/depres/depresolver.py                 |  16 +--
 roverlay/depres/depresult.py                   | 131 +++++++++++++++++++++++++
 roverlay/depres/deprule.py                     |  23 ++++-
 roverlay/depres/deptype.py                     |  12 ++-
 roverlay/depres/listeners.py                   |   2 +-
 roverlay/depres/simpledeprule/abstractrules.py |  50 +++++-----
 roverlay/depres/simpledeprule/console.py       |   4 +-
 roverlay/depres/simpledeprule/rulemaker.py     |  76 ++++++++------
 roverlay/ebuild/creation.py                    |  14 +--
 roverlay/ebuild/depfilter.py                   |   4 +-
 roverlay/ebuild/depres.py                      | 118 +++++++++++++---------
 roverlay/ebuild/ebuilder.py                    |   6 +-
 roverlay/overlay/category.py                   |   2 +-
 roverlay/overlay/pkgdir/packagedir_base.py     |   4 +
 roverlay/overlay/root.py                       |  34 +++++++
 roverlay/packageinfo.py                        |  25 +++--
 18 files changed, 399 insertions(+), 133 deletions(-)

diff --git a/roverlay/depres/channels.py b/roverlay/depres/channels.py
index 3e0085f..b1f39bd 100644
--- a/roverlay/depres/channels.py
+++ b/roverlay/depres/channels.py
@@ -14,6 +14,8 @@ __all__ = [ 'EbuildJobChannel', ]
 
 import logging
 
+import roverlay.depres.depresult
+
 from roverlay.depres               import deptype
 from roverlay.depres.depenv        import DepEnv
 from roverlay.depres.communication import DependencyResolverChannel
@@ -192,9 +194,9 @@ class EbuildJobChannel ( _EbuildJobChannelBase ):
             ret = True
          elif deptype.mandatory & ~dep_env.deptype_mask:
             # not resolved, but deptype has no mandatory bit set
-            #  => dep is not required, resolve as None and add it to
-            #     the list of unresolvable deps
-            resolved ( None )
+            #  => dep is not required, resolve it as "not resolved"
+            #     and add it to the list of unresolvable deps
+            resolved ( roverlay.depres.depresult.DEP_NOT_RESOLVED )
             unresolvable ( dep_env.dep_str )
             ret = True
          # else failed

diff --git a/roverlay/depres/depenv.py b/roverlay/depres/depenv.py
index c298447..3d324a4 100644
--- a/roverlay/depres/depenv.py
+++ b/roverlay/depres/depenv.py
@@ -191,6 +191,7 @@ class DepEnv ( object ):
 
             result.append ( dict (
                name             = m.group ( 'name' ),
+               name_low         = m.group ( 'name' ).lower(),
                version_modifier = vmod,
                version          = version,
                version_strlist  = version_strlist,
@@ -267,3 +268,5 @@ class DepEnv ( object ):
    def get_resolved ( self ):
       return self.resolved_by
    # --- end of get_resolved (...) ---
+
+# --- end of DepEnv ---

diff --git a/roverlay/depres/depresolver.py b/roverlay/depres/depresolver.py
index b9465fd..a49697a 100644
--- a/roverlay/depres/depresolver.py
+++ b/roverlay/depres/depresolver.py
@@ -177,7 +177,9 @@ class DependencyResolver ( object ):
          # log this event
          if event_type == events.DEPRES_EVENTS ['RESOLVED']:
             self.logger_resolved.info (
-               "{!r} as {!r}".format ( dep_env.dep_str, dep_env.resolved_by )
+               "{!r} as {!r}".format (
+                  dep_env.dep_str, dep_env.resolved_by.dep
+               )
             )
          elif event_type == events.DEPRES_EVENTS ['UNRESOLVABLE']:
             self.logger_unresolvable.info ( "{!r}".format ( dep_env.dep_str ) )
@@ -378,8 +380,8 @@ class DependencyResolver ( object ):
                if p.accepts ( dep_env.deptype_mask, try_other=False )
          ):
             result = rulepool.matches ( dep_env )
-            if result [0] > 0:
-               resolved    = result [1]
+            if result:
+               resolved    = result
                is_resolved = 2
                break
          # TRY_OTHER searching is disabled for dynamic rule pools,
@@ -391,8 +393,8 @@ class DependencyResolver ( object ):
                if p.accepts ( dep_env.deptype_mask, try_other=False )
          ):
             result = rulepool.matches ( dep_env )
-            if result [0] > 0:
-               resolved    = result [1]
+            if result:
+               resolved    = result
                is_resolved = 2
                break
 
@@ -405,8 +407,8 @@ class DependencyResolver ( object ):
                   if p.accepts ( ~dep_env.deptype_mask, try_other=True )
             ):
                result = rulepool.matches ( dep_env )
-               if result [0] > 0:
-                  resolved    = result [1]
+               if result:
+                  resolved    = result
                   is_resolved = 2
                   break
          # --

diff --git a/roverlay/depres/depresult.py b/roverlay/depres/depresult.py
new file mode 100644
index 0000000..91a4688
--- /dev/null
+++ b/roverlay/depres/depresult.py
@@ -0,0 +1,131 @@
+# R overlay -- dependency resolution, depres result
+# -*- coding: utf-8 -*-
+# Copyright (C) 2013 André Erdmann <dywi@mailerd.de>
+# Distributed under the terms of the GNU General Public License;
+# either version 2 of the License, or (at your option) any later version.
+
+__all__ = [ 'DepResult', 'DEP_NOT_RESOLVED', ]
+
+import roverlay.depres.depenv
+
+EMPTY_STR = ""
+
+class DepResult ( object ):
+
+   # TODO/FIXME: define those constants somewhere else
+   #  (especially VMOD_??)
+   #
+   VMOD_COMPARE_MAP = {
+      # p.version_compare_* functions are TODO
+      roverlay.depres.depenv.DepEnv.VMOD_EQ: (
+         lambda p: p.version_compare_eq
+      ),
+      roverlay.depres.depenv.DepEnv.VMOD_NE: (
+         lambda p: p.version_compare_ne
+      ),
+      roverlay.depres.depenv.DepEnv.VMOD_GT: (
+         lambda p: p.version_compare_gt
+      ),
+      roverlay.depres.depenv.DepEnv.VMOD_GE: (
+         lambda p: p.version_compare_ge
+      ),
+      roverlay.depres.depenv.DepEnv.VMOD_LT: (
+         lambda p: p.version_compare_lt
+      ),
+      roverlay.depres.depenv.DepEnv.VMOD_LE: (
+         lambda p: p.version_compare_le
+      ),
+   }
+
+   def __init__ ( self,
+      dep, score, matching_rule, dep_env=None, fuzzy=None
+   ):
+      self.dep        = dep
+      self.score      = score
+      #assert hasattr ( matching_rule, 'is_selfdep' )
+      self.is_selfdep = matching_rule.is_selfdep if matching_rule else 0
+
+      if self.is_selfdep:
+         self.fuzzy = fuzzy
+         self.resolving_package = matching_rule.resolving_package
+   # --- end of DepResult ---
+
+   def __eq__ ( self, other ):
+      if isinstance ( other, str ):
+         return str ( self ) == other
+      elif isinstance ( other, DepResult ):
+         return (
+            self.score == other.score
+            and self.is_selfdep == other.is_selfdep
+            and self.dep == other.dep
+         )
+      else:
+         return NotImplemented
+   # --- end of __eq__ (...) ---
+
+   def __hash__ ( self ):
+      #return hash ( self.__dict__.values() )
+      return hash (( self.dep, self.score, self.is_selfdep ))
+   # --- end of __hash__ (...) ---
+
+   def __bool__ ( self ):
+      return self.score > 0
+      #and self.dep is not False
+   # --- end of __bool__ (...) ---
+
+   def __str__ ( self ):
+      return self.dep if self.dep is not None else EMPTY_STR
+   # --- end of __str__ (...) ---
+
+   def __getitem__ ( self, key ):
+      # for backwards compatibility, indexing is supported
+      if key == 0:
+         return self.score
+      elif key == 1:
+         return self.dep
+      elif isinstance ( key, int ):
+         raise IndexError ( key )
+      else:
+         raise KeyError ( key )
+   # --- end of __getitem__ (...) ---
+
+   def prepare_selfdep_reduction ( self ):
+      cat, sepa, pkg  = self.resolving_package.rpartition ( '/' )
+      self.category   = cat
+      self.package    = pkg
+      self.candidates = list()
+      self.link       = self.candidates.append
+
+      if self.fuzzy:
+         vmod         = self.fuzzy ['vmod']
+         self.version = self.fuzzy ['version_tuple']
+         self._version_compare = self.VMOD_COMPARE_MAP [vmod]
+         self.version_compare  = (
+            lambda p: self._version_compare ( p ) ( self.version )
+         )
+   # --- end of prepare_selfdep_reduction (...) ---
+
+   def deps_satisfiable ( self ):
+      return bool ( self.candidates )
+
+   def link_if_version_matches ( self, p ):
+      if not self.fuzzy or self.version_compare ( p ):
+         self.link ( p )
+         return True
+      else:
+         return False
+   # --- end of link_if_version_matches (...) ---
+
+   def reduce ( self ):
+      candidates = list (
+         p for p in self.candidates if p.has_valid_selfdeps()
+      )
+      num_removed = len ( self.candidates ) - len ( candidates )
+      if num_removed != 0:
+         self.candidates = candidates
+      return num_removed
+   # --- end of reduce (...) ---
+
+# --- end of DepResult ---
+
+DEP_NOT_RESOLVED = DepResult ( dep=None, score=-2, matching_rule=None )

diff --git a/roverlay/depres/deprule.py b/roverlay/depres/deprule.py
index 46c710d..1d36941 100644
--- a/roverlay/depres/deprule.py
+++ b/roverlay/depres/deprule.py
@@ -8,6 +8,8 @@
 
 __all__ = [ 'DependencyRule', 'DependencyRulePool', ]
 
+import roverlay.depres.depresult
+
 from roverlay.depres import deptype
 
 class DependencyRule ( object ):
@@ -25,11 +27,19 @@ class DependencyRule ( object ):
    # --- end of __init__ (...) ---
 
    def matches ( self, dep_env ):
-      """Returns a tuple ( score ::= int > 0, matching dep ::= str )
+      """Returns a tuple ( score ::= int > 0, matching dep ::= DepResult )
       if this rule matches the given DepEnv, else None"""
       return None
    # --- end of matches (...) ---
 
+   def _make_result ( self, resolved_dep, score, *args, **kw ):
+      return roverlay.depres.depresult.DepResult (
+         resolved_dep, score, self, *args, **kw
+      )
+   # --- end of _make_result (...) ---
+
+   make_result = _make_result
+
 # --- end of DependencyRule ---
 
 
@@ -114,6 +124,11 @@ class DependencyRulePool ( object ):
          #  cannot expect a result in this case - abort now
          pass
 
+      elif skip_matches == 0:
+         for rule in self.rules:
+            result = rule.matches ( dep_env )
+            if result:
+               return result
       else:
          skipped = 0
          # python3 requires list ( range ... )
@@ -125,12 +140,12 @@ class DependencyRulePool ( object ):
 
          for index in order:
             result = self.rules [index].matches ( dep_env )
-            if result is not None and result [0] > 0:
+            if result:
                if skipped < skip_matches:
                   skipped += 1
                else:
                   return result
 
-
-      return ( -1, None )
+      # default return
+      return None
    # --- end of matches (...) ---

diff --git a/roverlay/depres/deptype.py b/roverlay/depres/deptype.py
index 269f666..f430316 100644
--- a/roverlay/depres/deptype.py
+++ b/roverlay/depres/deptype.py
@@ -13,14 +13,22 @@
 # <deptype> ::= 2**k | k in {0,1,2,...}
 # try_other indicates that the dep can be checked world-wide (in non-accepting
 # rule pools) after unsuccessful resolution
+#
 try_other = 1
 mandatory = 2
 external  = 4
 internal  = 8
+#internal does not imply selfdep
+# internal := dependency on package
+# selfdep  := created overlay has dependency
+selfdep   = 16
 
-_MAX = 15
+_MAX = 31
 
-ALL = external | internal | mandatory
+#VIRTUAL = try_other | mandatory | selfdep
+
+NONE = 0
+ALL  = external | internal | mandatory
 RESOLVE_ALL = external | internal
 
 SYS = external | mandatory

diff --git a/roverlay/depres/listeners.py b/roverlay/depres/listeners.py
index 29dd539..3d5ceaf 100644
--- a/roverlay/depres/listeners.py
+++ b/roverlay/depres/listeners.py
@@ -111,7 +111,7 @@ class ResolvedFileListener ( FileListener ):
    def notify ( self, event_type, dep_env=None, pkg_env=None, **extra ):
       self._event ( event_type,
          "{dep_str!r} as {dep!r}".format (
-            dep_str=dep_env.dep_str, dep=dep_env.resolved_by
+            dep_str=dep_env.dep_str, dep=dep_env.resolved_by.dep
       ) )
    # --- end of notify (...) ---
 

diff --git a/roverlay/depres/simpledeprule/abstractrules.py b/roverlay/depres/simpledeprule/abstractrules.py
index 0713c81..b80eb00 100644
--- a/roverlay/depres/simpledeprule/abstractrules.py
+++ b/roverlay/depres/simpledeprule/abstractrules.py
@@ -20,7 +20,7 @@ class SimpleRule ( deprule.DependencyRule ):
 
    def __init__ ( self,
       dep_str=None, priority=50, resolving_package=None,
-      is_selfdep=False, logger_name='simple_rule'
+      is_selfdep=0, logger_name='simple_rule'
    ):
       """Initializes a SimpleIgnoreDependencyRule.
 
@@ -29,25 +29,22 @@ class SimpleRule ( deprule.DependencyRule ):
       * priority -- priority of this rule
       """
       super ( SimpleRule, self ) . __init__ ( priority )
-      self.dep_alias = list()
-
-      self.logger = TMP_LOGGER.getChild ( logger_name )
-
-      self.is_selfdep = is_selfdep
-
-      self.resolving_package = resolving_package
 
+      self.dep_alias               = list()
+      self.logger                  = TMP_LOGGER.getChild ( logger_name )
+      self.is_selfdep              = int ( is_selfdep or 0 )
+      self.resolving_package       = resolving_package
       self.prepare_lowercase_alias = True
 
-      if not dep_str is None:
+      if dep_str is not None:
          self.dep_alias.append ( dep_str )
 
-      if self.is_selfdep and dep_str is not None:
-         # add the actual package name (replace '_' by '.') to self.dep_alias
-         actual_name = dep_str.replace ( '_', '.' )
-         if actual_name != dep_str:
-            self.dep_alias.append ( dep_str )
-
+         if self.is_selfdep:
+            # add the actual package name (replace '_' by '.')
+            # to self.dep_alias
+            actual_name = dep_str.replace ( '_', '.' )
+            if actual_name != dep_str:
+               self.dep_alias.append ( dep_str )
    # --- end of __init__ (...) ---
 
    def done_reading ( self ):
@@ -92,7 +89,9 @@ class SimpleRule ( deprule.DependencyRule ):
             "matches {dep_str} with score {s} and priority {p}.".format (
                dep_str=dep_env.dep_str, s=self.max_score, p=self.priority
          ) )
-         return ( self.max_score, self.resolving_package )
+         return self.make_result (
+            self.resolving_package, self.max_score, dep_env=dep_env
+         )
 
       return None
    # --- end of matches (...) ---
@@ -116,7 +115,7 @@ class SimpleRule ( deprule.DependencyRule ):
          else:
             resolving = self.resolving_package
 
-            if self.is_selfdep:
+            if self.is_selfdep == 2:
                resolving = resolving.rpartition ( '/' ) [2]
 
 
@@ -125,6 +124,8 @@ class SimpleRule ( deprule.DependencyRule ):
       # -- end if;
 
       if self.is_selfdep:
+         if self.is_selfdep == 1:
+            yield '@selfdep'
          yield resolving
 
       elif len ( self.dep_alias ) == 0:
@@ -164,18 +165,18 @@ class FuzzySimpleRule ( SimpleRule ):
       elif self.resolving_package is None:
          # ignore rule
          for fuzzy in dep_env.fuzzy:
-            if self._find ( fuzzy ['name'], lowercase=True ):
+            if self._find ( fuzzy ['name_low'], lowercase=True ):
                return ( 1, fuzzy )
       else:
          for fuzzy in dep_env.fuzzy:
-            if self._find ( fuzzy ['name'], lowercase=True ):
+            if self._find ( fuzzy ['name_low'], lowercase=True ):
                return ( 0, fuzzy )
             # -- end if find (=match found)
       # -- end if
       return None
    # --- end of match_prepare (...) ---
 
-   def log_fuzzy_match ( self, dep_env, dep, score ):
+   def log_fuzzy_match ( self, dep_env, dep, score, fuzzy ):
       if dep is False:
          return None
       else:
@@ -185,7 +186,7 @@ class FuzzySimpleRule ( SimpleRule ):
                dep_str=dep_env.dep_str, dep=dep, s=score
             )
          )
-         return ( score, dep )
+         return self.make_result ( dep, score, dep_env=dep_env, fuzzy=fuzzy )
    # --- end of log_fuzzy_match (...) ---
 
    def log_standard_match ( self, dep_env, score ):
@@ -194,7 +195,7 @@ class FuzzySimpleRule ( SimpleRule ):
             dep_str=dep_env.dep_str, s=score, p=self.priority
          )
       )
-      return ( score, self.resolving_package )
+      return self.make_result ( self.resolving_package, score )
    # --- end of log_standard_match (...) ---
 
    def handle_version_relative_match ( self, dep_env, fuzzy ):
@@ -213,12 +214,13 @@ class FuzzySimpleRule ( SimpleRule ):
             return self.log_fuzzy_match (
                dep_env,
                self.handle_version_relative_match ( dep_env, fuzzy ),
-               score
+               score,
+               fuzzy
             )
          elif match_type == 1:
             # name-only match (ignore rule?)
             return self.log_fuzzy_match (
-               dep_env, self.resolving_package, score
+               dep_env, self.resolving_package, score, fuzzy
             )
          else:
             # non-fuzzy match

diff --git a/roverlay/depres/simpledeprule/console.py b/roverlay/depres/simpledeprule/console.py
index e4e5efc..a845d41 100644
--- a/roverlay/depres/simpledeprule/console.py
+++ b/roverlay/depres/simpledeprule/console.py
@@ -74,14 +74,14 @@ class PackageDirRuleMaker ( object ):
             yield rules.SimpleFuzzyDependencyRule (
                resolving_package = strutil.fix_ebuild_name ( cat + dep ),
                dep_str = dep,
-               is_selfdep=True
+               is_selfdep=2
             )
       else:
          for dep in self._scan ( distdir ):
             yield rules.SimpleDependencyRule (
                resolving_package = strutil.fix_ebuild_name ( cat + dep ),
                dep_str = dep,
-               is_selfdep=True
+               is_selfdep=2
             )
    # --- end of make_rules (...) ---
 

diff --git a/roverlay/depres/simpledeprule/rulemaker.py b/roverlay/depres/simpledeprule/rulemaker.py
index a993341..ed39791 100644
--- a/roverlay/depres/simpledeprule/rulemaker.py
+++ b/roverlay/depres/simpledeprule/rulemaker.py
@@ -31,15 +31,24 @@ class SimpleRuleMaker ( object ):
          '\s+::\s+' if rule_separator is None else rule_separator
       )
 
+      self.DEPTYPE_MAP = {
+         'all'     : deptype.ALL,
+         'sys'     : deptype.external,
+         'pkg'     : deptype.internal,
+         'selfdep' : deptype.selfdep,
+      }
+
       self.multiline_start = '{'
       self.multiline_stop  = '}'
       self.comment_char    = '#'
+      self.kw_selfdep_once = '@selfdep'
       self._kwmap          = rules.RuleConstructor (
          eapi = config.get_or_fail ( 'EBUILD.eapi' )
       )
       # deptype_kw is '#deptype' (this keyword requires comment 'mode')
       self.deptype_kw      = 'deptype'
       self._deptype        = deptype.ALL
+      self._deptype_once   = deptype.NONE
       self._next           = None
       # [ ( deptype, rule ), ... ]
       self._rules          = list()
@@ -72,19 +81,28 @@ class SimpleRuleMaker ( object ):
       return ret
    # --- end of done (...) ---
 
-   def _get_deptype ( self, t ):
-      if len ( t ) == 0 or t == 'all':
-         return deptype.ALL
-      elif t == 'sys':
-         return deptype.external
-      elif t == 'pkg':
-         return deptype.internal
+   def _parse_deptype ( self, deptype_str ):
+      ret = deptype.NONE
+      try:
+         for item in deptype_str.split ( ',' ):
+            ret |= self.DEPTYPE_MAP [item]
+      except KeyError:
+         raise Exception ( "unknown deptype {!r}".format ( deptype_str ) )
+
+      return ret if ret != deptype.NONE else deptype.ALL
+   # --- end of _parse_deptype (...) ---
+
+   def _get_effective_deptype ( self, clear_temporary=True ):
+      if self._deptype_once is not deptype.NONE:
+         if clear_temporary:
+            ret = self._deptype_once
+            self._deptype_once = deptype.NONE
+            return ret
+         else:
+            self._deptype_once
       else:
-         try:
-            return int ( t )
-         except ValueError:
-            return None
-   # --- end of _get_deptype (...) ---
+         return self._deptype
+   # --- end of _get_effective_deptype (...) ---
 
    def _single_line_rule ( self, dep, dep_str='' ):
       # single line rule, either selfdep,
@@ -92,35 +110,38 @@ class SimpleRuleMaker ( object ):
       #  or normal rule 'dev-lang/R :: R'
       # selfdeps are always single line statements (!)
 
+      rule_deptype                  = self._get_effective_deptype()
       rule_class, resolving, kwargs = self._kwmap.lookup ( dep )
 
       if dep_str:
          # normal rule
          new_rule = rule_class (
-            resolving_package=resolving,
-            dep_str=dep_str,
-            is_selfdep=False,
+            resolving_package = resolving,
+            dep_str           = dep_str,
+            is_selfdep        = (
+               1 if ( rule_deptype & deptype.selfdep ) else 0
+            ),
             **kwargs
          )
 
       elif resolving is not None:
-         # selfdep
+         # selfdep (rule stub)
          dep_str   = resolving
          resolving = (
             config.get_or_fail ( 'OVERLAY.category' ) + '/' + resolving
          )
 
          new_rule = rule_class (
-            resolving_package=resolving,
-            dep_str=dep_str,
-            is_selfdep=True,
+            resolving_package = resolving,
+            dep_str           = dep_str,
+            is_selfdep        = 2,
             **kwargs
          )
       else:
          return False
 
       new_rule.done_reading()
-      self._rules.append ( ( self._deptype, new_rule ) )
+      self._rules.append ( ( rule_deptype, new_rule ) )
       return True
    # --- end of _single_line_rule (...) ---
 
@@ -144,23 +165,22 @@ class SimpleRuleMaker ( object ):
          if line [ 1 : 1 + len ( self.deptype_kw ) ] == self.deptype_kw :
             # changing deptype ("#deptype <type>")
             dtype_str = line [ len ( self.deptype_kw ) + 2 : ].lstrip().lower()
-            dtype = self._get_deptype ( dtype_str )
-            if dtype is not None:
-               self._deptype = dtype
-            else:
-               raise AssertionError (
-                  "Expected deptype, but got {!r}.".format ( dtype_str )
-               )
+            self._deptype = self._parse_deptype ( dtype_str )
+
          # else is a comment,
          #  it's intented that multi line rules cannot contain comments
          return True
 
+      elif line == self.kw_selfdep_once:
+         self._deptype_once = self._deptype | deptype.selfdep
+         return True
+
       elif len ( line ) > 1 and line [-1] == self.multiline_start:
          l = line [:-1].rstrip()
          rule_class, resolving, kwargs = self._kwmap.lookup ( l )
 
          self._next = (
-            self._deptype,
+            self._get_effective_deptype(),
             rule_class ( resolving_package=resolving, **kwargs ),
          )
          return True

diff --git a/roverlay/ebuild/creation.py b/roverlay/ebuild/creation.py
index 9fda2b6..819616a 100644
--- a/roverlay/ebuild/creation.py
+++ b/roverlay/ebuild/creation.py
@@ -125,15 +125,16 @@ class EbuildCreation ( object ):
          )
          return False
 
-      _dep_resolution = depres.EbuildDepRes (
+      dep_resolution = depres.EbuildDepRes (
          self.package_info, self.logger,
          run_now=True, depres_channel_spawner=self.depres_channel_spawner,
          err_queue=self.err_queue
       )
 
-      if _dep_resolution.success():
-         dep_result  = _dep_resolution.get_result()
+      if dep_resolution.success():
+         #dep_result  = dep_resolution.get_result()
          ebuild      = ebuilder.Ebuilder()
+         evars_dep   = dep_resolution.get_evars()
          evars_extra = self.package_info.get_evars()
 
          if evars_extra:
@@ -145,10 +146,10 @@ class EbuildCreation ( object ):
          #   ...
 
          # add *DEPEND to the ebuild
-         ebuild.use ( *dep_result [1] )
+         ebuild.use_list ( evars_dep )
 
          # IUSE
-         if dep_result [2]:
+         if dep_resolution.has_suggests:
             rsuggests = ebuild.get ( 'R_SUGGESTS' )
             self.use_expand_flag_names = set ( rsuggests.get_flag_names() )
             ebuild.use ( evars.IUSE ( sorted ( rsuggests.get_flags() ) ) )
@@ -170,8 +171,9 @@ class EbuildCreation ( object ):
 
          self.package_info.update_now (
             ebuild=ebuild_text,
-            depres_result=dep_result
+            has_suggests=dep_resolution.has_suggests,
          )
+         self.package_info.selfdeps = dep_resolution.get_selfdeps()
 
          return True
 

diff --git a/roverlay/ebuild/depfilter.py b/roverlay/ebuild/depfilter.py
index a4c528a..4d59386 100644
--- a/roverlay/ebuild/depfilter.py
+++ b/roverlay/ebuild/depfilter.py
@@ -12,9 +12,11 @@ filter out redundant dependencies on dev-lang/R.
 
 __all__ = [ 'dep_allowed', ]
 
-def dep_allowed ( dep ):
+def dep_allowed ( dep_result ):
    """Filters out redundant dependencies on dev-lang/R."""
 
+   dep = dep_result.dep
+
    if not dep:
       return 0
    elif dep[0] in '|(':

diff --git a/roverlay/ebuild/depres.py b/roverlay/ebuild/depres.py
index ac65e31..4f12400 100644
--- a/roverlay/ebuild/depres.py
+++ b/roverlay/ebuild/depres.py
@@ -19,8 +19,8 @@ from roverlay.ebuild import evars, depfilter
 
 FIELDS_TO_EVAR = {
    'R_SUGGESTS' : ( 'Suggests', ),
-   'DEPENDS'    : ( 'Depends', 'Imports' ),
-   'RDEPENDS'   : ( 'LinkingTo', 'SystemRequirements' ),
+   'DEPEND'     : ( 'Depends', 'Imports' ),
+   'RDEPEND'    : ( 'LinkingTo', 'SystemRequirements' ),
    # ? : ( 'Enhances', )
 }
 
@@ -61,8 +61,8 @@ def create_use_expand_var ( *args, **kwargs ):
 
 EBUILDVARS = {
    'R_SUGGESTS' : create_use_expand_var,
-   'DEPENDS'    : evars.DEPEND,
-   'RDEPENDS'   : evars.RDEPEND,
+   'DEPEND'     : evars.DEPEND,
+   'RDEPEND'    : evars.RDEPEND,
 }
 
 
@@ -89,11 +89,10 @@ class EbuildDepRes ( object ):
 
       # > 0 busy/working; 0 == done,success; < 0 done,fail
       self.status       = 1
-      self.result       = None
+      self.depmap       = None
+      self.missingdeps  = None
       self.has_suggests = None
-
       self.err_queue    = err_queue
-
       self._channels    = None
 
       if run_now:
@@ -110,13 +109,15 @@ class EbuildDepRes ( object ):
       """Returns the result of dependency resolution,
       as tuple ( <status>, <evars>, <has R suggests> )
       """
+      raise NotImplementedError()
       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.missingdeps = None
+         self.depmap = None
          self._init_channels()
 
          if self._wait_resolve():
@@ -126,7 +127,8 @@ class EbuildDepRes ( object ):
             # unresolvable
             self.logger.info ( "Cannot satisfy dependencies!" )
 
-            self.result = None
+            self.missingdeps = None
+            self.depmap = None
             self.status = -5
 
       finally:
@@ -198,59 +200,81 @@ class EbuildDepRes ( object ):
    def _make_result ( self ):
       """Make evars using the depres result."""
 
-      # RDEPEND -> <deps>, DEPEND -> <deps>, ..
-      _depmap = dict()
-      # two for dep_type, <sth> loops to safely determine the actual deps
-      # (e.g. whether to include R_SUGGESTS in RDEPEND)
-
+      # <ebuild varname> => <deps>
+      depmap = dict()
       unresolvable_optional_deps = set()
 
       for dep_type, channel in self._channels.items():
          channel_result = channel.collect_dependencies()
-         deplist = tuple ( filter (
-            depfilter.dep_allowed, channel_result [0] )
-         )
+         deps = set ( filter ( depfilter.dep_allowed, channel_result[0] ) )
 
-         if len ( deplist ) > 0:
-            self.logger.debug (
-               "adding {deps} to {depvar}".format (
-                  deps=deplist, depvar=dep_type
+         if deps:
+            self.logger.debug ( "adding {deps} to {depvar}".format (
+               deps=deps, depvar=dep_type
             ) )
-            _depmap [dep_type] = deplist
+            depmap [dep_type] = deps
          # else: (effectively) no dependencies for dep_type
 
-         if channel_result [1] is not None:
-            unresolvable_optional_deps |= channel_result [1]
+         if channel_result[1]:
+            unresolvable_optional_deps |= channel_result[1]
 
       self._close_channels()
 
-      # empty R_SUGGESTS has been filtered out
-      self.has_suggests = bool ( 'R_SUGGESTS' in _depmap )
-
-      _result = list()
-      for dep_type, deplist in _depmap.items():
-         # add dependencies in no_append/override mode
-         _result.append (
-            EBUILDVARS [dep_type] (
-               deplist,
-               using_suggests=self.has_suggests,
-               use_expand=True
-            )
-         )
+      # remove redundant deps (DEPEND in RDEPEND, RDEPEND,DEPEND in R_SUGGESTS)
+      if 'RDEPEND' in depmap and 'DEPEND' in depmap:
+         depmap ['RDEPEND'] -= depmap ['DEPEND']
+         if not depmap ['RDEPEND']:
+            del depmap ['RDEPEND']
+
+      self.has_suggests = False
+      if 'R_SUGGESTS' in depmap:
+         if 'RDEPEND' in depmap:
+            depmap ['R_SUGGESTS'] -= depmap ['RDEPEND']
+         if 'DEPEND' in depmap:
+            depmap ['R_SUGGESTS'] -= depmap ['DEPEND']
+
+         if depmap ['R_SUGGESTS']:
+            self.has_suggests = True
+         else:
+            del depmap ['R_SUGGESTS']
 
-      # When using suggested dependencies, RDEPENDS is required even if empty
-      if self.has_suggests and 'RDEPENDS' not in _depmap:
-         _result.append (
-            EBUILDVARS ['RDEPENDS'] (
+
+      self.depmap = depmap
+      if unresolvable_optional_deps:
+         self.missingdeps = unresolvable_optional_deps
+   # --- end of _make_result (...) ---
+
+   def get_selfdeps ( self ):
+      def gen_selfdeps():
+         for deps in self.depmap.values():
+            for dep_result in deps:
+               if dep_result.is_selfdep:
+                  yield dep_result
+      # --- end of gen_selfdeps (...) ---
+
+      return frozenset ( gen_selfdeps() ) or None
+   # --- end of get_selfdeps (...) ---
+
+   def get_evars ( self ):
+      depgen = lambda D : ( k.dep for k in D )
+
+      evar_list = list (
+         EBUILDVARS [evar_name] (
+            depgen ( deps ),
+            using_suggests=self.has_suggests, use_expand=True
+         ) for evar_name, deps in self.depmap.items()
+      )
+      if self.has_suggests and 'RDEPEND' not in self.depmap:
+         evar_list.append (
+            EBUILDVARS ['RDEPEND'] (
                None, using_suggests=True, use_expand=True
             )
          )
 
-      if unresolvable_optional_deps:
-#         if not self.has_suggests: raise AssertionError() #?
-         _result.append (
-            evars.MISSINGDEPS ( unresolvable_optional_deps, do_sort=True )
+      if self.missingdeps:
+         evar_list.append (
+            evars.MISSINGDEPS ( self.missingdeps, do_sort=True )
          )
 
-      self.result = tuple ( _result )
-   # --- end of _make_result (...) ---
+      return evar_list
+   # --- end of get_evars (...) ---

diff --git a/roverlay/ebuild/ebuilder.py b/roverlay/ebuild/ebuilder.py
index 152cfc7..6806478 100644
--- a/roverlay/ebuild/ebuilder.py
+++ b/roverlay/ebuild/ebuilder.py
@@ -52,11 +52,15 @@ class Ebuilder ( object ):
       arguments:
       * *evar_list --
       """
+      self.use_list ( evar_list )
+   # --- end of use (...) ---
+
+   def use_list ( self, evar_list ):
       for e in evar_list:
          if e is not None:
             assert e.name not in self._evars
             self._evars [e.name] = e
-   # --- end of use (...) ---
+   # --- end of use_list (...) ---
 
    def has ( self, evar_name ):
       """Returns True if an evar with name evar_name exists.

diff --git a/roverlay/overlay/category.py b/roverlay/overlay/category.py
index aab8ff4..9c5c79f 100644
--- a/roverlay/overlay/category.py
+++ b/roverlay/overlay/category.py
@@ -160,7 +160,7 @@ class Category ( object ):
                yield dict (
                   dep_str           = name,
                   resolving_package = ( self.name + "/" + name ),
-                  is_selfdep        = is_default_category,
+                  is_selfdep        = 2 if is_default_category else 1,
                   # prefer packages from the default category (really?)
                   priority          = 80 if is_default_category else 90,
                )

diff --git a/roverlay/overlay/pkgdir/packagedir_base.py b/roverlay/overlay/pkgdir/packagedir_base.py
index 1f033a0..8b5b634 100644
--- a/roverlay/overlay/pkgdir/packagedir_base.py
+++ b/roverlay/overlay/pkgdir/packagedir_base.py
@@ -379,6 +379,10 @@ class PackageDirBase ( object ):
       self._need_metadata = True
       self.modified       = True
       if self.runtime_incremental:
+         raise Exception (
+            '--write-immediate is currently not available '
+            '(blocked by selfdep reduction).'
+         )
          with self._lock:
             return self.write_ebuilds ( overwrite=False )
       else:

diff --git a/roverlay/overlay/root.py b/roverlay/overlay/root.py
index 943518a..a5e847c 100644
--- a/roverlay/overlay/root.py
+++ b/roverlay/overlay/root.py
@@ -671,6 +671,40 @@ class Overlay ( object ):
          )
    # --- end of import_ebuilds (...) ---
 
+   def remove_bad_packages ( self ):
+      # "prepare"
+      #
+      ## collect:
+      ## find all <PackageInfo> p with selfdeps
+      ##    p->selfdeps->prepare_selfdep_reduction()
+      ##    add p->selfdeps to a list/listlike object S
+      ##
+      ## link:
+      ## foreach selfdep in S loop
+      ##    find <PackageInfo> candidates in overlay and link them to selfdep
+      ## end loop
+      #
+      # "reduce"
+      #
+      ## num_removed <- 0
+      ## first       <- True
+      ##
+      ## while num_removed > 0 or first loop
+      ##    first <- False
+      ##    foreach selfdep in S loop
+      ##        num_removed += selfdep.reduce()
+      ##    end loop
+      ## end loop
+      ##
+      #
+      # "balance" [if <anything removed>]
+      #
+      ## find all <PackageInfo> p with valid == False
+      ##     drop p
+      ##
+      raise NotImplementedError ( "TODO" )
+   # --- end of remove_bad_packages (...) ---
+
    def scan ( self, **kw ):
       def scan_categories():
          for x in os.listdir ( self.physical_location ):

diff --git a/roverlay/packageinfo.py b/roverlay/packageinfo.py
index b86d69d..bef9327 100644
--- a/roverlay/packageinfo.py
+++ b/roverlay/packageinfo.py
@@ -104,6 +104,7 @@ class PackageInfo ( object ):
       'imported',
       'physical_only',
       'src_uri',
+      'has_suggests',
    ))
    _UPDATE_KEYS_SIMPLE_INITIAL = frozenset ((
       'package_filename',
@@ -126,10 +127,13 @@ class PackageInfo ( object ):
       arguments:
       * **initial_info -- passed to update ( **kw )
       """
-      self._info               = dict()
-      self.readonly            = False
+      self._info    = dict()
+      self.valid    = True
+      self.readonly = False
+      self.logger   = LOGGER
+      self.selfdeps = None
+
       #self.overlay_package_ref = None
-      self.logger              = LOGGER
       #self._evars              = dict()
       #self._lazy_actions       = list()
       #(or set(), but list preserves order for actions with the same condition)
@@ -137,6 +141,17 @@ class PackageInfo ( object ):
       self.update ( **initial_info )
    # --- end of __init__ (...) ---
 
+   def has_valid_selfdeps ( self ):
+      """Returns True if all selfdeps of this package are valid."""
+      v = self.valid
+      if v is True and self.selfdeps is not None and not all (
+         map ( lambda d: d.deps_satisfiable(), self.selfdeps )
+      ):
+         self.valid = False
+         return False
+      return v
+   # --- end of has_valid_selfdeps (...) ---
+
    def attach_lazy_action ( self, lazy_action ):
       """Attaches a lazy action.
       Unsafe operation (no locks will be acquired etc.).
@@ -664,11 +679,9 @@ class PackageInfo ( object ):
             self._use_pvr ( value )
 
          elif key == 'suggests':
+            # FIXME/TODO: remove
             self._info ['has_suggests'] = value
 
-         elif key == 'depres_result':
-            self._info ['has_suggests'] = value [2]
-
          elif key == 'filepath':
             self._use_filepath ( value )
 


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2013-07-04 17:02 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-04 17:02 [gentoo-commits] proj/R_overlay:gsoc13/next commit in: roverlay/ebuild/, roverlay/depres/simpledeprule/, roverlay/depres/, roverlay/, André Erdmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox