From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from pigeon.gentoo.org ([208.92.234.80] helo=lists.gentoo.org) by finch.gentoo.org with esmtp (Exim 4.60) (envelope-from ) id 1Skk06-0000sW-Lz for garchives@archives.gentoo.org; Fri, 29 Jun 2012 22:49:19 +0000 Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id BA390E082D; Fri, 29 Jun 2012 22:48:26 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) by pigeon.gentoo.org (Postfix) with ESMTP id 7A9B1E07E4 for ; Fri, 29 Jun 2012 22:48:26 +0000 (UTC) Received: from hornbill.gentoo.org (hornbill.gentoo.org [94.100.119.163]) (using TLSv1 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id B34F91B4029 for ; Fri, 29 Jun 2012 22:48:25 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by hornbill.gentoo.org (Postfix) with ESMTP id E2417E5435 for ; Fri, 29 Jun 2012 22:48:22 +0000 (UTC) From: "André Erdmann" To: gentoo-commits@lists.gentoo.org Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "André Erdmann" Message-ID: <1341009393.f4fe2f55298624cd522b554aa57b505591a4138a.dywi@gentoo> Subject: [gentoo-commits] proj/R_overlay:master commit in: roverlay/depres/ X-VCS-Repository: proj/R_overlay X-VCS-Files: roverlay/depres/abstractsimpledeprule.py roverlay/depres/deprule.py roverlay/depres/simpledeprule.py X-VCS-Directories: roverlay/depres/ X-VCS-Committer: dywi X-VCS-Committer-Name: André Erdmann X-VCS-Revision: f4fe2f55298624cd522b554aa57b505591a4138a X-VCS-Branch: master Date: Fri, 29 Jun 2012 22:48:22 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: quoted-printable X-Archives-Salt: 5388f043-5675-4e84-bd88-f2f16cfda53d X-Archives-Hash: 1ca7cb53edd5f5b7fa9b4904808dd5d2 commit: f4fe2f55298624cd522b554aa57b505591a4138a Author: Andr=C3=A9 Erdmann mailerd de> AuthorDate: Fri Jun 29 22:36:33 2012 +0000 Commit: Andr=C3=A9 Erdmann mailerd de> CommitDate: Fri Jun 29 22:36:33 2012 +0000 URL: http://git.overlays.gentoo.org/gitweb/?p=3Dproj/R_overlay.git= ;a=3Dcommit;h=3Df4fe2f55 dependency resolution: 'fuzzy' rules These extended simple rules match various dependency strings with a single rule, e.g. a fuzzy "R" rule matches "R (>=3D 2.10)" as ">=3Ddev-lang/R-2.10" and "R <2.15" as " 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/a= bstractsimpledeprule.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 =3D logging.getLogger ('simpledeps') + +class SimpleRule ( deprule.DependencyRule ): + """A dependency rule that represents an ignored package in portage.""" + + def __init__ ( self, + dep_str=3DNone, priority=3D50, resolving_package=3DNone, + logger_name=3D'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 =3D list() + + self.logger =3D TMP_LOGGER.getChild ( logger_name ) + + self.resolving_package =3D resolving_package + + self.prepare_lowercase_alias =3D 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 =3D frozenset ( self.dep_alias ) + if self.prepare_lowercase_alias: + self.dep_alias_low =3D 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=3DTrue ): + """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=3DNone ): + """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 =3D len ( self.dep_alias ) + + retlist =3D [] + + if alias_count: + if resolving_to is None: + if hasattr ( self, 'resolving_package'): + resolving_package =3D self.resolving_package + else: + resolving_package =3D '!' + else: + resolving_package =3D resolving_to + + # todo hardcoded rule format here + if alias_count > 1: + + retlist =3D [ resolving_package + ' {\n' ] + \ + [ "\t%s\n" % alias for alias in self.dep_alias ] + \ + [ '}\n' ] + else: + retlist =3D [ + "%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 =3D True + + # 0 : version with modifier, 1 : version w/o mod, 2 : name only, 3 : s= td + self.fuzzy_score =3D ( 1250, 1000, 750, 500 ) + self.max_score =3D max ( self.fuzzy_score ) + + def matches ( self, dep_env ): + if self._find ( dep_env.dep_str_low, lowercase=3DTrue ): + # 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=3DTrue ): + # fuzzy match found + + if self.resolving_package is None: + # ignore rule + res =3D None + score =3D self.fuzzy_score [2] + + + elif 'version' in fuzzy: + + ver_pkg =3D '-'.join ( ( + self.resolving_package, fuzzy ['version'] + ) ) + + if 'version_modifier' in fuzzy: + vmod =3D fuzzy ['version_modifier'] + if '!' in vmod: + # package matches, but specific version is forbidden + # ( !- ) + res =3D '( !=3D%s %s )' % ( + ver_pkg, + self.resolving_package + ) + + else: + # std vmod: >=3D, <=3D, =3D, <, > + res =3D vmod + ver_pkg + + score =3D self.fuzzy_score[0] + + else: + # version required, but no modifier: defaults to '>=3D' + + res =3D '>=3D' + ver_pkg + score =3D self.fuzzy_score[1] + + else: + # substring match + # currently not possible (see DepEnv's regexes) + score =3D fuzzy[2] + res =3D self.resolving_package + # --- if resolving... elif version ... else + + + self.logger.debug ( + "fuzzy-match: %s resolved as '%s' with score=3D%i." + % ( dep_env.dep_str, res, score ) + ) + return ( score, res ) + # --- if find (=3Dmatch 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__ (...) --- =20 def matches ( self, dep_env ): - """Returns an int > 0 if this rule matches the given DepEnv.""" - return 0 + """Returns a tuple ( score ::=3D int > 0, matching dep ::=3D str ) + if this rule matches the given DepEnv, else None""" + return None # --- end of matches (...) --- =20 # --- end of DependencyRule --- @@ -97,12 +98,12 @@ class DependencyRulePool ( object ): order.reverse() =20 for index in order: - score =3D self.rules [index].matches ( dep_env ) - if score: + result =3D self.rules [index].matches ( dep_env ) + if result is not None and result [0] > 0: if skipped < skip_matches: skipped +=3D 1 else: - return ( score, self.rules [index].get_dep () ) + return result =20 =20 return None diff --git a/roverlay/depres/simpledeprule.py b/roverlay/depres/simpledep= rule.py index ee40045..ce4ba10 100644 --- a/roverlay/depres/simpledeprule.py +++ b/roverlay/depres/simpledeprule.py @@ -5,122 +5,23 @@ import re import logging =20 +from roverlay import config from roverlay.depres import deprule +from roverlay.depres.abstractsimpledeprule import SimpleRule, FuzzySimpl= eRule =20 TMP_LOGGER =3D logging.getLogger ('simpledeps') =20 -class SimpleIgnoreDependencyRule ( deprule.DependencyRule ): - """A dependency rule that represents an ignored package in portage.""" - - def __init__ ( self, dep_str=3DNone, priority=3D50 ): - """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 =3D set () - - self.logger =3D 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=3DTrue ): - """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=3Dself.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 =3D dep_env.dep_str.lower() - for alias in self.dep_alias: - if alias.lower() =3D=3D 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=3DNone ): - """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 =3D len ( self.dep_alias ) - - retlist =3D [] - - if alias_count: - if resolving_to is None: - if hasattr ( self, 'resolving_package'): - resolving_package =3D self.resolving_package - else: - resolving_package =3D '!' - else: - resolving_package =3D resolving_to - - # todo hardcoded rule format here - if alias_count > 1: - - retlist =3D [ resolving_package + ' {\n' ] + \ - [ "\t%s\n" % alias for alias in self.dep_alias ] + \ - [ '}\n' ] - else: - retlist =3D [ - "%s :: %s\n" % ( resolving_package, self.dep_alias [0] ) - ] - - # -- if - - return retlist - # --- end of export_rule (...) --- +class SimpleIgnoreDependencyRule ( SimpleRule ): =20 + def __init__ ( self, dep_str=3DNone, priority=3D50, resolving_package=3D= None ): + super ( SimpleIgnoreDependencyRule, self ) . __init__ ( + dep_str=3Ddep_str, + priority=3Dpriority, + resolving_package=3DNone, + logger_name =3D 'IGNORE_DEPS', + ) =20 -class SimpleDependencyRule ( SimpleIgnoreDependencyRule ): +class SimpleDependencyRule ( SimpleRule ): =20 def __init__ ( self, resolving_package, dep_str=3DNone, priority=3D70 )= : """Initializes a SimpleDependencyRule. This is @@ -132,21 +33,32 @@ class SimpleDependencyRule ( SimpleIgnoreDependencyR= ule ): * priority -- """ super ( SimpleDependencyRule, self ) . __init__ ( - dep_str=3Ddep_str, priority=3Dpriority + dep_str=3Ddep_str, + priority=3Dpriority, + resolving_package=3Dresolving_package, + logger_name=3Dresolving_package ) =20 - self.resolving_package =3D resolving_package + # --- end of __init__ (...) --- =20 - self.logger =3D TMP_LOGGER.getChild ( resolving_package ) +class SimpleFuzzyIgnoreDependencyRule ( FuzzySimpleRule ): =20 - # --- end of __init__ (...) --- + def __init__ ( self, dep_str=3DNone, priority=3D51, resolving_package=3D= None ): + super ( SimpleFuzzyIgnoreDependencyRule, self ) . __init__ ( + dep_str=3Ddep_str, + priority=3Dpriority, + resolving_package=3DNone, + logger_name =3D 'FUZZY.IGNORE_DEPS', + ) =20 - 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=3DNone, priority=3D71 )= : + super ( SimpleFuzzyDependencyRule, self ) . __init__ ( + dep_str=3Ddep_str, + priority=3Dpriority, + resolving_package=3Dresolving_package, + logger_name =3D 'FUZZY.' + resolving_package, + ) =20 =20 class SimpleDependencyRulePool ( deprule.DependencyRulePool ): @@ -175,7 +87,7 @@ class SimpleDependencyRulePool ( deprule.DependencyRul= ePool ): 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 =3D '{' multiline_stop =3D '}' comment_chars =3D "#;" + # todo: const/config? - package_ignore =3D [ '!' ] + package_ignore =3D '!' + fuzzy =3D '~' + fuzzy_ignore =3D '%' + + BREAK_PARSING =3D frozenset (( '#! NOPARSE', '#! BREAK' )) =20 =20 def __init__ ( self ): @@ -229,6 +146,12 @@ class SimpleDependencyRuleReader ( object ): pass # --- end of __init__ (...) --- =20 + + def _make_rule ( self, rule_str ): + CLS =3D 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 =3D open ( filepath, 'r' ) =20 + CLS =3D self.__class__ + # the list of read rules rules =3D list () =20 @@ -258,47 +183,95 @@ class SimpleDependencyRuleReader ( object ): # empty pass =20 + elif line in CLS.BREAK_PARSING: + # stop reading here + break + elif not next_rule is None: # in a multiline rule =20 - if line [0] =3D=3D SimpleDependencyRuleReader.multiline_stop: + if line [0] =3D=3D 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 =3D None else: # new resolved str next_rule.add_resolved ( line ) =20 - 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 =20 - elif line [-1] =3D=3D SimpleDependencyRuleReader.multiline_start: + elif line [-1] =3D=3D CLS.multiline_start: # start of a multiline rule portpkg =3D line [:-1].rstrip() - if portpkg in SimpleDependencyRuleReader.package_ignore: + + if portpkg =3D=3D CLS.fuzzy_ignore: + next_rule =3D SimpleFuzzyIgnoreDependencyRule ( None ) + elif portpkg =3D=3D CLS.fuzzy: + next_rule =3D SimpleFuzzyDependencyRule ( portpkg[1:], None ) + elif portpkg =3D=3D CLS.package_ignore: next_rule =3D SimpleIgnoreDependencyRule ( None, 60 ) else: next_rule =3D SimpleDependencyRule ( portpkg, None, 70 ) =20 else: - # single line rule? - rule_str =3D \ - 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 =3D CLS.one_line_separator.split (line, 1) + + new_rule =3D None + rule_class =3D None + resolving =3D None + + first_char =3D rule_str [0][0] if len ( rule_str [0] ) else '' + + if first_char =3D=3D CLS.fuzzy: + rule_class =3D SimpleFuzzyDependencyRule + resolving =3D rule_str [0] [1:] + + elif rule_str [0] =3D=3D CLS.fuzzy_ignore: + rule_class =3D SimpleFuzzyIgnoreDependencyRule + resolving =3D None + + elif rule_str [0] =3D=3D CLS.package_ignore: + rule_class =3D SimpleIgnoreDependencyRule + + else: + rule_class =3D SimpleDependencyRule + resolving =3D rule_str [0] =20 if len ( rule_str ) =3D=3D 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 =3D rule_class ( + resolving_package=3Dresolving, + dep_str=3Drule_str [1] + ) + + elif resolving is not None: + # selfdep + dep_str =3D resolving + resolving =3D '/'.join ( ( + config.get_or_fail ( 'OVERLAY.category' ), + resolving + ) ) + new_rule =3D rule_class ( + resolving_package=3Dresolving, + dep_str=3Ddep_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 ): =20 if fh: fh.close () =20 + 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 )