diff --git a/britney.py b/britney.py index aa376c4..9cdb539 100755 --- a/britney.py +++ b/britney.py @@ -213,7 +213,7 @@ from britney2.utils import (old_libraries_format, undo_changes, create_provides_map, read_release_file, read_sources_file, get_dependency_solvers, invalidate_excuses, compile_nuninst, - ensuredir, + ensuredir, get_component, allowed_component, ) __author__ = 'Fabio Tranchitella and the Debian Release Team' @@ -1102,11 +1102,16 @@ class Britney(object): return True is_all_ok = True + # Don't check components when testing PPAs, as they do not have this concept + if self.options.adt_ppas: + component = None + else: + component = get_component(binary_u.section) # for every dependency block (formed as conjunction of disjunction) for block, block_txt in zip(parse_depends(deps), deps.split(',')): # if the block is satisfied in testing, then skip the block - packages = get_dependency_solvers(block, binaries_t_a, provides_t_a) + packages = get_dependency_solvers(block, binaries_t_a, provides_t_a, component=component) if packages: for p in packages: if p not in binaries_s_a: @@ -1115,7 +1120,7 @@ class Britney(object): continue # check if the block can be satisfied in the source suite, and list the solving packages - packages = get_dependency_solvers(block, binaries_s_a, provides_s_a) + packages = get_dependency_solvers(block, binaries_s_a, provides_s_a, component=component) packages = [binaries_s_a[p].source for p in packages] # if the dependency can be satisfied by the same source package, skip the block: diff --git a/britney2/consts.py b/britney2/consts.py index 8f760d1..ceaa61b 100644 --- a/britney2/consts.py +++ b/britney2/consts.py @@ -34,3 +34,9 @@ DEPENDS = 6 CONFLICTS = 7 PROVIDES = 8 ESSENTIAL = 9 + +# components +MAIN = 0 +RESTRICTED = 1 +UNIVERSE = 2 +MULTIVERSE = 3 diff --git a/britney2/utils.py b/britney2/utils.py index 6d8e817..acef624 100644 --- a/britney2/utils.py +++ b/britney2/utils.py @@ -38,6 +38,7 @@ from britney2.consts import (VERSION, PROVIDES, DEPENDS, CONFLICTS, ARCHITECTURE, SECTION, SOURCE, MAINTAINER, MULTIARCH, ESSENTIAL) +from britney2.consts import (MAIN, RESTRICTED, UNIVERSE, MULTIVERSE) from britney2.migrationitem import MigrationItem, UnversionnedMigrationItem @@ -745,13 +746,17 @@ def read_sources_file(filename, sources=None, intern=sys.intern): return sources -def get_dependency_solvers(block, binaries_s_a, provides_s_a, *, empty_set=frozenset()): +def get_dependency_solvers(block, binaries_s_a, provides_s_a, *, empty_set=frozenset(), component=None): """Find the packages which satisfy a dependency block This method returns the list of packages which satisfy a dependency block (as returned by apt_pkg.parse_depends) in a package table for a given suite and architecture (a la self.binaries[suite][arch]) + If component was not specified, use all available (multiverse). This is to + avoid britney pretending that a bunch of things are non-installable in + release pocket, and start trading components-mismatches things. + :param block: The dependency block as parsed by apt_pkg.parse_depends :param binaries_s_a: A dict mapping package names to the relevant BinaryPackage :param provides_s_a: A dict mapping package names to their providers (as generated by parse_provides) @@ -774,7 +779,8 @@ def get_dependency_solvers(block, binaries_s_a, provides_s_a, *, empty_set=froze # (if present) if (op == '' and version == '') or apt_pkg.check_dep(package.version, op, version): if archqual is None or (archqual == 'any' and package.multi_arch == 'allowed'): - packages.append(name) + if component is None or allowed_component(component, get_component(package.section)): + packages.append(name) # look for the package in the virtual packages list and loop on them for prov, prov_version in provides_s_a.get(name, empty_set): @@ -865,3 +871,34 @@ def compile_nuninst(binaries_t, inst_tester, architectures, nobreakall_arches): nuninst[arch].remove(pkg_name) return nuninst + + +def get_component(section): + """Parse section and return component + + Given a section, return component. Packages in MAIN have no + prefix, all others have / prefix. + """ + name2component = { + "restricted": RESTRICTED, + "universe": UNIVERSE, + "multiverse": MULTIVERSE + } + + if '/' in section: + return name2component[section.split('/', 1)[0]] + + return MAIN + + +def allowed_component(me, dep): + """Check if I can depend on the other component""" + + component_dependencies = { + MAIN: [MAIN], + RESTRICTED: [MAIN, RESTRICTED], + UNIVERSE: [MAIN, UNIVERSE], + MULTIVERSE: [MAIN, RESTRICTED, UNIVERSE, MULTIVERSE], + } + + return dep in component_dependencies[me] diff --git a/tests/test_util.py b/tests/test_util.py new file mode 100755 index 0000000..fdd300d --- /dev/null +++ b/tests/test_util.py @@ -0,0 +1,52 @@ +#!/usr/bin/python3 +# (C) 2014 - 2016 Canonical Ltd. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. + +import os +import sys +import unittest + +PROJECT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +sys.path.insert(0, PROJECT_DIR) + +from britney2.utils import get_component, allowed_component +from britney2.consts import MAIN, RESTRICTED, UNIVERSE, MULTIVERSE + + +class UtilTests(unittest.TestCase): + + def test_get_component(self): + self.assertEqual(get_component('utils'), MAIN) + self.assertEqual(get_component('utils'), MAIN) + self.assertEqual(get_component('restricted/admin'), RESTRICTED) + self.assertEqual(get_component('universe/web'), UNIVERSE) + self.assertEqual(get_component('multiverse/libs'), MULTIVERSE) + + def test_allowed_component(self): + self.assertTrue(allowed_component(MAIN, MAIN)) + self.assertFalse(allowed_component(MAIN, UNIVERSE)) + self.assertFalse(allowed_component(MAIN, MULTIVERSE)) + self.assertFalse(allowed_component(MAIN, RESTRICTED)) + + self.assertTrue(allowed_component(RESTRICTED, MAIN)) + self.assertFalse(allowed_component(RESTRICTED, UNIVERSE)) + self.assertFalse(allowed_component(RESTRICTED, MULTIVERSE)) + self.assertTrue(allowed_component(RESTRICTED, RESTRICTED)) + + self.assertTrue(allowed_component(UNIVERSE, MAIN)) + self.assertTrue(allowed_component(UNIVERSE, UNIVERSE)) + self.assertFalse(allowed_component(UNIVERSE, MULTIVERSE)) + self.assertFalse(allowed_component(UNIVERSE, RESTRICTED)) + + self.assertTrue(allowed_component(MULTIVERSE, MAIN)) + self.assertTrue(allowed_component(MULTIVERSE, UNIVERSE)) + self.assertTrue(allowed_component(MULTIVERSE, MULTIVERSE)) + self.assertTrue(allowed_component(MULTIVERSE, RESTRICTED)) + + +if __name__ == '__main__': + unittest.main()