Merge pull request #43 from Enlik/nonregex-dep-rewrite

Simpler dependency rewrite syntax
This commit is contained in:
Enlik
2018-04-05 21:23:17 +02:00
committed by GitHub
4 changed files with 518 additions and 38 deletions
@@ -10,6 +10,8 @@
# AND or OR operators: ( app-foo/bar & foo-app/rab ) | app-nice/woot
# Please take this into consideration when writing dep rewrites.
# 1. Regex-based dependency rewrite syntax.
# LINE CONSTRUCTION:
# <::pkg::> <::dep_pattern::> <::dep_replace_1::> [<::dep_replace_2::> ...]
# ::pkg:: = package containing dependency to match, or * for catch-all
@@ -59,3 +61,25 @@
# Apply a dep_rewrite rule to any package being added:
# * <::dep_pattern::> <::dep_replace_1::> [<::dep_replace_2::> ...]
# In other words, set <::pkg::> to *
# 2. Token-based dependency rewrite syntax.
# This syntax supports only modification to dependencies, not addition nor removal.
# rewrite <::pkg::> <::rule::>
# where <::pkg::> is matched the same was as explained above,
# and <::rule::> is:
# <from-dep=::dep_atom::> <to-dep=::new_dep_atom::>
# [<if-dep-has-use=::use_to_match::>] [<drop-use=::use_to_remove::>]
# (order does not matter).
#
# To a dependency to be rewritten, ::dep_atom:: must match and ::use_to_match:: if present.
# Dependency will be rewritten as ::new_dep_atom::.
# If present in rule, ::use_to_remove:: will be removed if dependency contains it.
#
# ::dep_atom:: and ::new_dep_atom:: are category/package names, without version, slot etc.
# ::use_to_remove:: can be an asterisk (*) which means to remove all USE flags.
#
# EXAMPLE
# rewrite foo/bar from-dep=app-crypt/pinentry to-dep=app-crypt/pinentry-gtk2 if-dep-has-use=gtk drop-use=gtk
# will change foo/bar's dependency "app-crypt/pinentry[gtk,qt5]" to "app-crypt/pinentry-gtk2[qt5]".
+139 -1
View File
@@ -3,8 +3,9 @@
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@author: Slawomir Nizio <slawomir.nizio@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@copyright: Fabio Erculiani, Slawomir Nizio
@license: GPL-2
B{Entropy dependency functions module}.
@@ -1241,3 +1242,140 @@ def expand_dependencies(dependencies, entropy_repository_list,
pkg_deps.append((dep, dep_type))
return pkg_deps
class WrongRewriteRuleError(Exception):
"""
Exception thrown when the new dep_rewrite mechanism encounters a badly
formatted rule.
"""
pass
class DependencyRewriter(object):
"""
Class that implements the new dependency rewrite schema.
It is simpler to use but less powerful than the regex based one, so the two
are complementary.
"""
_use_in_depstring_re = re.compile(r"\[([^\]]+)\]")
def __init__(self, deps, rule):
self.deps = deps
self._rule = rule
self._rule_dict = self._get_rewrite_rules_dict(rule)
self.matched = None
self.changed = None
self._dep_has_use, self._modify_use = self._setup_default_funcs()
@staticmethod
def _get_rewrite_rules_dict(rule):
known_rule_keys = set(["if-dep-has-use", "from-dep", "to-dep", "drop-use"])
mandatory_keys = set(["from-dep", "to-dep"])
rule_dict = {}
for rule_word in rule.split():
try:
op, arg = rule_word.split("=", 1)
except ValueError:
raise WrongRewriteRuleError("Badly formatted line with '%s'" % (rule_word,))
rule_dict[op] = arg
if op not in known_rule_keys:
raise WrongRewriteRuleError("Bad key '%s'" % (op,))
missing_keys = mandatory_keys - set(rule_dict.keys())
if missing_keys:
raise WrongRewriteRuleError("Incomplete rewrite rule")
return rule_dict
def _setup_default_funcs(self):
if 'if-dep-has-use' in self._rule_dict:
dep_has_use_func = lambda deps_: self._rule_dict['if-dep-has-use'] in deps_
else:
dep_has_use_func = lambda _: True
if 'drop-use' in self._rule_dict:
if self._rule_dict['drop-use'] == "*":
modify_use_func = lambda dep_postfix, use_flags_list, clean_use_flags_list: \
DependencyRewriter._use_in_depstring_re.sub(
"",
dep_postfix,
count=1)
else:
modify_use_func = lambda dep_postfix, use_flags_list, clean_use_flags_list: \
DependencyRewriter._use_in_depstring_re.sub(
self._filter_use(use_flags_list, clean_use_flags_list, self._rule_dict['drop-use']),
dep_postfix,
count=1)
else:
modify_use_func = lambda dep_postfix, _1, _2: dep_postfix
return dep_has_use_func, modify_use_func
@staticmethod
def _filter_use(use_list, clean_use_list, use_to_remove):
filtered_use = []
for orig_use, clean_use in zip(use_list, clean_use_list):
if clean_use != use_to_remove:
filtered_use.append(orig_use)
if filtered_use:
result = "[%s]" % (",".join(filtered_use),)
else:
result = ""
return result
def rewrite(self):
"""
Do a rewrite of dependencies and set attributes: self.deps (rewritten
dependencies), self.matched (any dependency matched its prerequisites)
and self.changed (at least one dependency was modifed).
Value of these attributes is not defined before executing this method.
"""
matched = False
changed = False
new_deps = []
for dep in self.deps:
clean_dep = dep_getkey(dep)
dep_prefix, dep_postfix = dep.split(clean_dep, 1)
use_flags_list, clean_use_flags_list = self._use_flags_from_dep(dep_postfix)
if self._rule_dict['from-dep'] == clean_dep and self._dep_has_use(clean_use_flags_list):
new_dep = dep_prefix + self._rule_dict['to-dep'] + self._modify_use(dep_postfix, use_flags_list, clean_use_flags_list)
new_deps.append(new_dep)
matched = True
if dep != new_dep:
changed = True
else:
new_deps.append(dep)
self.matched = matched
self.changed = changed
self.deps = new_deps
@staticmethod
def _use_flags_from_dep(depstring):
dep_use_match = DependencyRewriter._use_in_depstring_re.search(depstring)
usestring = dep_use_match.group(1) if dep_use_match else ""
dep_use = usestring.split(",")
clean_dep_use = []
use_postfixes_to_strip = ("?", "(-)", "(+)")
for raw_dep in dep_use:
for use_postfix_to_strip in use_postfixes_to_strip:
if raw_dep.endswith(use_postfix_to_strip):
raw_dep = raw_dep[:-len(use_postfix_to_strip)]
clean_dep_use += [raw_dep]
assert len(dep_use) == len(clean_dep_use)
return dep_use, clean_dep_use
+105 -37
View File
@@ -2,8 +2,9 @@
"""
@author: Fabio Erculiani <lxnay@sabayon.org>
@author: Slawomir Nizio <slawomir.nizio@sabayon.org>
@contact: lxnay@sabayon.org
@copyright: Fabio Erculiani
@copyright: Fabio Erculiani, Slawomir Nizio
@license: GPL-2
B{Entropy Package Manager Server Main Interfaces}.
@@ -984,16 +985,83 @@ class ServerSystemSettingsPlugin(SystemSettingsPlugin):
if cached is not None:
return cached
data = {}
data = []
rewrite_file = Server._get_conf_dep_rewrite_file()
if not os.path.isfile(rewrite_file):
return data
rewrite_content = self.__generic_parser(rewrite_file)
def add_dep_handler(dep_pattern):
metadata = {'dep_pattern_str': dep_pattern,
'replaces_str': _("added"),
'action': "add",
'add_what': dep_pattern}
return metadata
def remove_dep_handler(dep_pattern, compiled_pattern):
metadata = {'dep_pattern_str': dep_pattern,
'replaces_str': _("removed"),
'action': "remove",
'does_dep_match_func': lambda dep_string: compiled_pattern.match(dep_string) is not None,
'replaces': []}
return metadata
def replace_dep_handler(dep_pattern, compiled_pattern, replaces):
def _do(replace, dep_string):
new_dep_string, number_of_subs_made = \
compiled_pattern.subn(replace, dep_string)
return new_dep_string, bool(number_of_subs_made)
metadata = {'dep_pattern_str': dep_pattern,
'replaces_str': "=> " + ', '.join(replaces),
'action': "replace",
'does_dep_match_func': lambda dep_string: compiled_pattern.match(dep_string) is not None,
'replaces': replaces,
'do_func': _do}
return metadata
def new_replace_dep_handler(rule):
def _do(_unused, dep_string):
try:
# Should not actually happen as it's tested with does_dep_match_func.
rewriter = entropy.dep.DependencyRewriter([dep_string], rule)
except entropy.dep.WrongRewriteRuleError:
return dep_string, False
rewriter.rewrite()
return rewriter.deps[0], rewriter.changed
def _does_dep_match(dep_string):
try:
rewriter = entropy.dep.DependencyRewriter([dep_string], rule)
except entropy.dep.WrongRewriteRuleError:
return False
rewriter.rewrite()
return rewriter.matched
metadata = {'dep_pattern_str': "rewrite",
# not translated to match the keyword in configuration
'replaces_str': "~> %s" % (rule,),
'action': "replace",
'does_dep_match_func': _does_dep_match,
'replaces': [rule],
'do_func': _do}
return metadata
for line in rewrite_content:
params = line.split()
if len(params) < 2:
continue
if params[0] == "rewrite":
if len(params) < 3:
continue
_unused, pkg_match, rule = line.split(None, 2)
metadata = new_replace_dep_handler(rule)
data.append((pkg_match, metadata))
continue
pkg_match, pattern, replaces = params[0], params[1], params[2:]
if pattern.startswith("++"):
compiled_pattern = None
@@ -1007,8 +1075,18 @@ class ServerSystemSettingsPlugin(SystemSettingsPlugin):
except re.error:
# invalid pattern
continue
if compiled_pattern is None:
# this means that user is asking to add dep_pattern
# as a dependency to package
metadata = add_dep_handler(pattern)
elif not replaces:
# this means that user is asking to remove dep_pattern
metadata = remove_dep_handler(pattern, compiled_pattern)
else:
metadata = replace_dep_handler(pattern, compiled_pattern, replaces)
# use this key to make sure to not overwrite similar entries
data[(pkg_match, pattern)] = (compiled_pattern, replaces)
data.append((pkg_match, metadata))
self._mod_rewrite_data = data
return data
@@ -7357,7 +7435,7 @@ class Server(Client):
rewrites_enabled = []
wildcard_rewrite = False
for dep_string_rewrite, dep_pattern in dep_rewrite:
for dep_string_rewrite, handler in dep_rewrite:
# magic catch-all support
if dep_string_rewrite == "*":
pkg_id, rc = None, 0
@@ -7366,7 +7444,7 @@ class Server(Client):
wildcard_rewrite = False
pkg_id, rc = tmp_repo.atomMatch(dep_string_rewrite)
if rc == 0:
rewrites_enabled.append((dep_string_rewrite, dep_pattern))
rewrites_enabled.append((dep_string_rewrite, handler))
tmp_repo.close()
if not rewrites_enabled:
@@ -7384,22 +7462,11 @@ class Server(Client):
level = "info",
header = brown(" @@ ")
)
for dep_string_rewrite, dep_pattern in rewrites_enabled:
compiled_pattern, replaces = \
dep_rewrite[(dep_string_rewrite, dep_pattern)]
if compiled_pattern is None:
# this means that user is asking to add dep_pattern
# as a dependency to package
replaces_str = _("added")
elif not replaces:
# this means that user is asking to remove dep_pattern
replaces_str = _("removed")
else:
replaces_str = "=> " + ', '.join(replaces)
for dep_string_rewrite, handler in rewrites_enabled:
self.output(
"%s %s" % (
purple(dep_pattern),
replaces_str,
purple(handler['dep_pattern_str']),
handler['replaces_str'],
),
importance = 1,
level = "info",
@@ -7457,17 +7524,19 @@ class Server(Client):
for dep_string, dep_value, is_conflict in pkg_deps:
dep_string_matched = False
dep_changed = False
matched_pattern = False
for key in rewrites_enabled:
for dep_string_rewrite, handler in rewrites_enabled:
dep_string_rewrite, dep_pattern = key
compiled_pattern, replaces = dep_rewrite[key]
if compiled_pattern is None:
# user is asking to add dep_pattern to dependency list
action = handler['action']
assert action in ("add", "remove", "replace")
if action == "add":
# user is asking to add a dependency to dependency list
dep_pattern_string, dep_pattern_type, conflict = \
_extract_dep_add_from_dep_pattern(dep_pattern)
_extract_dep_add_from_dep_pattern(handler['add_what'])
if conflict:
conflicts.add(dep_pattern_string)
else:
@@ -7475,20 +7544,19 @@ class Server(Client):
(dep_pattern_string, dep_pattern_type))
continue
if not compiled_pattern.match(dep_string):
if not handler['does_dep_match_func'](dep_string):
# dep_string not matched, skipping
continue
matched_pattern = True
if not replaces:
# then it's a removal
dep_string_matched = True
if action == "remove":
dep_changed = True
for replace in replaces:
new_dep_string, number_of_subs_made = \
compiled_pattern.subn(replace, dep_string)
if number_of_subs_made:
dep_string_matched = True
for replace in handler['replaces']:
new_dep_string, subst_made = \
handler['do_func'](replace, dep_string)
if subst_made:
dep_changed = True
if new_dep_string and (new_dep_string != "-"):
if is_conflict:
@@ -7529,13 +7597,13 @@ class Server(Client):
header = darkred(" !!! ")
)
if dep_string_matched:
if dep_changed:
if is_conflict:
remove_conflicts.add(dep_string)
else:
remove_dependencies.add(dep_string)
elif (not dep_string_matched) and matched_pattern:
elif (not dep_changed) and matched_pattern:
self.output(
"%s: %s :: %s" % (
darkred(_("No dependency rewrite made for")),
+250
View File
@@ -7,6 +7,7 @@ import unittest
from entropy.const import const_convert_to_rawstring, const_convert_to_unicode
from entropy.output import print_generic
import tests._misc as _misc
import itertools
import tempfile
import subprocess
import shutil
@@ -285,6 +286,255 @@ class DepTest(unittest.TestCase):
outcome = et.get_entropy_package_sha1(name)
self.assertEqual(outcome, expected_outcome)
class DepsRewriteTestsMixin:
def _validate(self):
rewriter = et.DependencyRewriter(self._deps, self._rule)
rewriter.rewrite()
self.assertEqual(rewriter.deps, self._expected_deps)
class MatchedChangedTestsMixin:
def _validate(self):
rewriter = et.DependencyRewriter(self._deps, self._rule)
rewriter.rewrite()
self.assertEqual(rewriter.matched, self._expected_matched)
self.assertEqual(rewriter.changed, self._expected_changed)
class DependencyRewriterTests(unittest.TestCase, DepsRewriteTestsMixin):
# Test for the new rewrite rules without regexes.
def test_dep_changed(self):
# inspired by:
# foo/bar (.*)app-text/poppler(.*)(\[.*\]) \1app-text/poppler-glib\2
self._rule = "from-dep=app-text/poppler to-dep=app-text/poppler-glib"
self._deps = ["app-text/poppler"]
self._expected_deps = ["app-text/poppler-glib"]
self._validate()
def _test_dep_changed_pkg_data_stays(self, dep_matches):
prefixes = ("", "=", ">=", "<", "~")
postfixes = ("", ":3", "[some]", "[some,use]", ":4[use]")
rule = "from-dep=app-text/poppler to-dep=app-text/poppler-glib"
if dep_matches:
dep_base = "app-text/poppler"
expected_base = "app-text/poppler-glib"
else:
dep_base = "foobar"
expected_base = dep_base
for prefix, postfix in itertools.product(prefixes, postfixes):
self._rule = rule
self._deps = [prefix + dep_base + postfix]
self._expected_deps = [prefix + expected_base + postfix]
self._validate()
def test_dep_changed_pkg_data_stays(self):
self._test_dep_changed_pkg_data_stays(dep_matches=True)
def test_dep_with_pkg_data_dep_not_matched(self):
self._test_dep_changed_pkg_data_stays(dep_matches=False)
def test_dep_changed_version_stays(self):
self._rule = "from-dep=app-text/poppler to-dep=app-text/poppler-glib"
self._deps = ["=app-text/poppler-10"]
self._expected_deps = ["=app-text/poppler-glib-10"]
self._validate()
def test_version_dep_not_matched(self):
self._rule = "from-dep=app-text/poppler to-dep=app-text/poppler-glib"
self._deps = ["=app-text/not-poppler-10"]
self._expected_deps = ["=app-text/not-poppler-10"]
self._validate()
def test_version_and_data_matches(self):
self._rule = "from-dep=app-text/poppler to-dep=app-text/poppler-glib"
self._deps = ["=app-text/poppler-10:3[use]"]
self._expected_deps = ["=app-text/poppler-glib-10:3[use]"]
self._validate()
def test_version_and_data_not_matches(self):
self._rule = "from-dep=app-text/poppler to-dep=app-text/poppler-glib"
self._deps = ["=app-text/not-poppler-10:3[use]"]
self._expected_deps = ["=app-text/not-poppler-10:3[use]"]
self._validate()
def test_more_deps_one_changed(self):
self._rule = "from-dep=app-text/poppler to-dep=app-text/poppler-glib"
self._deps = ["d1", "app-text/poppler", "d2"]
self._expected_deps = ["d1", "app-text/poppler-glib", "d2"]
self._validate()
def test_dep_not_changed_dep_not_matched(self):
self._rule = "from-dep=app-text/poppler-not to-dep=app-text/poppler-glib"
self._deps = ["app-text/poppler"]
self._expected_deps = ["app-text/poppler"]
self._validate()
def test_more_deps_none_changed_dep_not_matched(self):
self._rule = "from-dep=app-text/poppler-not to-dep=app-text/poppler-glib"
self._deps = ["d1", "app-text/poppler", "d2"]
self._expected_deps = ["d1", "app-text/poppler", "d2"]
self._validate()
def _test_with_if_has_use(self, dep_use, rule_use, dep_use_matches):
assert dep_use.startswith("[") or not dep_use
if dep_use_matches:
expected_dep_base = "x11-misc/lightdm-qt4"
else:
expected_dep_base = "x11-misc/lightdm"
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4 if-dep-has-use=%s" % (rule_use,)
self._deps = ["x11-misc/lightdm"+dep_use]
self._expected_deps = [expected_dep_base+dep_use]
self._validate()
def test_with_if_has_use_matched(self):
self._test_with_if_has_use(dep_use="[qt4]", rule_use="qt4", dep_use_matches=True)
def test_with_if_has_use_matched_complex(self):
use_list = ("[qt4,qt5]", "[qt4?,qt5]", "[qt4(-)]", "[qt4(+)]")
for use in use_list:
self._test_with_if_has_use(dep_use=use, rule_use="qt4", dep_use_matches=True)
def test_with_if_has_use_not_matched_no_use(self):
self._test_with_if_has_use(dep_use="", rule_use="qt4", dep_use_matches=False)
def test_with_if_has_use_not_matched_different_use(self):
self._test_with_if_has_use(dep_use="[not-qt4]", rule_use="qt4", dep_use_matches=False)
def test_with_if_has_use_not_matched_different_use_complex(self):
self._test_with_if_has_use(dep_use="[qt4]", rule_use="not-qt4", dep_use_matches=False)
# There is no necessity to handle [-use(-)].
self._test_with_if_has_use(dep_use="[-qt4]", rule_use="qt4", dep_use_matches=False)
use_list = ("[qt4,qt5]", "[qt4?,qt5]", "[qt4(-)]", "[qt4(+)]")
for use in use_list:
self._test_with_if_has_use(dep_use=use, rule_use="not-qt4", dep_use_matches=False)
def test_with_if_has_use_and_drop_use(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4 if-dep-has-use=qt4 drop-use=qt4"
self._deps = ["x11-misc/lightdm[qt4]"]
self._expected_deps = ["x11-misc/lightdm-qt4"]
self._validate()
def test_with_if_has_use_and_drop_use_more_deps(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4 if-dep-has-use=qt4 drop-use=qt4"
self._deps = ["x11-misc/lightdm[qt4,something-else]"]
self._expected_deps = ["x11-misc/lightdm-qt4[something-else]"]
self._validate()
def test_with_if_has_use_and_drop_use_complex(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4 if-dep-has-use=qt4 drop-use=qt4"
self._deps = ["x11-misc/lightdm[qt4(-),something-else(+)]"]
self._expected_deps = ["x11-misc/lightdm-qt4[something-else(+)]"]
self._validate()
def test_with_if_has_use_and_drop_use_no_dropped_use_match(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4 if-dep-has-use=qt4 drop-use=something"
self._deps = ["x11-misc/lightdm[qt4]"]
self._expected_deps = ["x11-misc/lightdm-qt4[qt4]"]
self._validate()
def test_without_if_has_use_but_with_drop_use(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt5 drop-use=qt4"
self._deps = ["x11-misc/lightdm[qt4]"]
self._expected_deps = ["x11-misc/lightdm-qt5"]
self._validate()
def test_with_drop_use_asterisk(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt5 drop-use=*"
self._deps = ["x11-misc/lightdm[qt4?,qt5]"]
self._expected_deps = ["x11-misc/lightdm-qt5"]
self._validate()
def test_with_drop_use_asterisk_and_no_use_in_dep(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt5 drop-use=*"
self._deps = ["x11-misc/lightdm"]
self._expected_deps = ["x11-misc/lightdm-qt5"]
self._validate()
def test_raises_on_unknown_key(self):
rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4 haha=true"
deps = ["x11-misc/lightdm"]
with self.assertRaisesRegexp(et.WrongRewriteRuleError, r"^Bad key 'haha'"):
et.DependencyRewriter(deps, rule)
def test_raises_on_missing_key(self):
rule_parts = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4".split()
deps = []
for rule in rule_parts:
with self.assertRaisesRegexp(et.WrongRewriteRuleError, r"Incomplete rewrite rule"):
et.DependencyRewriter(deps, rule)
def test_raises_on_key_with_no_assignment(self):
wrong_values = ("if-has-use", "drop-use", "haha")
for value in wrong_values:
rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt4 %s" % (value,)
deps = ["x11-misc/lightdm"]
with self.assertRaisesRegexp(et.WrongRewriteRuleError,
r"^Badly formatted line with '%s'" % (value,)):
et.DependencyRewriter(deps, rule)
def test_with_empty_deps(self):
self._rule = "from-dep=app-text/poppler to-dep=app-text/poppler-glib"
self._deps = []
self._expected_deps = []
self._validate()
class DependencyRewriterBasicAttrsTests(unittest.TestCase, MatchedChangedTestsMixin):
def test_matched_and_changed(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt5 drop-use=qt4"
self._deps = ["x11-misc/lightdm[qt4]"]
self._expected_matched = True
self._expected_changed = True
self._validate()
def test_not_matched_and_not_changed_dep_mismatch(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt5 drop-use=qt4"
self._deps = ["something-else/lightdm[qt4]"]
self._expected_matched = False
self._expected_changed = False
self._validate()
def test_not_matched_and_not_changed_use_mismatch(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm-qt5 if-dep-has-use=qt4"
self._deps = ["x11-misc/lightdm[not-qt4]"]
self._expected_matched = False
self._expected_changed = False
self._validate()
def test_matched_and_not_changed(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm if-dep-has-use=qt4"
self._deps = ["x11-misc/lightdm[qt4]"]
self._expected_matched = True
self._expected_changed = False
self._validate()
def test_with_empty_deps(self):
self._rule = "from-dep=app-text/poppler to-dep=app-text/poppler-glib"
self._deps = []
self._expected_matched = False
self._expected_changed = False
self._validate()
def test_matched_and_changed_with_use_asterisk(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm drop-use=*"
self._deps = ["x11-misc/lightdm[gtk]"]
self._expected_matched = True
self._expected_changed = True
self._validate()
def test_matched_and_not_changed_with_use_asterisk(self):
self._rule = "from-dep=x11-misc/lightdm to-dep=x11-misc/lightdm drop-use=*"
self._deps = ["x11-misc/lightdm"]
self._expected_matched = True
self._expected_changed = False
self._validate()
if __name__ == '__main__':
unittest.main()
raise SystemExit(0)