public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* [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