Add new syntax to allow matching multiple profile
Given the following: package1 [foo bar] package2 [foo (bar baz)] package3 [baz] package4 [(bar baz)] Profile 'foo' will match package1 and package2 Profile 'bar' will match package1 Profile 'baz' will match package3 package4 cannot be match when only declaring a single profile Specifing profiles 'bar baz' will match all four packages Additionally, this relaxes the whitespace around the profiles and groups. Previously while space was allowed after but not before braces. Change-Id: I077943ff52cc8dc2eb6437925f8ca653b3534508
This commit is contained in:
parent
71c58d24c0
commit
24427065c5
15
README.rst
15
README.rst
@ -92,6 +92,12 @@ match on the other selectors. As an example, ``[platform:rpm test]``
|
||||
would only install a package on a RPM platform if the test selector is
|
||||
used.
|
||||
|
||||
Profiles can also be grouped together using ``()``. In a group, all profiles
|
||||
must match for the group to match. Given the example
|
||||
``[test (ceph glance !lvm)]``, to select the package you must either specify
|
||||
``test`` OR (``ceph`` AND ``glance`` AND NOT ``lvm``). Platform selectors will
|
||||
not work inside of the group.
|
||||
|
||||
Version constraints are a comma separated list of constraints where each
|
||||
constraint is (== | < | <= | >= | > | !=) VERSION, and the constraints are ANDed
|
||||
together (the same as pip requirements version constraints).
|
||||
@ -160,3 +166,12 @@ To select the curl package, the OpenStack CI default file uses::
|
||||
|
||||
This selects the ``curl`` package on all distributions with the
|
||||
exception of Gentoo, and selects ``net-misc/curl`` on Gentoo only.
|
||||
|
||||
To select a package based on a group of profiles::
|
||||
|
||||
ceph-common [ceph]
|
||||
python-rbd [(ceph glance)]
|
||||
|
||||
This selects the ``ceph-common`` package when the profile ``ceph`` is
|
||||
specified. However, it will only select the ``python-rbd`` package when both
|
||||
``ceph`` and ``glance`` profiles are active.
|
||||
|
@ -47,7 +47,9 @@ lowercase = ('a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|'i'|'j'|'k'|'l'|'m'|'n'|'o'|'p'
|
||||
name = letterOrDigit:start (letterOrDigit|'.'|'+'|'-'|'_'|'/')+:rest
|
||||
ws = ' '+
|
||||
profile = ('!'?:neg <(lowercase|digit|':'|'-'|'.')+>:name) -> (neg!='!', name)
|
||||
selector = ws '[' profile:p1 (ws profile)*:p2 ']' -> [p1] + p2
|
||||
profiles = '(' (ws? profile)*:p ws? ')' -> p
|
||||
group = profiles | profile
|
||||
selector = ws '[' (ws? group)*:p ws? ']' -> p
|
||||
oneversion = <('<=' | '<' | '!=' | '==' | '>=' | '>')>:rel <debversion>:v -> (
|
||||
rel, v)
|
||||
version = ws oneversion:v1 (',' oneversion)*:v2 -> [v1] + v2
|
||||
@ -138,7 +140,11 @@ class Depends(object):
|
||||
"""
|
||||
platform = []
|
||||
user = []
|
||||
for sense, profile in rule[1]:
|
||||
for group in rule[1]:
|
||||
if isinstance(group, list):
|
||||
user.append(group)
|
||||
continue
|
||||
sense, profile = group
|
||||
if profile.startswith("platform:"):
|
||||
platform.append((sense, profile))
|
||||
else:
|
||||
@ -160,7 +166,15 @@ class Depends(object):
|
||||
positive = False
|
||||
match_found = False
|
||||
negative = False
|
||||
for sense, profile in partition_rule:
|
||||
for group in partition_rule:
|
||||
if isinstance(group, list):
|
||||
if self._match_all(group, profiles):
|
||||
match_found = True
|
||||
continue
|
||||
else:
|
||||
negative = True
|
||||
break
|
||||
sense, profile = group
|
||||
if sense:
|
||||
positive = True
|
||||
if profile in profiles:
|
||||
@ -173,6 +187,19 @@ class Depends(object):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _match_all(self, partition_rules, profiles):
|
||||
"""Evaluate rules. Do they all match the profiles?
|
||||
|
||||
:return Result True if all profiles match else False
|
||||
"""
|
||||
def matches(sense, profile, profiles):
|
||||
return sense if profile in profiles else not sense
|
||||
|
||||
for sense, profile in partition_rules:
|
||||
if not matches(sense, profile, profiles):
|
||||
return False
|
||||
return True
|
||||
|
||||
def active_rules(self, profiles):
|
||||
"""Return the rules active given profiles.
|
||||
|
||||
|
@ -27,7 +27,7 @@ logging.basicConfig(
|
||||
|
||||
|
||||
def main(depends=None):
|
||||
usage = "Usage: %prog [options] [profile]"
|
||||
usage = "Usage: %prog [options] [profile]..."
|
||||
parser = optparse.OptionParser(
|
||||
usage=usage, version="%%prog %s" % bindep.version)
|
||||
parser.add_option(
|
||||
|
@ -236,6 +236,34 @@ class TestDepends(TestCase):
|
||||
[("foo", [(False, "bar"), (True, "baz"), (True, "quux")], [])],
|
||||
depends._rules)
|
||||
|
||||
def test_whitespace(self):
|
||||
depends = Depends("foo [ ( bar !baz ) quux ]\n")
|
||||
self.assertEqual(
|
||||
[("foo", [[(True, "bar"), (False, "baz")], (True, "quux")], [])],
|
||||
depends._rules)
|
||||
|
||||
def test_group_selectors(self):
|
||||
depends = Depends("foo [(bar !baz) quux]\n")
|
||||
self.assertEqual(
|
||||
[("foo", [[(True, "bar"), (False, "baz")], (True, "quux")], [])],
|
||||
depends._rules)
|
||||
|
||||
def test_multiple_group_selectors(self):
|
||||
depends = Depends("foo [(bar baz) (baz quux)]\n")
|
||||
parsed_profiles = [
|
||||
[(True, "bar"), (True, "baz")],
|
||||
[(True, "baz"), (True, "quux")],
|
||||
]
|
||||
self.assertEqual(
|
||||
[("foo", parsed_profiles, [])],
|
||||
depends._rules)
|
||||
|
||||
def test_single_profile_group_selectors(self):
|
||||
depends = Depends("foo [(bar) (!baz)]\n")
|
||||
self.assertEqual(
|
||||
[("foo", [[(True, "bar")], [(False, "baz")]], [])],
|
||||
depends._rules)
|
||||
|
||||
def test_versions(self):
|
||||
depends = Depends("foo <=1,!=2\n")
|
||||
self.assertEqual(
|
||||
|
@ -0,0 +1,9 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
New syntax extention allows declaring a group of profiles which must be
|
||||
specified to enable the package. Using the syntax as follows
|
||||
|
||||
package1 [(profile1 profile2)]
|
||||
|
||||
To install 'package1' you must declare profile1 AND profile2
|
Loading…
x
Reference in New Issue
Block a user