From cf026ec1840a0d858b48e35fa98b248323ab9d90 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 21 Oct 2011 11:07:53 +0200 Subject: first cut of multiarch support, tests still fail though --- apt/debfile.py | 34 ++++++++++++++++--- tests/data/test_debs/multiarch-test1_i386.deb | Bin 0 -> 978 bytes tests/test_debfile.py | 8 +++-- tests/test_debfile_multiarch.py | 46 ++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 8 deletions(-) create mode 100644 tests/data/test_debs/multiarch-test1_i386.deb create mode 100644 tests/test_debfile_multiarch.py diff --git a/apt/debfile.py b/apt/debfile.py index 104b0814..1a9b471a 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -54,6 +54,7 @@ class DebPackage(object): self._sections = {} self._need_pkgs = [] self._failure_string = "" + self._multiarch = None if filename: self.open(filename) @@ -83,6 +84,14 @@ class DebPackage(object): self.filename)] return files + # helper that will return a pkgname with a multiarch suffix if needed + def _maybe_append_multiarch_suffix(self, pkgname): + if (self._multiarch and + not self._cache.is_virtual_package(pkgname) and + self._cache[pkgname].candidate.architecture != "all"): + return "%s:%s" % (pkgname, self._multiarch) + return pkgname + def _is_or_group_satisfied(self, or_group): """Return True if at least one dependency of the or-group is satisfied. @@ -96,6 +105,9 @@ class DebPackage(object): ver = dep[1] oper = dep[2] + # multiarch + depname = self._maybe_append_multiarch_suffix(depname) + # check for virtual pkgs if not depname in self._cache: if self._cache.is_virtual_package(depname): @@ -131,6 +143,9 @@ class DebPackage(object): for dep in or_group: depname, ver, oper = dep + # multiarch + depname = self._maybe_append_multiarch_suffix(depname) + # if we don't have it in the cache, it may be virtual if not depname in self._cache: if not self._cache.is_virtual_package(depname): @@ -203,6 +218,10 @@ class DebPackage(object): ver = dep[1] oper = dep[2] + # FIXME: is this good enough? i.e. will apt always populate + # the cache with conflicting pkgnames for our arch? + depname = self._maybe_append_multiarch_suffix(depname) + # check conflicts with virtual pkgs if not depname in self._cache: # FIXME: we have to check for virtual replaces here as @@ -400,9 +419,14 @@ class DebPackage(object): return False arch = self._sections["Architecture"] if arch != "all" and arch != apt_pkg.config.find("APT::Architecture"): - self._dbg(1, "ERROR: Wrong architecture dude!") - self._failure_string = _("Wrong architecture '%s'") % arch - return False + if arch in apt_pkg.get_architectures(): + self._multiarch = arch + self.pkgname = "%s:%s" % (self.pkgname, self._multiarch) + self._dbg(1, "Found multiarch arch: '%s'" % arch) + else: + self._dbg(1, "ERROR: Wrong architecture dude!") + self._failure_string = _("Wrong architecture '%s'") % arch + return False # check version if self.compare_to_version_in_cache() == self.VERSION_OUTDATED: @@ -656,7 +680,7 @@ class DscSrcPackage(DebPackage): def _test(): """Test function""" from apt.cache import Cache - from apt.progress import DpkgInstallProgress + from apt.progress.base import InstallProgress cache = Cache() @@ -678,7 +702,7 @@ def _test(): print d.filelist print "Installing ..." - ret = d.install(DpkgInstallProgress()) + ret = d.install(InstallProgress()) print ret #s = DscSrcPackage(cache, "../tests/3ddesktop_0.2.9-6.dsc") diff --git a/tests/data/test_debs/multiarch-test1_i386.deb b/tests/data/test_debs/multiarch-test1_i386.deb new file mode 100644 index 00000000..439a9f46 Binary files /dev/null and b/tests/data/test_debs/multiarch-test1_i386.deb differ diff --git a/tests/test_debfile.py b/tests/test_debfile.py index 951c2afe..72d5e0b0 100644 --- a/tests/test_debfile.py +++ b/tests/test_debfile.py @@ -17,8 +17,8 @@ sys.path.insert(0, get_library_dir()) import apt_pkg import apt.debfile -class TestDebfilee(unittest.TestCase): - """ test the apt cache """ +class TestDebfile(unittest.TestCase): + """ test the debfile """ TEST_DEBS = [ # conflicts with apt @@ -87,7 +87,7 @@ class TestDebfilee(unittest.TestCase): self.assertEqual(deb["Maintainer"], "Samuel Lidén Borell ") - def testContent(self): + def test_content(self): # no python-debian for python3 yet, so fail gracefully try: import debian @@ -130,6 +130,8 @@ Description: testpackage for gdebi - contains usr/bin/binary for file reading # we need to support python2.6 self.assertTrue(raised) + + if __name__ == "__main__": #logging.basicConfig(level=logging.DEBUG) unittest.main() diff --git a/tests/test_debfile_multiarch.py b/tests/test_debfile_multiarch.py new file mode 100644 index 00000000..1b468a45 --- /dev/null +++ b/tests/test_debfile_multiarch.py @@ -0,0 +1,46 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# +# Copyright (C) 2010 Michael Vogt +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. +"""Unit tests for verifying the correctness of DebPackage in apt.debfile.""" +import os +import logging +import unittest + +from test_all import get_library_dir +import sys +sys.path.insert(0, get_library_dir()) +import apt +import apt_pkg +import apt.debfile + +class TestDebfileMultiarch(unittest.TestCase): + """ test the multiarch debfile """ + + def test_multiarch_deb(self): + if apt_pkg.get_architectures() != ["amd64", "i386"]: + logging.warn("skipping test because running on a non-multiarch system") + return + deb = apt.debfile.DebPackage( + "./data/test_debs/multiarch-test1_i386.deb") + missing = deb.missing_deps + print missing + self.assertFalse("dpkg:i386" in missing) + + def test_multiarch_conflicts(self): + cache = apt.Cache() + # WARNING: this assumes that lib3ds-1-3 is a non-multiarch lib + # use "lib3ds-1-3" as a test to see if non-multiach lib conflicts work + cache["lib3ds-1-3"].mark_install() + deb = apt.debfile.DebPackage( + "./data/test_debs/multiarch-test1_i386.deb", cache=cache) + # this deb should now not be installable + self.assertFalse(deb.check()) + + +if __name__ == "__main__": + unittest.main() -- cgit v1.2.3 From c96acf6d26beb8c2c2e6eb9a868a4ea6b053a9d4 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 21 Oct 2011 11:47:03 +0200 Subject: make the tests pass --- apt/debfile.py | 36 +++++++++++++++++++++++++++++------- tests/test_debfile_multiarch.py | 11 ++++++++--- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/apt/debfile.py b/apt/debfile.py index 1a9b471a..0e8bfcad 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -85,12 +85,33 @@ class DebPackage(object): return files # helper that will return a pkgname with a multiarch suffix if needed - def _maybe_append_multiarch_suffix(self, pkgname): - if (self._multiarch and - not self._cache.is_virtual_package(pkgname) and - self._cache[pkgname].candidate.architecture != "all"): - return "%s:%s" % (pkgname, self._multiarch) - return pkgname + def _maybe_append_multiarch_suffix(self, pkgname, + in_conflict_checking=False): + # trivial cases + if not self._multiarch: + return pkgname + elif self._cache.is_virtual_package(pkgname): + return pkgname + elif self._cache[pkgname].candidate == "all": + return pkgname + # now do the real multiarch checking + multiarch_pkgname = "%s:%s" % (pkgname, self._multiarch) + # the upper layers will handle this + if not multiarch_pkgname in self._cache: + return multiarch_pkgname + # now check the multiarch state + cand = self._cache[multiarch_pkgname].candidate._cand + #print pkgname, multiarch_pkgname, cand.multi_arch + # the default is to add the suffix, unless its a pkg that can satify + # foreign dependencies + if cand.multi_arch & cand.MULTI_ARCH_FOREIGN: + return pkgname + # for conflicts we need a special case here, any not multiarch enabled + # package has a implicit conflict + if (in_conflict_checking and + not (cand.multi_arch & cand.MULTI_ARCH_SAME)): + return pkgname + return multiarch_pkgname def _is_or_group_satisfied(self, or_group): """Return True if at least one dependency of the or-group is satisfied. @@ -220,7 +241,8 @@ class DebPackage(object): # FIXME: is this good enough? i.e. will apt always populate # the cache with conflicting pkgnames for our arch? - depname = self._maybe_append_multiarch_suffix(depname) + depname = self._maybe_append_multiarch_suffix( + depname, in_conflict_checking=True) # check conflicts with virtual pkgs if not depname in self._cache: diff --git a/tests/test_debfile_multiarch.py b/tests/test_debfile_multiarch.py index 1b468a45..db777692 100644 --- a/tests/test_debfile_multiarch.py +++ b/tests/test_debfile_multiarch.py @@ -21,14 +21,14 @@ import apt.debfile class TestDebfileMultiarch(unittest.TestCase): """ test the multiarch debfile """ - def test_multiarch_deb(self): + def test_multiarch_deb_check(self): if apt_pkg.get_architectures() != ["amd64", "i386"]: logging.warn("skipping test because running on a non-multiarch system") return deb = apt.debfile.DebPackage( "./data/test_debs/multiarch-test1_i386.deb") missing = deb.missing_deps - print missing + #print missing self.assertFalse("dpkg:i386" in missing) def test_multiarch_conflicts(self): @@ -39,7 +39,12 @@ class TestDebfileMultiarch(unittest.TestCase): deb = apt.debfile.DebPackage( "./data/test_debs/multiarch-test1_i386.deb", cache=cache) # this deb should now not be installable - self.assertFalse(deb.check()) + installable = deb.check() + #print deb._failure_string + self.assertFalse(installable) + self.assertEqual(deb._failure_string, + "Conflicts with the installed package 'lib3ds-1-3'") + if __name__ == "__main__": -- cgit v1.2.3 From cccf74c205b05cf81bade4269ea7df99c5dcbea7 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 21 Oct 2011 11:57:10 +0200 Subject: tests/test_debfile_multiarch.py: skip test if e.g. unvierse is not enabled --- tests/test_debfile_multiarch.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_debfile_multiarch.py b/tests/test_debfile_multiarch.py index db777692..7c02a32a 100644 --- a/tests/test_debfile_multiarch.py +++ b/tests/test_debfile_multiarch.py @@ -35,7 +35,11 @@ class TestDebfileMultiarch(unittest.TestCase): cache = apt.Cache() # WARNING: this assumes that lib3ds-1-3 is a non-multiarch lib # use "lib3ds-1-3" as a test to see if non-multiach lib conflicts work - cache["lib3ds-1-3"].mark_install() + canary = "lib3ds-1-3" + if not canary in cache: + logging.warn("skipping test because %s is missing" % canary) + return + cache[canary].mark_install() deb = apt.debfile.DebPackage( "./data/test_debs/multiarch-test1_i386.deb", cache=cache) # this deb should now not be installable -- cgit v1.2.3 From 5416003d5acd3630bff5b48f69277b5e1d917f20 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 21 Oct 2011 12:14:29 +0200 Subject: apt/debfile.py: really check against architecture --- apt/debfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apt/debfile.py b/apt/debfile.py index 0e8bfcad..1d7a4a16 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -92,7 +92,7 @@ class DebPackage(object): return pkgname elif self._cache.is_virtual_package(pkgname): return pkgname - elif self._cache[pkgname].candidate == "all": + elif self._cache[pkgname].candidate.architecture == "all": return pkgname # now do the real multiarch checking multiarch_pkgname = "%s:%s" % (pkgname, self._multiarch) -- cgit v1.2.3 From 350bb4a03d6562ddba12fbb0a34610aac7706b3c Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 8 Dec 2011 17:26:57 +0100 Subject: handle architecture-specific conflicts correctly (LP: #829138) --- apt/debfile.py | 3 ++- debian/changelog | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/apt/debfile.py b/apt/debfile.py index c91ce349..17f1dbd9 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -310,6 +310,7 @@ class DebPackage(object): size = float(len(self._cache)) steps = max(int(size/50), 1) debver = self._sections["Version"] + debarch = self._sections["Architecture"] # store what we provide so that we can later check against that provides = [ x[0][0] for x in self.provides] for (i, pkg) in enumerate(self._cache): @@ -338,7 +339,7 @@ class DebPackage(object): if "Conflicts" in ver.depends_list: for conflicts_ver_list in ver.depends_list["Conflicts"]: for c_or in conflicts_ver_list: - if c_or.target_pkg.name == self.pkgname: + if c_or.target_pkg.name == self.pkgname and c_or.target_pkg.architecture == debarch: if apt_pkg.check_dep(debver, c_or.comp_type, c_or.target_ver): self._dbg(2, "would break (conflicts) %s" % pkg.name) # TRANSLATORS: the first '%s' is the package that conflicts, the second the packagename that it conflicts with (so the name of the deb the user tries to install), the third is the relation (e.g. >=) and the last is the version for the relation diff --git a/debian/changelog b/debian/changelog index 4a90e907..d5b68082 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +python-apt (0.8.3) UNRELEASED; urgency=low + + [ Alexey Feldgendler ] + * handle architecture-specific conflicts correctly (LP: #829138) + + -- Michael Vogt Thu, 08 Dec 2011 17:26:37 +0100 + python-apt (0.8.2) unstable; urgency=low [ Michael Vogt ] -- cgit v1.2.3 From 33c83f032fa17f0068a3a1b5486a3cfcfeabd66d Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 8 Dec 2011 20:15:58 +0100 Subject: tests/test_apt_cache.py: change test to test for python3 instead of xterm to fix test failure on certain buildds --- tests/test_apt_cache.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_apt_cache.py b/tests/test_apt_cache.py index 6ec04ed5..e62507ed 100644 --- a/tests/test_apt_cache.py +++ b/tests/test_apt_cache.py @@ -185,11 +185,11 @@ class TestAptCache(unittest.TestCase): cache = apt.Cache(rootdir="/") l = [] l.append(cache["libc6"]) - l.append(cache["xterm"]) + l.append(cache["python3"]) l.append(cache["apt"]) l.sort() self.assertEqual([p.name for p in l], - ["apt", "libc6", "xterm"]) + ["apt", "libc6", "python3"]) def test_get_architectures(self): main_arch = apt.apt_pkg.config.get("APT::Architecture") -- cgit v1.2.3 From a84352261cd34aaa34b3c4507d9d8e6216170050 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 8 Dec 2011 20:31:15 +0100 Subject: * tests/test_apt_cache.py: - add additional check if provides test can actually be run --- debian/changelog | 2 ++ tests/test_apt_cache.py | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/debian/changelog b/debian/changelog index 2b16a2bd..46a94688 100644 --- a/debian/changelog +++ b/debian/changelog @@ -6,6 +6,8 @@ python-apt (0.8.3) UNRELEASED; urgency=low [ Michael Vogt ] * lp:~mvo/python-apt/debfile-multiarch: - add multiarch support to the debfile.py code + * tests/test_apt_cache.py: + - add additional check if provides test can actually be run -- Michael Vogt Thu, 08 Dec 2011 17:26:37 +0100 diff --git a/tests/test_apt_cache.py b/tests/test_apt_cache.py index e62507ed..2bc19353 100644 --- a/tests/test_apt_cache.py +++ b/tests/test_apt_cache.py @@ -74,6 +74,9 @@ class TestAptCache(unittest.TestCase): apt.apt_pkg.config.set("Apt::architecture", "i386") cache = apt.Cache(rootdir="./data/test-provides/") cache.open() + if len(cache) == 0: + logging.warn("skipping test_get_provided_packages, cache empty?!?") + return # a true virtual pkg l = cache.get_providing_packages("mail-transport-agent") self.assertTrue(len(l) > 0) @@ -84,6 +87,9 @@ class TestAptCache(unittest.TestCase): apt.apt_pkg.config.set("Apt::architecture", "i386") # create highlevel cache and get the lowlevel one from it highlevel_cache = apt.Cache(rootdir="./data/test-provides") + if len(highlevel_cache) == 0: + logging.warn("skipping test_log_level_pkg_provides, cache empty?!?") + return # low level cache provides list of the pkg cache = highlevel_cache._cache l = cache["mail-transport-agent"].provides_list -- cgit v1.2.3