summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vogt <egon@debian-devbox>2011-12-08 20:41:48 +0100
committerMichael Vogt <egon@debian-devbox>2011-12-08 20:41:48 +0100
commit49a261ded353b836db807b372780a082502e5b5a (patch)
tree9bef9306f9f6c764719409e04dd70d872269bd2f
parentd686a36d94e909eefc13403391ee60938f54df5c (diff)
parenta84352261cd34aaa34b3c4507d9d8e6216170050 (diff)
downloadpython-apt-49a261ded353b836db807b372780a082502e5b5a.tar.gz
* handle architecture-specific conflicts correctly (LP: #829138)
* 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
-rw-r--r--apt/debfile.py59
-rw-r--r--debian/changelog13
-rw-r--r--po/python-apt.pot34
-rw-r--r--tests/data/test_debs/multiarch-test1_i386.debbin0 -> 978 bytes
-rw-r--r--tests/test_apt_cache.py10
-rw-r--r--tests/test_debfile.py13
-rw-r--r--tests/test_debfile_multiarch.py55
7 files changed, 148 insertions, 36 deletions
diff --git a/apt/debfile.py b/apt/debfile.py
index c91ce349..160a4a72 100644
--- a/apt/debfile.py
+++ b/apt/debfile.py
@@ -55,6 +55,7 @@ class DebPackage(object):
self._need_pkgs = []
self._check_was_run = False
self._failure_string = ""
+ self._multiarch = None
if filename:
self.open(filename)
@@ -85,6 +86,35 @@ 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,
+ 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.architecture == "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.
@@ -98,6 +128,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):
@@ -133,6 +166,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):
@@ -205,6 +241,11 @@ 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, in_conflict_checking=True)
+
# check conflicts with virtual pkgs
if not depname in self._cache:
# FIXME: we have to check for virtual replaces here as
@@ -310,6 +351,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 +380,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
@@ -404,9 +446,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:
@@ -672,7 +719,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()
@@ -694,7 +741,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/debian/changelog b/debian/changelog
index 4a90e907..fcf8ff98 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,16 @@
+python-apt (0.8.3) unstable; urgency=low
+
+ [ Alexey Feldgendler ]
+ * handle architecture-specific conflicts correctly (LP: #829138)
+
+ [ 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 <mvo@debian.org> Thu, 08 Dec 2011 20:31:52 +0100
+
python-apt (0.8.2) unstable; urgency=low
[ Michael Vogt ]
diff --git a/po/python-apt.pot b/po/python-apt.pot
index 8772e88b..f1aecc59 100644
--- a/po/python-apt.pot
+++ b/po/python-apt.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2011-12-01 13:58+0100\n"
+"POT-Creation-Date: 2011-12-08 20:01+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -474,23 +474,23 @@ msgid ""
"Please check your Internet connection."
msgstr ""
-#: ../apt/debfile.py:84
+#: ../apt/debfile.py:85
#, python-format
msgid "List of files for '%s' could not be read"
msgstr ""
-#: ../apt/debfile.py:169
+#: ../apt/debfile.py:205
#, python-format
msgid "Dependency is not satisfiable: %s\n"
msgstr ""
-#: ../apt/debfile.py:190
+#: ../apt/debfile.py:226
#, python-format
msgid "Conflicts with the installed package '%s'"
msgstr ""
#. TRANSLATORS: the first '%s' is the package that breaks, the second the dependency that makes it break, the third the relation (e.g. >=) and the latest the version for the releation
-#: ../apt/debfile.py:329
+#: ../apt/debfile.py:371
#, python-format
msgid ""
"Breaks existing package '%(pkgname)s' dependency %(depname)s "
@@ -498,63 +498,63 @@ msgid ""
msgstr ""
#. 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
-#: ../apt/debfile.py:345
+#: ../apt/debfile.py:387
#, python-format
msgid ""
"Breaks existing package '%(pkgname)s' conflict: %(targetpkg)s (%(comptype)s "
"%(targetver)s)"
msgstr ""
-#: ../apt/debfile.py:355
+#: ../apt/debfile.py:397
#, python-format
msgid ""
"Breaks existing package '%(pkgname)s' that conflict: '%(targetpkg)s'. But "
"the '%(debfile)s' provides it via: '%(provides)s'"
msgstr ""
-#: ../apt/debfile.py:403
+#: ../apt/debfile.py:445
msgid "No Architecture field in the package"
msgstr ""
-#: ../apt/debfile.py:408
+#: ../apt/debfile.py:455
#, python-format
msgid "Wrong architecture '%s'"
msgstr ""
#. the deb is older than the installed
-#: ../apt/debfile.py:415
+#: ../apt/debfile.py:462
msgid "A later version is already installed"
msgstr ""
-#: ../apt/debfile.py:440
+#: ../apt/debfile.py:487
msgid "Failed to satisfy all dependencies (broken cache)"
msgstr ""
-#: ../apt/debfile.py:470
+#: ../apt/debfile.py:517
#, python-format
msgid "Cannot install '%s'"
msgstr ""
-#: ../apt/debfile.py:514
+#: ../apt/debfile.py:561
msgid "Python-debian module not available"
msgstr ""
-#: ../apt/debfile.py:557
+#: ../apt/debfile.py:604
msgid ""
"Automatically decompressed:\n"
"\n"
msgstr ""
-#: ../apt/debfile.py:563
+#: ../apt/debfile.py:610
msgid "Automatically converted to printable ascii:\n"
msgstr ""
-#: ../apt/debfile.py:653
+#: ../apt/debfile.py:700
#, python-format
msgid "Install Build-Dependencies for source package '%s' that builds %s\n"
msgstr ""
-#: ../apt/debfile.py:664
+#: ../apt/debfile.py:711
msgid "An essential package would be removed"
msgstr ""
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
--- /dev/null
+++ b/tests/data/test_debs/multiarch-test1_i386.deb
Binary files differ
diff --git a/tests/test_apt_cache.py b/tests/test_apt_cache.py
index 6ec04ed5..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
@@ -185,11 +191,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")
diff --git a/tests/test_debfile.py b/tests/test_debfile.py
index af04af26..04a6b65a 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
@@ -131,15 +131,6 @@ Description: testpackage for gdebi - contains usr/bin/binary for file reading
# we need to support python2.6
self.assertTrue(raised)
- 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")
- res = deb.check()
- # FIXME: do something sensible with the multiarch test
-
-
if __name__ == "__main__":
#logging.basicConfig(level=logging.DEBUG)
diff --git a/tests/test_debfile_multiarch.py b/tests/test_debfile_multiarch.py
new file mode 100644
index 00000000..7c02a32a
--- /dev/null
+++ b/tests/test_debfile_multiarch.py
@@ -0,0 +1,55 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2010 Michael Vogt <mvo@ubuntu.com>
+#
+# 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_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
+ 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
+ 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
+ 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__":
+ unittest.main()