commit 4268288f669be5e023be2a53477caa81a95d4244
parent 6b27485f8e6a1ef3bc904db5ea47e01a4051ffa6
Author: KatolaZ <katolaz@freaknet.org>
Date:   Sun, 24 Jun 2018 12:39:20 +0200
Implement dependency alternatives parsing.
This commit adds support for parsing dependencies which contain
alternatives, e.g. "foo | bar".
Currently it is utilized for banning packages.
Diffstat:
3 files changed, 56 insertions(+), 26 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -1,6 +1,6 @@
 Copyright (c) 2017 Merlijn Wajer <merlijn@wizzup.org>
 Copyright (c) 2017 Evilham <devuan@evilham.com>
-Copyright (c) 2017 KatolaZ <katolaz@freaknet.org>
+Copyright (c) 2017-2018 KatolaZ <katolaz@freaknet.org>
 Copyright (c) 2017-2018 Ivan J. <parazyd@dyne.org>
 
                     GNU AFFERO GENERAL PUBLIC LICENSE
diff --git a/lib/package.py b/lib/package.py
@@ -75,6 +75,33 @@ def load_packages_file(filename):
     return None
 
 
+def depends_on_all_banned(deps, banned_pkgs):
+    """
+    Gets a list of dicts of dep alternatives and a set of banned packages and
+    returns True if any of the dicts consist exclusively of banned_pkgs.
+    """
+    for dep in deps:
+        alt = set(dep.keys())
+        if len(alt.intersection(banned_pkgs)) == len(alt):
+            # All the alternatives are banned
+            return True
+    return False
+
+
+def depends_on(deps, package_set):
+    """
+    Gets a list of dicts of dep alternatives and a set of packages and returns
+    True if any of the dicts include at least one of the elements in
+    package_set.
+    """
+    for dep in deps:
+        alt = set(dep.keys())
+        if alt.intersection(package_set):
+            # At least one alternative is in package_set
+            return True
+    return False
+
+
 def package_banned(pkg, banned_pkgs):
     """
     Returns True is the package contains a banned dependency.
@@ -89,19 +116,17 @@ def package_banned(pkg, banned_pkgs):
     depends = parse_dependencies(pkg.get('Depends', ''))
     pre_depends = parse_dependencies(pkg.get('Pre-Depends', ''))
 
-    depends = [v for v in depends]
-    pre_depends = [v for v in pre_depends]
-
-    deps = set(depends).union(set(pre_depends))
+    depends.extend(pre_depends)
 
-    if 'libsystemd0' in deps:
+    if depends_on(depends, set(['libsystemd0'])):
         logtofile('libsystemd.txt', '%s,%s\n' % (globalvars.suite,
                                                  pkg.get('Package')))
 
-    if bool(deps.intersection(banned_pkgs)):
+    isbanned = depends_on_all_banned(depends, banned_pkgs)
+    if isbanned:
         logtofile('bannedpackages.txt', '%s,%s\n' % (globalvars.suite,
                                                      pkg.get('Package')))
-    return bool(deps.intersection(banned_pkgs))
+    return isbanned
 
 
 def package_newer(pkg1, pkg2):
diff --git a/lib/parse.py b/lib/parse.py
@@ -127,28 +127,33 @@ def parse_dependencies(dependencies):
 
     Example line::
 
-        'lib6 (>= 2.4), libdbus-1-3 (>= 1.0.2), foo'
+        'lib6 (>= 2.4), libdbus-1-3 (>= 1.0.2), foo | bar (>= 4.5.6)'
 
     Output::
 
-        {'lib6': '(>= 2.4)', 'libdbus-1-3': '(>= 1.0.2)', 'foo': None}
-    """
-    ret = {}
-
-    for pkg_plus_version in dependencies.split(', '):
-        ver = pkg_plus_version.split(' ', 1)
-        name = ver[0]
-
-        # If we get passed an empty string, the name is '', and we just
-        # outright stop
-        if not name:
-            return {}
+        A list of dep alternatives, whose elements are dicts, in the form:
 
-        if len(ver) == 2:
-            version = ver[1]
-            ret[name] = version
-        else:
-            ret[name] = None
+        [{'lib6': '(>= 2.4)'}, {'libdbus-1-3': '(>= 1.0.2)'},
+         {'foo': None, 'bar': '(>= 4.5.6)'}]
+    """
+    ret = []
+
+    for alternatives in dependencies.split(', '):
+        depset = {}
+        for pkg_plus_version in alternatives.split('|'):
+            ver = pkg_plus_version.strip(' ').split(' ', 1)
+            name = ver[0]
+
+            # If we get passed an empty string, the name is '', and we just
+            # outright stop.
+            if not name:
+                return []
+            if len(ver) == 2:
+                version = ver[1]
+                depset[name] = version
+            else:
+                depset[name] = None
+        ret.append(depset)
 
     return ret