From 7217a44a6d480f5fc4390954e418f116239996ca Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Sat, 5 Jul 2008 19:57:18 +0100 Subject: [PATCH] Added support for multi-arch We can choose either x86_64 binaries or i[3456]86 binaries, but we can't mix both in a single process. Also fixed the sense of the OS and CPU tests so that we now pick the best OS and CPU match than the worst. --- tests/testsolver.py | 20 ++++++++++++++++++++ zeroinstall/injector/arch.py | 8 ++++++++ zeroinstall/injector/solver.py | 22 ++++++++++++++++------ 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/tests/testsolver.py b/tests/testsolver.py index 39e7dc3..aca12d6 100755 --- a/tests/testsolver.py +++ b/tests/testsolver.py @@ -74,6 +74,26 @@ class TestSolver(BaseTest): assert len(s.details) == 1 assert s.details[foo] == [(foo._main_feed.implementations['sha1=abc'], None)] + def testMultiArch(self): + s = solver.DefaultSolver(model.network_full, iface_cache, Stores()) + + foo = iface_cache.get_interface('http://foo/MultiArch.xml') + reader.update(foo, 'MultiArch.xml') + + # On an i686 system we can only use the i486 implementation + + binary_arch = arch.get_architecture('Linux', 'i686') + s.solve('http://foo/MultiArch.xml', binary_arch) + assert s.ready + assert s.selections[foo].machine == 'i486' + + # On an 64 bit system we could use either, but we prefer the 64 bit implementation + + binary_arch = arch.get_architecture('Linux', 'x86_64') + s.solve('http://foo/MultiArch.xml', binary_arch) + assert s.ready + assert s.selections[foo].machine == 'x86_64' + def testArch(self): host_arch = arch.get_host_architecture() host_arch2 = arch.get_architecture(None, None) diff --git a/zeroinstall/injector/arch.py b/zeroinstall/injector/arch.py index f9c52ad..ddc2274 100644 --- a/zeroinstall/injector/arch.py +++ b/zeroinstall/injector/arch.py @@ -30,6 +30,13 @@ os_ranks = { _uname[0] : 1, # Current OS } +# All chosen machine-specific implementations must come from the same group +# Unlisted archs are in group 0 +machine_groups = { + 'x86_64': 64, + 'ppc64': 64, +} + def _get_machine_ranks(target_machine): # Binaries compiled for _this_machine are best... machine_ranks = {target_machine : 0} @@ -41,6 +48,7 @@ def _get_machine_ranks(target_machine): 'i486': ['i386'], 'i586': ['i486', 'i386'], 'i686': ['i586', 'i486', 'i386'], + 'x86_64': ['i686', 'i586', 'i486', 'i386'], 'ppc64': ['ppc32'], } for supported in _machine_matrix.get(target_machine, []): diff --git a/zeroinstall/injector/solver.py b/zeroinstall/injector/solver.py index e758110..26fe003 100644 --- a/zeroinstall/injector/solver.py +++ b/zeroinstall/injector/solver.py @@ -7,6 +7,7 @@ from logging import debug, warn, info from zeroinstall.zerostore import BadDigest, NotStored +from zeroinstall.injector.arch import machine_groups from zeroinstall.injector import selections from zeroinstall.injector import model @@ -69,6 +70,7 @@ class DefaultSolver(Solver): self.selections = {} self.feeds_used = set() self.details = self.record_details and {} + self._machine_group = None restrictions = {} debug("Solve! root = %s", root_interface) @@ -91,6 +93,9 @@ class DefaultSolver(Solver): if impl: debug("Will use implementation %s (version %s)", impl, impl.get_version()) self.selections[iface] = impl + if self._machine_group is None and impl.machine: + self._machine_group = machine_groups.get(impl.machine, 0) + debug("Now restricted to architecture group %s", self._machine_group) for d in impl.requires: debug("Considering dependency %s", d) if not process(d, arch.child_arch): @@ -184,13 +189,13 @@ class DefaultSolver(Solver): if r: return r # Get best OS - r = cmp(arch.os_ranks.get(a.os, None), - arch.os_ranks.get(b.os, None)) + r = cmp(arch.os_ranks.get(b.os, None), + arch.os_ranks.get(a.os, None)) if r: return r # Get best machine - r = cmp(arch.machine_ranks.get(a.machine, None), - arch.machine_ranks.get(b.machine, None)) + r = cmp(arch.machine_ranks.get(b.machine, None), + arch.machine_ranks.get(a.machine, None)) if r: return r # Slightly prefer cached versions @@ -225,6 +230,11 @@ class DefaultSolver(Solver): @rtype: str @note: The restrictions are for the interface being requested, not the interface of the implementation; they may be different when feeds are being used.""" + machine = impl.machine + if machine and self._machine_group is not None: + if machine_groups.get(machine, 0) != self._machine_group: + return "Incompatible with another selection from a different architecture group" + for r in restrictions: if not r.meets_restriction(impl): return "Incompatible with another selected implementation" @@ -238,8 +248,8 @@ class DefaultSolver(Solver): # When looking for source code, we need to known if we're # looking at an implementation of the root interface, even if # it's from a feed, hence the sneaky restrictions identity check. - if impl.machine not in arch.machine_ranks: - if impl.machine == 'src': + if machine not in arch.machine_ranks: + if machine == 'src': return "Source code" return "Unsupported machine type" return None -- 2.11.4.GIT