From 2838b7b79fc3c30fb44579f1b993e799502fa5bc Mon Sep 17 00:00:00 2001 From: Dimitri John Ledkov Date: Thu, 18 Feb 2016 14:02:31 +0000 Subject: [PATCH] Teach excuse_unsat_deps() about components ogre model. --- britney.py | 25 +++++++++++++++------- britney_util.py | 33 ++++++++++++++++++++++++++++- consts.py | 7 +++++++ tests/test_util.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 8 deletions(-) create mode 100755 tests/test_util.py diff --git a/britney.py b/britney.py index f7ece67..2b49882 100755 --- a/britney.py +++ b/britney.py @@ -208,10 +208,11 @@ from britney_util import (old_libraries_format, same_source, undo_changes, eval_uninst, newly_uninst, make_migrationitem, write_excuses, write_heidi_delta, write_controlfiles, old_libraries, is_nuninst_asgood_generous, ensuredir, - clone_nuninst) + clone_nuninst, get_component, allowed_component) from consts import (VERSION, SECTION, BINARIES, MAINTAINER, FAKESRC, - SOURCE, SOURCEVER, ARCHITECTURE, DEPENDS, CONFLICTS, - PROVIDES, RDEPENDS, RCONFLICTS, MULTIARCH, ESSENTIAL) + SOURCE, SOURCEVER, ARCHITECTURE, DEPENDS, CONFLICTS, + PROVIDES, RDEPENDS, RCONFLICTS, MULTIARCH, ESSENTIAL, + COMPONENT, MULTIVERSE) from autopkgtest import AutoPackageTest, srchash @@ -710,6 +711,7 @@ class Britney(object): [], [], ess, + get_component(get_field('Section')) ] # retrieve the name and the version of the source package @@ -1105,7 +1107,7 @@ class Britney(object): # Utility methods for package analysis # ------------------------------------ - def get_dependency_solvers(self, block, arch, distribution): + def get_dependency_solvers(self, block, arch, distribution, component=MULTIVERSE): """Find the packages which satisfy a dependency block This method returns the list of packages which satisfy a dependency @@ -1115,6 +1117,12 @@ class Britney(object): It returns a tuple with two items: the first is a boolean which is True if the dependency is satisfied, the second is the list of the solving packages. + + If component was not specified, use all availalbe + (multiverse). This is to avoid britney pretending that a bunch + of things are non-installable in release pocket, and start + trading components-missmatches things. + """ packages = [] @@ -1136,7 +1144,8 @@ class Britney(object): # (if present) if (op == '' and version == '') or apt_pkg.check_dep(package[VERSION], op, version): if archqual is None or (archqual == 'any' and package[MULTIARCH] == 'allowed'): - packages.append(name) + if allowed_component(component, package[COMPONENT]): + packages.append(name) # look for the package in the virtual packages list and loop on them for prov in binaries[1].get(name, []): @@ -1193,12 +1202,14 @@ class Britney(object): return True deps = binary_u[DEPENDS] + component = binary_u[COMPONENT] + all_satisfiable = True # for every dependency block (formed as conjunction of disjunction) for block, block_txt in zip(parse_depends(deps, False), deps.split(',')): # if the block is satisfied in testing, then skip the block - packages = get_dependency_solvers(block, arch, 'testing') + packages = get_dependency_solvers(block, arch, 'testing', component) if packages: for p in packages: if p not in self.binaries[suite][arch][0]: continue @@ -1206,7 +1217,7 @@ class Britney(object): continue # check if the block can be satisfied in unstable, and list the solving packages - packages = get_dependency_solvers(block, arch, suite) + packages = get_dependency_solvers(block, arch, suite, component) packages = [self.binaries[suite][arch][0][p][SOURCE] for p in packages] # if the dependency can be satisfied by the same source package, skip the block: diff --git a/britney_util.py b/britney_util.py index 0dc9981..4232b16 100644 --- a/britney_util.py +++ b/britney_util.py @@ -35,7 +35,7 @@ from migrationitem import MigrationItem, UnversionnedMigrationItem from consts import (VERSION, BINARIES, PROVIDES, DEPENDS, CONFLICTS, RDEPENDS, RCONFLICTS, ARCHITECTURE, SECTION, SOURCE, SOURCEVER, MAINTAINER, MULTIARCH, - ESSENTIAL) + ESSENTIAL, MAIN, RESTRICTED, UNIVERSE, MULTIVERSE) binnmu_re = re.compile(r'^(.*)\+b\d+$') @@ -620,3 +620,34 @@ def clone_nuninst(nuninst, packages_s, architectures): clone[arch] = set(x for x in nuninst[arch] if x in packages_s[arch][0]) clone[arch + "+all"] = set(x for x in nuninst[arch + "+all"] if x in packages_s[arch][0]) return clone + + +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/consts.py b/consts.py index 493a538..f01650a 100644 --- a/consts.py +++ b/consts.py @@ -37,3 +37,10 @@ PROVIDES = 8 RDEPENDS = 9 RCONFLICTS = 10 ESSENTIAL = 11 +COMPONENT = 12 + +# components +MAIN = 0 +RESTRICTED = 1 +UNIVERSE = 2 +MULTIVERSE = 3 diff --git a/tests/test_util.py b/tests/test_util.py new file mode 100755 index 0000000..f2e79cb --- /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 britney_util import get_component, allowed_component +from 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()