From: "André Erdmann" <dywi@mailerd.de>
To: gentoo-commits@lists.gentoo.org
Subject: [gentoo-commits] proj/R_overlay:wip/addition_control commit in: roverlay/packagerules/generators/
Date: Thu, 17 Jul 2014 20:12:28 +0000 (UTC) [thread overview]
Message-ID: <1405614392.862594b151befc3ac3e1766df370890c8af88470.dywi@gentoo> (raw)
commit: 862594b151befc3ac3e1766df370890c8af88470
Author: André Erdmann <dywi <AT> mailerd <DOT> de>
AuthorDate: Thu Jul 17 16:26:32 2014 +0000
Commit: André Erdmann <dywi <AT> mailerd <DOT> de>
CommitDate: Thu Jul 17 16:26:32 2014 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/R_overlay.git;a=commit;h=862594b1
add-policy rule-gen: implement token generatorion
---
.../packagerules/generators/addition_control.py | 883 +++++++--------------
1 file changed, 279 insertions(+), 604 deletions(-)
diff --git a/roverlay/packagerules/generators/addition_control.py b/roverlay/packagerules/generators/addition_control.py
index 73040e0..7f2cc95 100644
--- a/roverlay/packagerules/generators/addition_control.py
+++ b/roverlay/packagerules/generators/addition_control.py
@@ -1,684 +1,342 @@
-# R overlay -- package rule generators, addition control
+# R overlay -- abstract package rule generators, addition control
# -*- coding: utf-8 -*-
# Copyright (C) 2014 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.
from __future__ import absolute_import
-# temporary_demo_func():
-from __future__ import print_function
import abc
-# __metaclass__/metaclass= workaround
-_AbstractObject = abc.ABCMeta ( str("AbstractObject"), ( object, ), {} )
-
import collections
+import fnmatch
+import re
+
+
+import roverlay.packagerules.generators.abstract.addition_control
-#~ import roverlay.util.fileio
-import roverlay.util.namespace
-#~
import roverlay.packagerules.abstract.acceptors
-import roverlay.packagerules.abstract.rules
-#~ import roverlay.packagerules.acceptors.stringmatch
-#~ import roverlay.packagerules.acceptors.util
-import roverlay.packagerules.acceptors.trivial
-import roverlay.packagerules.actions.addition_control
-#~
-#~ from roverlay.packagerules.abstract.rules import (
- #~ NestedPackageRule, PackageRule
-#~ )
-#~
-#~ from roverlay.packagerules.acceptors.stringmatch (
- #~ NocaseStringAcceptor, StringAcceptor,
- #~ RegexAcceptor, ExactRegexAcceptor
-#~ )
-#~
-#~ from roverlay.packagerules.acceptors.util import (
- #~ get_package, get_package_name, get_ebuild_name, get_category,
- #~ DEFAULT_CATEGORY_REPLACEMENT
-#~ )
-
-import roverlay.overlay.abccontrol
-from roverlay.overlay.abccontrol import AdditionControlResult
-
-
-# converting addition-control lists (cmdline, from file...) to rule objects,
-# hacky solution:
-#
-# ** step 1 ** -- collect category/package tokens, determine bitmask
-#
-# create a dict (
-# category_token|True => package_token|True => bitmask<policy>
-# ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ ^~~~~~~~~~~~~~^
-# "acceptor chain" "add-policy"
-# )
-#
-# "True" means "accept all".
-#
-# make sure that the tokens get de-duped
-# (normalize values, use tuples (or namespace))
-#
-# Only the first and the last step need to know *what* category/package
-# tokens are. All intermediate steps should not need to care about this.
-#
-
-
-
-class AbstractAdditionControlPackageRuleGenerator ( _AbstractObject ):
- """(Abstract) object that takes cmdline/files as input and creates
- add-policy package rules."""
-
- # Note that tokens are not totally abstract,
- # the "match-all" (True) token is hardcoded
-
- #CategoryToken = collections.namedtuple ( 'CategoryToken', '<attr>*' )
- #PackageToken = collections.namedtuple ( 'PackageToken', '<attr>*' )
-
- @abc.abstractmethod
- def category_token_to_acceptor ( self, category_token, priority ):
- """Creates a package rule acceptor for the given category token.
+import roverlay.packagerules.acceptors.stringmatch
+import roverlay.packagerules.acceptors.util
- Returns: not-None acceptor (or nested acceptor)
- Must not return None.
- If a token is meaningless, then don't create it in the first place.
+from roverlay.packagerules.abstract.acceptors import Acceptor_AND
- arguments:
- * category_token -- a category token
- * priority -- priority of the acceptor (int)
- """
- raise NotImplementedError()
- # --- end of category_token_to_acceptor (...) ---
+from roverlay.packagerules.acceptors.stringmatch import (
+ StringAcceptor, ExactRegexAcceptor,
+)
- @abc.abstractmethod
- def package_token_to_acceptor ( self, package_token, priority ):
- """Creates a package rule acceptor for the given package token.
+from roverlay.packagerules.acceptors.util import (
+ get_category, get_ebuild_name, get_ebuild_version_tuple,
+)
- Returns: not-None acceptor (or nested acceptor)
+#import roverlay.util.fileio
+import roverlay.util.namespace
- arguments:
- * package_token -- a package token
- * priority -- priority of the acceptor (int)
- """
- raise NotImplementedError()
- # --- end of package_token_to_acceptor (...) ---
+import roverlay.util.portage_regex.default
+import roverlay.util.portage_regex.wildcard
+from roverlay.util.portage_regex.default import RE_PACKAGE_EBUILD_FILE
+from roverlay.util.portage_regex.wildcard import (
+ RE_WILDCARD_PACKAGE, RE_WILDCARD_CATEGORY
+)
- def create_package_rules ( self, reduced_bitmask_acceptor_chain_map ):
- """Creates a nested add-policy package rule object.
- The rule object's priority has to be set manually afterwards.
-
- Returns: (nested) package rule or None
- """
- # create_package_rules() is defined/implemented below (step 5)
- return create_package_rules (
- reduced_bitmask_acceptor_chain_map,
- convert_category_token_to_acceptor = self.category_token_to_acceptor,
- convert_package_token_to_acceptor = self.package_token_to_acceptor
- )
- # --- end of create_package_rules (...) ---
- def prepare_bitmask_map ( self, acceptor_chain_bitmask_map ):
- """Transforms the given "acceptor chain" -> "bitmask" map into the
- reduced "effective bitmask" -> "acceptor chain" map.
- Note: Involves in-place operations that modify
- acceptor_chain_bitmask_map.
- Pass a copy if the original map should remain unchanged.
- Returns: reduced/optimized "effective bitmask" -> "acceptor chain"
- arguments:
- * acceptor_chain_bitmask_map -- "acceptor chain" -> "bitmask" map
- """
- expand_acceptor_chain_bitmasks ( acceptor_chain_bitmask_map )
- bitmask_acceptor_chain_map = (
- create_bitmask_acceptor_chain_map ( acceptor_chain_bitmask_map )
- )
- reduce_bitmask_acceptor_chain_map ( bitmask_acceptor_chain_map )
- return bitmask_acceptor_chain_map
- # --- end of prepare_bitmask_map (...) ---
- def compile_bitmask_map ( self, acceptor_chain_bitmask_map ):
- """Transforms the given "acceptor chain" -> "bitmask" map into a
- (nested) package rule.
- This is equal to calling
- obj.create_package_rules (
- obj.prepare_bitmask_map ( acceptor_chain_bitmask_map )
- )
+class TokenValueError ( ValueError ):
+ pass
- Returns: (nested) rule object or None
+class InvalidTokenInputString ( TokenValueError ):
+ pass
- arguments:
- * acceptor_chain_bitmask_map -- "acceptor chain" -> "bitmask" map
- """
- return self.create_package_rules (
- prepare_bitmask_map ( acceptor_chain_bitmask_map )
- )
- # --- end of compile_bitmask_map (...) ---
-
-
-# --- end of AbstractAdditionControlPackageRuleGenerator ---
-
-
-#
-# ** step 2 ** -- expand global and category-wide bitmasks,
-# set effective package bitmask
-# (FIXME: does it make sense to apply the global bitmask?)
-#
-# for each category with at least one non-True package_token loop
-# for each package in category loop
-# category->package |= category->True [bitwise-OR]
-# end loop
-# (do not modify category->True, as it applies to packages not matched
-# by any package_token, too)
-# end loop
-#
-# for each category loop
-# for each entry in category loop
-# reduce policy bitmask (keep effective bits only)
-# end loop
-# end loop
-#
-# (merge the two for-loops in code)
-#
-
-def expand_acceptor_chain_bitmasks ( acceptor_chain_bitmask_map ):
- """Expands a "acceptor chain" -> "bitmask" map.
- (Sets the effective bitmask, propagates global bitmasks, ...)
-
- In-place operation that modifies the acceptor_chain_bitmask_map arg.
-
- Returns: None (implicit)
-
- arguments:
- * acceptor_chain_bitmask_map -- "acceptor chain" -> "bitmask" map
- """
- # naming convention: >e<ffective bit>mask< => emask
-
- get_emask = AdditionControlResult.get_effective_package_policy
-
- def normalize_entry ( mapping, key, additional_emask=0 ):
- """Determines and sets the effective bitmask of mapping->key.
-
- Returns: None (implicit)
-
- arguments:
- * mapping -- dict-like object
- * key -- dict key (has to exist)
- * additional_emask -- effective bitmask that should be propagated to
- mapping->key (global/category-wide bitmask)
- """
- new_value = get_emask ( mapping [key] | additional_emask )
- mapping [key] = new_value
- return new_value
- # --- end of normalize_entry (...) ---
-
- def normalize_entry_maybe_missing ( mapping, key, additional_emask=0 ):
- """Like normalize_entry(), but does not require the existence of
- mapping->key (the entry will be created if necessary).
-
- arguments:
- * mapping --
- * key --
- * additional_emask --
- """
- if key in mapping:
- return normalize_entry ( mapping, key, additional_emask )
- else:
- mapping [key] = additional_emask
- return additional_emask
- # --- end of normalize_entry_maybe_missing (...) ---
+class TokenItemNotSupported ( TokenValueError ):
+ pass
- # propagate global/category-wide emask to package_token entries
- # acceptor_chain_bitmask_map->True->True is the global emask
- if True in acceptor_chain_bitmask_map:
- global_emask = normalize_entry_maybe_missing (
- acceptor_chain_bitmask_map [True], True
- )
- else:
- global_emask = 0
- for category_token, package_token_map in acceptor_chain_bitmask_map.items():
- # --- cannot modify acceptor_chain_bitmask_map in this block
- category_emask = normalize_entry_maybe_missing (
- package_token_map, True, global_emask
- )
+class AdditionControlPackageRuleGenerator (
+ roverlay.packagerules.generators.abstract.addition_control.\
+ AbstractAdditionControlPackageRuleGenerator
+):
- for package_token in package_token_map:
- # --- cannot modify acceptor_chain_bitmask_map, package_token_map
- if package_token is not True:
- # else already processed (category_emask)
- normalize_entry (
- package_token_map, package_token, category_emask
- )
- # -- end if <package_token>
- # -- end for <package_token>
-
- # -- end for <category_token,package_token_map>
-
-# --- end of expand_acceptor_chain_bitmasks (...) ---
-
-
-#
-# ** step 3 -- create reversed map **
-#
-# BITMASK_MAP: create a dict (
-# effective_bitmask => category_token|True => set(package_token|True>)
-# ^~~~~~~~~~~~~~~~^ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
-# "add-policy atom" "acceptor chain"
-# )
-#
-#
-# **hacky**:
-# It would be better to split effective_bitmask into its components
-# (2**k for k in ...), but this requires path compaction.
-# Not implemented. (graph/spanning-tree and/or logic minimization)
-#
-
-def create_bitmask_acceptor_chain_map ( acceptor_chain_bitmask_map ):
- """Transforms a "acceptor chain" -> "[effective] bitmask" map
- into a "[effective] bitmask" -> "acceptor chain" mask without applying
- any optimization/reduction steps.
-
- Returns: "[effective] bitmask" -> "acceptor chain" map
-
- arguments:
- * acceptor_chain_bitmask_map -- "acceptor chain" -> "bitmask" map
- Should be in expanded form
- (expand_acceptor_chain_bitmasks())
- """
- bitmask_acceptor_chain_map = {}
+ #TOKEN_ITEM_IS_SPECIAL = 0 ## implicit
+ TOKEN_ITEM_IS_STR = 1
+ TOKEN_ITEM_IS_REGEX = 2
- for category_token, package_token_map in acceptor_chain_bitmask_map.items():
+ TokenItemTuple = collections.namedtuple (
+ "TokenItemTuple", "item_type value"
+ )
- for package_token, emask in package_token_map.items():
- try:
- emask_entry = bitmask_acceptor_chain_map [emask]
- except KeyError:
- bitmask_acceptor_chain_map [emask] = {
- category_token: set ({ package_token, })
- }
- else:
- try:
- category_entry = emask_entry [category_token]
- except KeyError:
- emask_entry [category_token] = set ({ package_token, })
- else:
- category_entry.add ( package_token )
- # -- end for <package token map>
-
- # -- end for <category token map>
-
- return bitmask_acceptor_chain_map
-# --- end of create_bitmask_acceptor_chain_map (...) ---
-
-
-#
-# ** step 4 -- naive path compaction **
-# (Keep in mind that acceptor tokens cannot be merged with match-all)
-#
-# reduce acceptor chains (drop-superseeded):
-# for each effective_bitmask b in BITMASK_MAP loop
-# if BITMASK_MAP->b->True->True exists then
-# drop all other entries from BITMASK_MAP->b
-# else
-# for each category in BITMASK_MAP->b loop
-# if category->True exists then
-# drop all other entries from category
-# end if
-# end loop
-# end if
-# end loop
-#
-# (optional: drop overlapping acceptor chains, e.g. regex ".*" is equal
-# to True and therefore all other entries in the regex' branch can be
-# removed)
-#
-#
-# merge-bitmask: (OPTIONAL / NOT IMPLEMENTED)
-# (bitwise-OR effective_bitmasks with identical acceptor chains)
-#
-# *could* create a large table
-# <add-policy atom X category/package> => bool
-# (where category, package can also be "accept-all")
-#
-#
-# +-----------------+-------+-------+-----+-------+-------+-----+-------+
-# | add-policy atom | c0/p0 | c0/p1 | ... | c0/pM | c1/p0 | ... | cN/pJ |
-# +=================+=======+=======+=====+=======+=======+=====+=======+
-# | 2**0 | 0|1 | 0|1 | ... | 0|1 | 0|1 | ... | 0|1 |
-# +-----------------+-------+-------+-----+-------+-------+-----+-------+
-# | ... | ... | ... | ... | ... | ... | ... | ... |
-# +-----------------+-------+-------+-----+-------+-------+-----+-------+
-# | 2**k | 0|1 | 0|1 | ... | 0|1 | 0|1 | ... | 0|1 |
-# +-----------------+-------+-------+-----+-------+-------+-----+-------+
-#
-# ++ reduce table
-#
-
-def reduce_bitmask_acceptor_chain_map ( bitmask_acceptor_chain_map ):
- """Reduces/Optimizes a "effective bitmask" -> "acceptor chain" map.
-
- In-place operation, the bitmask_acceptor_chain_map will be modified.
-
- Returns: None (implicit)
-
- arguments:
- * bitmask_acceptor_chain_map -- "effective bitmask" -> "acceptor chain" map
-
- Implementation detail:
- The reduced map uses empty sets/dicts for representing "match-all"
- acceptors.
- """
+ # PackageToken: tuple ( None|$PN, None|$PV, None|$PR )
+ # (revision not implemented because it cannot be matched in package rules
+ # -- always 0)
+ # condition: not all ( item is None for item in <PackageToken> )
+ # and all not-None items must evaluate to True
+ # <=> any ( <PackageToken> )
+ #
+ PackageToken = collections.namedtuple ( 'PackageToken', 'name version' )
- # could be integrated in create_bitmask_acceptor_chain_map(),
- # but kept separate for better readability
+ # CategoryToken: tuple ( $CATEGORY )
+ # same conditions as for PackageToken apply,
+ # which effectively means that $CATEGORY must a non-empty str
#
+ CategoryToken = collections.namedtuple ( 'CategoryToken', 'name' )
- # emask==0 can be ignored
- bitmask_acceptor_chain_map.pop ( 0, True )
-
- for emask in bitmask_acceptor_chain_map:
- emask_matches_all = False
-
- for category_token, package_token_set in (
- bitmask_acceptor_chain_map [emask].items()
- ):
- if True not in package_token_set:
- # category~DONT_CARE, package!=True <=> keep entries
- pass
- elif category_token is True:
- # category==True, package==True <=> match all, *** BREAK LOOP ***
- emask_matches_all = True
- break
- else:
- # category!=True, package==True <=> match entire category
- package_token_set.clear()
- # -- end for <category->package token map>
-
- if emask_matches_all:
- bitmask_acceptor_chain_map [emask].clear()
- # -- end for <emask>
-# --- end of reduce_bitmask_acceptor_chain_map (...) ---
-
-
-#
-# ** step 5 -- convert the acceptor chains to objects **
-#
-# the final BITMASK_MAP can be easily translated into rule objects:
-#
-# * convert the the effective bitmask into one or more
-# PackageAdditionControl*Actions
-#
-# * an OR<category OR<packages>> match statement
-# represents the acceptor chain
-# (reduce properly, e.g. "accept-all" entries)
-#
-#
-# ** done **
-#
-
-def create_packagerule_action_map():
- """Helper function that creates all add-policy package rule actions.
-
- Returns: dict ( "bitmask atom" (2**k) -> "package rule action" )
-
- arguments: None
- """
- return {
- action_cls.CONTROL_RESULT: action_cls (
- priority=action_cls.CONTROL_RESULT
- )
- for action_cls in (
- getattr (
- roverlay.packagerules.actions.addition_control,
- action_cls_name
- ) for action_cls_name in (
- roverlay.packagerules.actions.addition_control.ACTIONS
- )
- ) if action_cls.CONTROL_RESULT
- }
-# --- end of create_packagerule_action_map (...) ---
+ def create_token_item_from_str ( self, s ):
+ get_obj = self.namespace.get_object_v
-def create_package_rules (
- reduced_bitmask_acceptor_chain_map,
- convert_category_token_to_acceptor,
- convert_package_token_to_acceptor
-):
- """Converts the given "effective bitmask" -> "acceptor chain" map
- into a nested package rule.
-
- Returns: (nested) package rule or None
-
- arguments:
- * reduced_bitmask_acceptor_chain_map -- reduced/optimized
- "bitmask" -> "acceptor chain" map
- * convert_category_token_to_acceptor -- function(token,priority)
- -> category acceptor
- * convert_package_token_to_acceptor -- function(token,priority)
- -> package acceptor
- """
- packagerule_actions = create_packagerule_action_map()
- # true acceptor with priority -1
- always_true_acceptor = (
- roverlay.packagerules.acceptors.trivial.TrueAcceptor ( priority=-1 )
- )
+ if not s:
+ return None
+ elif any ( char in "?*" for char in s ):
+ s_stripped = s.strip("*")
+ if not s_stripped or (
+ s_stripped == "?" and s_stripped != s
+ ):
+ # "****", "?*", "*?", ... => match all
+ return True
- def get_acceptor_recursive ( category_token_map, priority ):
- """
- Creates a (possibly nested) acceptor for the given category_token_map.
-
- Returns: not-None acceptor
-
- arguments:
- * category_token_map -- "category token" -> "package token" map
- ("acceptor chain")
- * priority -- "recommended" priority of the acceptor
- Ignored when returning an always-true acceptor.
- """
-
- # Note: it's illegal to set an acceptor's priority after its creation
- # this would violate namespace->get_object()
- # ==> use 0 as priority for objects where it doesn't matter much
- # (at the cost of unstable-sorted output)
- #
- # The acceptor gets wrapped with an Acceptor_AND object anyway(*),
- # no need to set any priority.
- # (*) "the top-level logic of a MATCH-block is AND by convention"
- # the acceptor returned by get_*acceptor*() can be of *any*
- # type, but its str representation (--print-package-rules)
- # would always be the same.
- #
- # ["proper" prio-setting is already implemented at
- # package/category acceptor level, so the outmost AND acceptor
- # has exactly one member and the member's priority matches
- # the acceptor's]
- #
-
- def get_package_acceptor ( package_tokens, prio ):
- """Creates a (nested) acceptor for the given non-empty iterable
- of package tokens.
-
- Returns: not-None acceptor
-
- arguments:
- * package_tokens -- iterable of package tokens (not empty)
- * prio -- advised priority of the top-most acceptor
- (the object being returned)
- """
- if not package_tokens:
- raise ValueError ( "package token set must not be empty!" )
-
- elif len(package_tokens) == 1:
- # special case: bind prio to package_acceptor
- return convert_package_token_to_acceptor (
- next(iter(package_tokens)), prio
+ else:
+ return get_obj (
+ self.__class__.TokenItemTuple,
+ (
+ self.__class__.TOKEN_ITEM_IS_REGEX,
+ get_obj ( fnmatch.translate, ( s, ) )
+ )
)
- else:
- package_acceptors = [
- convert_package_token_to_acceptor ( package_token, 0 )
- for package_token in package_tokens
- ]
+ else:
+ return get_obj (
+ self.__class__.TokenItemTuple,
+ ( self.__class__.TOKEN_ITEM_IS_STR, s )
+ )
+ # --- end of create_token_item_from_str (...) ---
+
+ def validate_token ( self, package_token ):
+ all_none = True
+ any_nonspecial = False
+
+ for item in package_token:
+ if item:
+ all_none = False
+ if item is not True:
+ any_nonspecial = True
+ # -- end for
+
+ if all_none:
+ assert not any_nonspecial
+ return None
+ elif any_nonspecial:
+ return package_token
+ else:
+ # FIXME: remove assert
+ assert all ( item in ( True, None ) for item in package_token ), package_token
+ return True
+ # --- end of validate_token (...) ---
+
+ def _create_package_token ( self, name_str, version_str, revision_str ):
+ if revision_str:
+ raise TokenItemNotSupported (
+ "revision {!s}".format ( revision_str )
+ )
- # package acceptors get ORed, no need to set a specific priority
- combined_acceptor = (
- roverlay.packagerules.abstract.acceptors.Acceptor_OR ( prio )
- )
+ package_token = self.namespace.get_object_v (
+ self.__class__.PackageToken,
+ (
+ self.create_token_item_from_str ( name_str ),
+ self.create_token_item_from_str ( version_str ),
+## self.create_token_item_from_str ( revision_str ),
+ )
+ )
- for package_acceptor in package_acceptors:
- combined_acceptor.add_acceptor ( package_acceptor )
+ return self.validate_token ( package_token )
+ # --- end of _create_package_token (...) ---
- return combined_acceptor
+ def _create_category_token ( self, category_str ):
+ category_token = self.namespace.get_object_v (
+ self.__class__.CategoryToken,
+ (
+ self.create_token_item_from_str ( category_str ),
+ )
+ )
- # --- end of get_package_acceptor (...) ---
+ return self.validate_token ( category_token )
+ # --- end of _create_category_token (...) ---
+
+ def create_category_token ( self, input_str ):
+ # input_str doesn't need much parsing,
+ # not using RE_WILDCARD_CATEGORY for now
+## re_match = RE_WILDCARD_CATEGORY.match ( input_str )
+## if not re_match:
+## raise InvalidTokenInputString ( input_str )
+##
+## match_vars = re_match.groupdict()
+##
+## if not match_vars ['CATEGORY']:
+## raise InvalidTokenInputString ( input_str )
+
+ if not input_str:
+ raise InvalidTokenInputString ( input_str )
+ else:
+ return self._create_category_token ( input_str )
+ # --- end of create_category_token (...) ---
- def get_category_acceptor ( category_token, package_tokens, prio ):
- """Creates a nested acceptor for the given category token and its
- package tokens.
- Returns: not-None acceptor
+ def create_token (
+ self, input_str, with_category=True, package_regex=RE_WILDCARD_PACKAGE
+ ):
+ re_match = package_regex.match ( input_str )
- arguments:
- * category_token -- category token (True or non-empty)
- * package_tokens -- iterable of package tokens (can be empty)
- """
+ if not re_match:
+ raise InvalidTokenInputString (
+ "{!s}: not matched by regex".format ( input_str )
+ )
- if category_token is True:
- return get_package_acceptor ( package_tokens, prio )
+ match_vars = re_match.groupdict()
- elif package_tokens:
- acceptor = (
- roverlay.packagerules.abstract.acceptors.Acceptor_AND ( prio )
- )
- # match category first and then packages
- acceptor.add_acceptor (
- convert_category_token_to_acceptor ( category_token, 0 )
- )
- acceptor.add_acceptor (
- get_package_acceptor ( package_tokens, 1 )
- )
+ package_token = self._create_package_token (
+ match_vars ['PN'], match_vars ['PV'], match_vars ['revision']
+ )
- return acceptor
+ if not package_token:
+ raise InvalidTokenInputString ( input_str )
- else:
- return convert_category_token_to_acceptor ( category_token, prio )
- # --- end of get_category_acceptor (...) ---
-
- if not category_token_map:
- # match-all
- return always_true_acceptor
-
- elif len(category_token_map) == 1:
- # special case: bind priority to entry
- category_acceptor = None
- for category_token, package_tokens in category_token_map.items():
- if category_acceptor is None:
- category_acceptor = get_category_acceptor (
- category_token, package_tokens, priority
- )
- else:
- raise AssertionError ( "must not loop more than once." )
- # -- end for
- return category_acceptor
+ if with_category:
+ category_token = self._create_category_token (
+ match_vars ['CATEGORY']
+ )
- else:
- acceptors = [
- get_category_acceptor ( category_token, package_tokens, k )
- for ( k, ( category_token, package_tokens ) ) in enumerate (
- category_token_map.items()
+ if not category_token:
+ if match_vars ['CATEGORY']:
+ raise InvalidTokenInputString (
+ "{!s}: invalid category str {!s}".format (
+ input_str, match_vars ['CATEGORY']
+ )
)
- ]
+ # --
- combined_acceptor = (
- roverlay.packagerules.abstract.acceptors.Acceptor_OR ( priority )
+ # => match-all
+ category_token = True
+ # -- end if
+
+ return ( category_token, package_token )
+
+ elif match_vars ['CATEGORY']:
+ raise InvalidTokenInputString (
+ "{!s}: must not contain CATEGORY".format ( input_str )
)
+ else:
+ return package_token
+ # --- end of create_token (...) ---
- for acceptor in acceptors:
- combined_acceptor.add_acceptor ( acceptor )
+ def create_token_for_ebuild_filepath ( self, efile ):
+ return self.create_token (
+ efile, with_category=True, package_regex=RE_PACKAGE_EBUILD_FILE
+ )
+ # --- end of create_token_for_ebuild_filepath (...) ---
- return combined_acceptor
+ def create_package_token ( self, input_str ):
+ return self.create_token ( input_str, with_category=False )
+ # --- end of create_package_token (...) ---
- # --- end of get_acceptor_recursive (...) ---
- def create_rule ( category_token_map, emask ):
- """Creates a package rule for the given acceptor chain
- ("category token" -> "package tokens" map)
+ def __init__ ( self, default_category ):
+ super ( AdditionControlPackageRuleGenerator, self ).__init__()
+ self.namespace = roverlay.util.namespace.SimpleNamespace()
- Returns: not-None not-nested package rule (with a nested match block)
+ def clear_object_cache ( self ):
+ if self.namespace:
+ self.namespace.zap(True)
+ # --- end of clear_object_cache (...) ---
- arguments:
- * category_token_map -- acceptor chain
- * emask -- effective bitmask that gets translated into
- its corresponding package rule actions
- """
+ def __del__ ( self ):
+ try:
+ self.clear_object_cache()
+ except NotImplementedError:
+ pass
- # wrap actual acceptor with Acceptor_AND, see above
- actual_acceptor = get_acceptor_recursive ( category_token_map, 0 )
- and_acceptor = roverlay.packagerules.abstract.acceptors.Acceptor_AND (0)
- and_acceptor.add_acceptor ( actual_acceptor )
+ def token_item_to_acceptor ( self, token_item, value_getter, priority ):
+ if token_item in ( True, None ):
+ # should be catched elsewhere
+ return None
- rule = roverlay.packagerules.abstract.rules.PackageRule ( priority=emask )
+ elif token_item.item_type == self.__class__.TOKEN_ITEM_IS_STR:
+ acceptor_cls = StringAcceptor
- rule.set_acceptor ( and_acceptor )
- have_any_action = False
- for k, action in packagerule_actions.items():
- have_any_action = True
- if ( k & emask ):
- rule.add_action ( action )
+ elif token_item.item_type == self.__class__.TOKEN_ITEM_IS_REGEX:
+ acceptor_cls = ExactRegexAcceptor
- if not have_any_action:
+ else:
raise AssertionError (
- "rule object has no actions - bad emask? {:#x}".format (
- emask=emask
- )
+ "invalid token item type: {!s}".format ( token_item.item_type )
)
+ # -- end if
- return rule
- # --- end of create_rule (...) ---
-
- rules = [
- create_rule ( category_token_map, emask )
- for emask, category_token_map in \
- reduced_bitmask_acceptor_chain_map.items()
- ]
+ return self.namespace.get_object_v (
+ acceptor_cls, ( priority, value_getter, token_item.value )
+ )
+ # --- end of token_item_to_acceptor (...) ---
- if not rules:
- return None
+ def category_token_to_acceptor ( self, category_token, priority ):
+ if category_token is True:
+ raise Exception ( "C-TRUE" )
- elif len(rules) == 1:
- rules [0].priority = -1
- return rules [0]
- else:
- combined_rule = roverlay.packagerules.abstract.rules.NestedPackageRule (
- priority = -1
+ return self.token_item_to_acceptor (
+ category_token.name, get_category, priority
)
- combined_rule.set_acceptor ( always_true_acceptor )
+ # --- end of category_token_to_acceptor (...) ---
- for rule in rules:
- combined_rule.add_rule ( rule )
+ def package_token_to_acceptor ( self, package_token, priority ):
+ if package_token is True:
+ raise Exception ( "P-TRUE" )
+ else:
+ relevant_items = [
+ item_and_getter for item_and_getter in zip (
+ package_token,
+ (
+ get_ebuild_name,
+ get_ebuild_version_tuple
+ )
+ ) if item_and_getter[0] and item_and_getter[0] is not True
+ ]
- return combined_rule
- # -- end if
+ if not relevant_items:
+ raise TokenValueError ( package_token )
+
+ elif len(relevant_items) == 1:
+ return self.token_item_to_acceptor (
+ relevant_items[0][0], relevant_items[0][1], priority
+ )
+ else:
+ sub_acceptors = [
+ self.token_item_to_acceptor ( item, getter, 0 )
+ for item, getter in relevant_items
+ ]
+
+ combined_acceptor = Acceptor_AND ( priority=priority )
+ for sub_acceptor in sub_acceptors:
+ combined_acceptor.add_acceptor ( sub_acceptor )
+
+ return combined_acceptor
+ # --- end of package_token_to_acceptor (...) ---
-# --- end of create_package_rules (...) ---
class SillyAdditionControlPackageRuleGenerator (
- AbstractAdditionControlPackageRuleGenerator
+ roverlay.packagerules.generators.abstract.addition_control.\
+ AbstractAdditionControlPackageRuleGenerator
):
"""
An add-policy package rule generator that doesn't care about its tokens.
@@ -705,41 +363,53 @@ class SillyAdditionControlPackageRuleGenerator (
def temporary_demo_func():
- rule_generator = SillyAdditionControlPackageRuleGenerator()
+ #rule_generator = SillyAdditionControlPackageRuleGenerator()
+ ARES = AdditionControlResult
+ rule_generator = AdditionControlPackageRuleGenerator("sci-R")
+ CTOKEN = rule_generator.create_category_token
+ PTOKEN = rule_generator.create_package_token
add_control_rule = None
bitmask_acceptor_chain_map = None
acceptor_chain_bitmask_map = {
- True: {
- True: AdditionControlResult.PKG_REVBUMP_ON_COLLISION,
- 'p0': 8|2,
+ CTOKEN ( "sys-*" ): {
+ PTOKEN ( "a*-2" ): ARES.PKG_FORCE_DENY,
+ },
+ CTOKEN ( "*" ): {
+ PTOKEN ( "?*" ): ARES.PKG_REVBUMP_ON_COLLISION,
+ PTOKEN ( 'p0' ): ARES.PKG_FORCE_DENY|ARES.PKG_FORCE_REPLACE,
},
- 'c': {
- True: 2,
+ CTOKEN ( 'c' ): {
+ PTOKEN ( "***?****" ): ARES.PKG_FORCE_DENY,
},
- 'd': {
- True: AdditionControlResult.PKG_REPLACE_ONLY,
+ CTOKEN ( 'd' ): {
+ PTOKEN ( "*" ): ARES.PKG_REPLACE_ONLY,
},
- 'f': {
- 'p1': AdditionControlResult.PKG_REPLACE_ONLY,
+ CTOKEN ( 'f' ): {
+ PTOKEN ( 'p1' ): ARES.PKG_REPLACE_ONLY,
+ PTOKEN ( 'p1-5.0' ): ARES.PKG_REPLACE_ONLY,
},
}
+
print ( "** initial acceptor_chain -> raw_bitmask map" )
print ( acceptor_chain_bitmask_map )
print()
+ roverlay.packagerules.generators.abstract.addition_control.\
expand_acceptor_chain_bitmasks ( acceptor_chain_bitmask_map )
print ( "** expanded acceptor_chain -> effective_bitmask map" )
print ( acceptor_chain_bitmask_map )
print()
bitmask_acceptor_chain_map = (
+ roverlay.packagerules.generators.abstract.addition_control.\
create_bitmask_acceptor_chain_map ( acceptor_chain_bitmask_map )
)
print ( "** initial effective_bitmask -> acceptor_chain map" )
print(bitmask_acceptor_chain_map)
print()
+ roverlay.packagerules.generators.abstract.addition_control.\
reduce_bitmask_acceptor_chain_map ( bitmask_acceptor_chain_map )
print ( "** reduced effective_bitmask -> acceptor_chain map" )
print(bitmask_acceptor_chain_map)
@@ -758,12 +428,17 @@ def temporary_demo_func():
print ( "** content of the rule generator\'s namespace" )
print ( rule_generator.namespace._objects )
+ print ( "** content of the rule generator\'s namespace after clear-cache" )
+ rule_generator.clear_object_cache()
+ print ( rule_generator.namespace._objects )
+
# --- end of temporary_demo_func (...) ---
if __name__ == '__main__':
import sys
import os
+ from roverlay.overlay.abccontrol import AdditionControlResult
try:
temporary_demo_func()
next reply other threads:[~2014-07-17 20:12 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-17 20:12 André Erdmann [this message]
-- strict thread matches above, loose matches on Subject: below --
2014-07-18 16:20 [gentoo-commits] proj/R_overlay:master commit in: roverlay/packagerules/generators/ André Erdmann
2014-07-18 2:28 ` [gentoo-commits] proj/R_overlay:wip/addition_control " André Erdmann
2014-07-18 2:50 André Erdmann
2014-07-18 2:28 André Erdmann
2014-07-17 20:12 André Erdmann
2014-07-17 20:12 André Erdmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1405614392.862594b151befc3ac3e1766df370890c8af88470.dywi@gentoo \
--to=dywi@mailerd.de \
--cc=gentoo-commits@lists.gentoo.org \
--cc=gentoo-dev@lists.gentoo.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox