* [gentoo-commits] proj/R_overlay:master commit in: roverlay/depres/
@ 2012-06-29 22:48 99% André Erdmann
0 siblings, 0 replies; 1+ results
From: André Erdmann @ 2012-06-29 22:48 UTC (permalink / raw
To: gentoo-commits
commit: f4fe2f55298624cd522b554aa57b505591a4138a
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Fri Jun 29 22:36:33 2012 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Fri Jun 29 22:36:33 2012 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=f4fe2f55
dependency resolution: 'fuzzy' rules
These extended simple rules match various dependency strings
with a single rule, e.g. a fuzzy "R" rule matches
"R (>= 2.10)" as ">=dev-lang/R-2.10" and "R <2.15" as "<dev-lang/R-2.15".
Also added easier syntax for R package dependencies (sound -> sci-R/sound)
in the dep rule file(s), which can now be written as 'sound' instead of
a category-hardcoded 'sci-R/sound :: sound' statement.
new file: roverlay/depres/abstractsimpledeprule.py
modified: roverlay/depres/deprule.py
modified: roverlay/depres/simpledeprule.py
---
roverlay/depres/abstractsimpledeprule.py | 204 ++++++++++++++++++++++++
roverlay/depres/deprule.py | 11 +-
roverlay/depres/simpledeprule.py | 254 ++++++++++++++----------------
3 files changed, 325 insertions(+), 144 deletions(-)
diff --git a/roverlay/depres/abstractsimpledeprule.py b/roverlay/depres/abstractsimpledeprule.py
new file mode 100644
index 0000000..b03ce63
--- /dev/null
+++ b/roverlay/depres/abstractsimpledeprule.py
@@ -0,0 +1,204 @@
+import logging
+
+from roverlay.depres import deprule
+
+TMP_LOGGER = logging.getLogger ('simpledeps')
+
+class SimpleRule ( deprule.DependencyRule ):
+ """A dependency rule that represents an ignored package in portage."""
+
+ def __init__ ( self,
+ dep_str=None, priority=50, resolving_package=None,
+ logger_name='simple_rule'
+ ):
+ """Initializes a SimpleIgnoreDependencyRule.
+
+ arguments:
+ * dep_str -- a dependency string that this rule is able to resolve
+ * priority -- priority of this rule
+ """
+ super ( SimpleRule, self ) . __init__ ( priority )
+ self.dep_alias = list()
+
+ self.logger = TMP_LOGGER.getChild ( logger_name )
+
+ self.resolving_package = resolving_package
+
+ self.prepare_lowercase_alias = True
+
+ if not dep_str is None:
+ self.dep_alias.append ( dep_str )
+
+ self.logger.debug ( "new rule (%s) for %s" % ( self.__class__.__name__, self.resolving_package ) )
+
+ # --- end of __init__ (...) ---
+
+ def done_reading ( self ):
+ self.dep_alias = frozenset ( self.dep_alias )
+ if self.prepare_lowercase_alias:
+ self.dep_alias_low = frozenset ( x.lower() for x in self.dep_alias )
+
+ def add_resolved ( self, dep_str ):
+ """Adds an dependency string that should be matched by this rule.
+
+ arguments:
+ * dep_str --
+ """
+ self.dep_alias.append ( dep_str )
+ # --- end of add_resolved (...) ---
+
+ def _find ( self, dep_str, lowercase ):
+ if lowercase:
+ if hasattr ( self, 'dep_alias_low' ):
+ if dep_str in self.dep_alias_low:
+ return True
+ else:
+ if dep_str in ( alias.lower() for alias in self.dep_alias ):
+ return True
+
+ return dep_str in self.dep_alias
+ # --- end of _find (...) ---
+
+ def matches ( self, dep_env, lowercase=True ):
+ """Returns True if this rule matches the given DepEnv, else False.
+
+ arguments:
+ * dep_env --
+ * lowercase -- if True: be case-insensitive when iterating over all
+ stored dep_strings
+ """
+
+ if self._find (
+ dep_env.dep_str_low if lowercase else dep_env.dep_str, lowercase
+ ):
+ self.logger.debug (
+ "matches %s with score %i and priority %i."
+ % ( dep_env.dep_str, self.max_score, self.priority )
+ )
+ return ( self.max_score, self.resolving_package )
+
+ return None
+ # --- end of matches (...) ---
+
+ def export_rule ( self, resolving_to=None ):
+ """Returns this rule as a list of text lines that can be written into
+ a file.
+ An empty list will be returned if dep_alias has zero length.
+
+ arguments:
+ * resolving_to -- portage package that the exported rule should
+ resolve to, defaults to self.resolving_package or
+ an ignore keyword such as '!'.
+ """
+
+ alias_count = len ( self.dep_alias )
+
+ retlist = []
+
+ if alias_count:
+ if resolving_to is None:
+ if hasattr ( self, 'resolving_package'):
+ resolving_package = self.resolving_package
+ else:
+ resolving_package = '!'
+ else:
+ resolving_package = resolving_to
+
+ # todo hardcoded rule format here
+ if alias_count > 1:
+
+ retlist = [ resolving_package + ' {\n' ] + \
+ [ "\t%s\n" % alias for alias in self.dep_alias ] + \
+ [ '}\n' ]
+ else:
+ retlist = [
+ "%s :: %s\n" % ( resolving_package, self.dep_alias [0] )
+ ]
+
+ # -- if
+
+ return retlist
+ # --- end of export_rule (...) ---
+
+class FuzzySimpleRule ( SimpleRule ):
+
+ def __init__ ( self, *args, **kw ):
+ super ( FuzzySimpleRule, self ) . __init__ ( *args, **kw )
+ self.prepare_lowercase_alias = True
+
+ # 0 : version with modifier, 1 : version w/o mod, 2 : name only, 3 : std
+ self.fuzzy_score = ( 1250, 1000, 750, 500 )
+ self.max_score = max ( self.fuzzy_score )
+
+ def matches ( self, dep_env ):
+ if self._find ( dep_env.dep_str_low, lowercase=True ):
+ # non-fuzzy match
+ self.logger.debug (
+ "matches %s with score %i and priority %i."
+ % ( dep_env.dep_str, self.max_score, self.priority )
+ )
+ return ( self.fuzzy_score[3], self.resolving_package )
+
+ elif hasattr ( dep_env, 'fuzzy' ):
+ for fuzzy in dep_env.fuzzy:
+ if 'name' in fuzzy:
+ if self._find ( fuzzy ['name'], lowercase=True ):
+ # fuzzy match found
+
+ if self.resolving_package is None:
+ # ignore rule
+ res = None
+ score = self.fuzzy_score [2]
+
+
+ elif 'version' in fuzzy:
+
+ ver_pkg = '-'.join ( (
+ self.resolving_package, fuzzy ['version']
+ ) )
+
+ if 'version_modifier' in fuzzy:
+ vmod = fuzzy ['version_modifier']
+ if '!' in vmod:
+ # package matches, but specific version is forbidden
+ # ( !<package>-<specific verion> <package> )
+ res = '( !=%s %s )' % (
+ ver_pkg,
+ self.resolving_package
+ )
+
+ else:
+ # std vmod: >=, <=, =, <, >
+ res = vmod + ver_pkg
+
+ score = self.fuzzy_score[0]
+
+ else:
+ # version required, but no modifier: defaults to '>='
+
+ res = '>=' + ver_pkg
+ score = self.fuzzy_score[1]
+
+ else:
+ # substring match
+ # currently not possible (see DepEnv's regexes)
+ score = fuzzy[2]
+ res = self.resolving_package
+ # --- if resolving... elif version ... else
+
+
+ self.logger.debug (
+ "fuzzy-match: %s resolved as '%s' with score=%i."
+ % ( dep_env.dep_str, res, score )
+ )
+ return ( score, res )
+ # --- if find (=match found)
+ # --- if name in
+ # --- for fuzzy
+ # --- elif hasattr
+
+ return None
+ # --- end of matches (...) ---
+
+
+
diff --git a/roverlay/depres/deprule.py b/roverlay/depres/deprule.py
index b02213c..72e706d 100644
--- a/roverlay/depres/deprule.py
+++ b/roverlay/depres/deprule.py
@@ -16,8 +16,9 @@ class DependencyRule ( object ):
# --- end of __init__ (...) ---
def matches ( self, dep_env ):
- """Returns an int > 0 if this rule matches the given DepEnv."""
- return 0
+ """Returns a tuple ( score ::= int > 0, matching dep ::= str )
+ if this rule matches the given DepEnv, else None"""
+ return None
# --- end of matches (...) ---
# --- end of DependencyRule ---
@@ -97,12 +98,12 @@ class DependencyRulePool ( object ):
order.reverse()
for index in order:
- score = self.rules [index].matches ( dep_env )
- if score:
+ result = self.rules [index].matches ( dep_env )
+ if result is not None and result [0] > 0:
if skipped < skip_matches:
skipped += 1
else:
- return ( score, self.rules [index].get_dep () )
+ return result
return None
diff --git a/roverlay/depres/simpledeprule.py b/roverlay/depres/simpledeprule.py
index ee40045..ce4ba10 100644
--- a/roverlay/depres/simpledeprule.py
+++ b/roverlay/depres/simpledeprule.py
@@ -5,122 +5,23 @@
import re
import logging
+from roverlay import config
from roverlay.depres import deprule
+from roverlay.depres.abstractsimpledeprule import SimpleRule, FuzzySimpleRule
TMP_LOGGER = logging.getLogger ('simpledeps')
-class SimpleIgnoreDependencyRule ( deprule.DependencyRule ):
- """A dependency rule that represents an ignored package in portage."""
-
- def __init__ ( self, dep_str=None, priority=50 ):
- """Initializes a SimpleIgnoreDependencyRule.
-
- arguments:
- * dep_str -- a dependency string that this rule is able to resolve
- * priority -- priority of this rule
- """
- super ( SimpleIgnoreDependencyRule, self ) . __init__ ( priority )
- self.dep_alias = set ()
-
- self.logger = TMP_LOGGER.getChild ( 'IGNORE_DEPS' )
-
- if not dep_str is None:
- self.dep_alias.add ( dep_str )
-
- # --- end of __init__ (...) ---
-
- def add_resolved ( self, dep_str ):
- """Adds an dependency string that should be matched by this rule.
-
- arguments:
- * dep_str --
- """
- self.dep_alias.add ( dep_str )
- # --- end of add_resolved (...) ---
-
- def matches ( self, dep_env, lowercase=True ):
- """Returns True if this rule matches the given DepEnv, else False.
-
- arguments:
- * dep_env --
- * lowercase -- if True: be case-insensitive when iterating over all
- stored dep_strings
- """
-
- def logmatch ( score=self.max_score ):
- """Wrapper function that logs a successful match and
- returns its score.
-
- arguments:
- * score -- score of this match, defaults to self.max_score
- """
-
- self.logger.debug ( "matches %s with score %i and priority %i." %
- ( dep_env.dep_str, score, self.priority )
- )
- return score
- # --- end of logmatch (...) ---
-
- if lowercase:
- #lower_dep_str = dep_env.dep_str.lower()
- for alias in self.dep_alias:
- if alias.lower() == dep_env.dep_str_low:
- return logmatch ()
- elif dep_env.dep_str in self.dep_alias:
- return logmatch ()
-
- return 0
- # --- end of matches (...) ---
-
- def get_dep ( self ):
- """Returns the textual portage package representation of this rule,
- which is None 'cause this is an ignored dependency.
- """
- return None
- # --- end of get_dep (...) ---
-
- def export_rule ( self, resolving_to=None ):
- """Returns this rule as a list of text lines that can be written into
- a file.
- An empty list will be returned if dep_alias has zero length.
-
- arguments:
- * resolving_to -- portage package that the exported rule should
- resolve to, defaults to self.resolving_package or
- an ignore keyword such as '!'.
- """
-
- alias_count = len ( self.dep_alias )
-
- retlist = []
-
- if alias_count:
- if resolving_to is None:
- if hasattr ( self, 'resolving_package'):
- resolving_package = self.resolving_package
- else:
- resolving_package = '!'
- else:
- resolving_package = resolving_to
-
- # todo hardcoded rule format here
- if alias_count > 1:
-
- retlist = [ resolving_package + ' {\n' ] + \
- [ "\t%s\n" % alias for alias in self.dep_alias ] + \
- [ '}\n' ]
- else:
- retlist = [
- "%s :: %s\n" % ( resolving_package, self.dep_alias [0] )
- ]
-
- # -- if
-
- return retlist
- # --- end of export_rule (...) ---
+class SimpleIgnoreDependencyRule ( SimpleRule ):
+ def __init__ ( self, dep_str=None, priority=50, resolving_package=None ):
+ super ( SimpleIgnoreDependencyRule, self ) . __init__ (
+ dep_str=dep_str,
+ priority=priority,
+ resolving_package=None,
+ logger_name = 'IGNORE_DEPS',
+ )
-class SimpleDependencyRule ( SimpleIgnoreDependencyRule ):
+class SimpleDependencyRule ( SimpleRule ):
def __init__ ( self, resolving_package, dep_str=None, priority=70 ):
"""Initializes a SimpleDependencyRule. This is
@@ -132,21 +33,32 @@ class SimpleDependencyRule ( SimpleIgnoreDependencyRule ):
* priority --
"""
super ( SimpleDependencyRule, self ) . __init__ (
- dep_str=dep_str, priority=priority
+ dep_str=dep_str,
+ priority=priority,
+ resolving_package=resolving_package,
+ logger_name=resolving_package
)
- self.resolving_package = resolving_package
+ # --- end of __init__ (...) ---
- self.logger = TMP_LOGGER.getChild ( resolving_package )
+class SimpleFuzzyIgnoreDependencyRule ( FuzzySimpleRule ):
- # --- end of __init__ (...) ---
+ def __init__ ( self, dep_str=None, priority=51, resolving_package=None ):
+ super ( SimpleFuzzyIgnoreDependencyRule, self ) . __init__ (
+ dep_str=dep_str,
+ priority=priority,
+ resolving_package=None,
+ logger_name = 'FUZZY.IGNORE_DEPS',
+ )
- def get_dep ( self ):
- """Returns the textual portage package representation of this rule,
- e.g. 'dev-lang/R'.
- """
- return self.resolving_package
- # --- end of get_dep (...) ---
+class SimpleFuzzyDependencyRule ( FuzzySimpleRule ):
+ def __init__ ( self, resolving_package, dep_str=None, priority=71 ):
+ super ( SimpleFuzzyDependencyRule, self ) . __init__ (
+ dep_str=dep_str,
+ priority=priority,
+ resolving_package=resolving_package,
+ logger_name = 'FUZZY.' + resolving_package,
+ )
class SimpleDependencyRulePool ( deprule.DependencyRulePool ):
@@ -175,7 +87,7 @@ class SimpleDependencyRulePool ( deprule.DependencyRulePool ):
arguments:
* rule --
"""
- if isinstance ( rule, SimpleIgnoreDependencyRule ):
+ if isinstance ( rule, SimpleRule ):
self.rules.append ( rule )
else:
raise Exception ( "bad usage (simple dependency rule expected)." )
@@ -220,8 +132,13 @@ class SimpleDependencyRuleReader ( object ):
multiline_start = '{'
multiline_stop = '}'
comment_chars = "#;"
+
# todo: const/config?
- package_ignore = [ '!' ]
+ package_ignore = '!'
+ fuzzy = '~'
+ fuzzy_ignore = '%'
+
+ BREAK_PARSING = frozenset (( '#! NOPARSE', '#! BREAK' ))
def __init__ ( self ):
@@ -229,6 +146,12 @@ class SimpleDependencyRuleReader ( object ):
pass
# --- end of __init__ (...) ---
+
+ def _make_rule ( self, rule_str ):
+ CLS = self.__class__
+
+
+
def read_file ( self, filepath ):
"""Reads a file that contains simple dependency rules
(SimpleIgnoreDependencyRules/SimpleDependencyRules).
@@ -244,6 +167,8 @@ class SimpleDependencyRuleReader ( object ):
logging.debug ( "Reading simple dependency rule file %s." % filepath )
fh = open ( filepath, 'r' )
+ CLS = self.__class__
+
# the list of read rules
rules = list ()
@@ -258,47 +183,95 @@ class SimpleDependencyRuleReader ( object ):
# empty
pass
+ elif line in CLS.BREAK_PARSING:
+ # stop reading here
+ break
+
elif not next_rule is None:
# in a multiline rule
- if line [0] == SimpleDependencyRuleReader.multiline_stop:
+ if line [0] == CLS.multiline_stop:
# end of a multiline rule,
# add rule to rules and set next_rule to None
+ next_rule.done_reading()
rules.append ( next_rule )
next_rule = None
else:
# new resolved str
next_rule.add_resolved ( line )
- elif line [0] in SimpleDependencyRuleReader.comment_chars:
+ elif line [0] in CLS.comment_chars:
# comment
# it is intented that multi line rules cannot contain comments
pass
- elif line [-1] == SimpleDependencyRuleReader.multiline_start:
+ elif line [-1] == CLS.multiline_start:
# start of a multiline rule
portpkg = line [:-1].rstrip()
- if portpkg in SimpleDependencyRuleReader.package_ignore:
+
+ if portpkg == CLS.fuzzy_ignore:
+ next_rule = SimpleFuzzyIgnoreDependencyRule ( None )
+ elif portpkg == CLS.fuzzy:
+ next_rule = SimpleFuzzyDependencyRule ( portpkg[1:], None )
+ elif portpkg == CLS.package_ignore:
next_rule = SimpleIgnoreDependencyRule ( None, 60 )
else:
next_rule = SimpleDependencyRule ( portpkg, None, 70 )
else:
- # single line rule?
- rule_str = \
- SimpleDependencyRuleReader.one_line_separator.split (line, 1)
+ # single line rule, either selfdep,
+ # e.g. '~zoo' -> fuzzy sci-R/zoo :: zoo
+ # or normal rule 'dev-lang/R :: R'
+ # selfdeps are always single line statements (!)
+ rule_str = CLS.one_line_separator.split (line, 1)
+
+ new_rule = None
+ rule_class = None
+ resolving = None
+
+ first_char = rule_str [0][0] if len ( rule_str [0] ) else ''
+
+ if first_char == CLS.fuzzy:
+ rule_class = SimpleFuzzyDependencyRule
+ resolving = rule_str [0] [1:]
+
+ elif rule_str [0] == CLS.fuzzy_ignore:
+ rule_class = SimpleFuzzyIgnoreDependencyRule
+ resolving = None
+
+ elif rule_str [0] == CLS.package_ignore:
+ rule_class = SimpleIgnoreDependencyRule
+
+ else:
+ rule_class = SimpleDependencyRule
+ resolving = rule_str [0]
if len ( rule_str ) == 2:
- # is a single line rule
-
- if rule_str [0] in SimpleDependencyRuleReader.package_ignore:
- rules.append (
- SimpleIgnoreDependencyRule ( rule_str [1], 40 )
- )
- else:
- rules.append (
- SimpleDependencyRule ( rule_str [0], rule_str [1], 50 )
- )
+ # normal rule
+ new_rule = rule_class (
+ resolving_package=resolving,
+ dep_str=rule_str [1]
+ )
+
+ elif resolving is not None:
+ # selfdep
+ dep_str = resolving
+ resolving = '/'.join ( (
+ config.get_or_fail ( 'OVERLAY.category' ),
+ resolving
+ ) )
+ new_rule = rule_class (
+ resolving_package=resolving,
+ dep_str=dep_str
+ )
+
+ # else: error
+
+
+ if new_rule:
+ new_rule.done_reading()
+ rules.append ( new_rule )
+
else:
logging.error (
"In %s, line %i : cannot use this line." %
@@ -308,6 +281,9 @@ class SimpleDependencyRuleReader ( object ):
if fh: fh.close ()
+ if next_rule is not None:
+ logging.warning ( "Multi line rule does not end at EOF - ignored" )
+
logging.info (
"%s: read %i dependency rules (in %i lines)" %
( filepath, len ( rules ), lineno )
^ permalink raw reply related [relevance 99%]
Results 1-1 of 1 | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2012-06-29 22:48 99% [gentoo-commits] proj/R_overlay:master commit in: roverlay/depres/ André Erdmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox