summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vogt <michael.vogt@ubuntu.com>2010-07-02 16:46:35 +0200
committerMichael Vogt <michael.vogt@ubuntu.com>2010-07-02 16:46:35 +0200
commit465b19e6ae3c6daeee0841d38ac93e0c19991c13 (patch)
treefe7105c64632ccc9dc22520b6d70a18d5342c97b
parent5a6c646ceffab7ce58106eccdccf884b6d332d58 (diff)
parentdd86db9ddb22b43867b5b4dc211f4440dec7aa6a (diff)
downloadpython-apt-465b19e6ae3c6daeee0841d38ac93e0c19991c13.tar.gz
* merged lp:~kiwinote/python-apt/merge-gdebi-changes, this port the
DebPackage class fixes from gdebi into python-apt so that gdebi can use the class from python-apt directly * apt/debfile.py: - check if the debfiles provides are in conflict with the systems packages * tests/test_debs/*.deb, tests/test_debfile.py: - add automatic test based on the test debs from gdebi
-rw-r--r--apt/cache.py24
-rw-r--r--apt/debfile.py280
-rw-r--r--apt/utils.py3
-rw-r--r--debian/changelog8
-rw-r--r--po/python-apt.pot191
-rw-r--r--tests/data/fake-packages/Packages21
-rw-r--r--tests/data/fake-packages/Packages.gzbin0 -> 555 bytes
-rw-r--r--tests/test_apt_cache.py22
-rw-r--r--tests/test_debfile.py56
-rw-r--r--tests/test_debs/gdebi-test1.debbin0 -> 934 bytes
-rw-r--r--tests/test_debs/gdebi-test10.debbin0 -> 614 bytes
-rw-r--r--tests/test_debs/gdebi-test2.debbin0 -> 554 bytes
-rw-r--r--tests/test_debs/gdebi-test3.debbin0 -> 570 bytes
-rw-r--r--tests/test_debs/gdebi-test4.debbin0 -> 2306 bytes
-rw-r--r--tests/test_debs/gdebi-test5.debbin0 -> 2306 bytes
-rw-r--r--tests/test_debs/gdebi-test6.debbin0 -> 4312 bytes
-rw-r--r--tests/test_debs/gdebi-test7.debbin0 -> 578 bytes
-rw-r--r--tests/test_debs/gdebi-test8.debbin0 -> 598 bytes
-rw-r--r--tests/test_debs/gdebi-test9.debbin0 -> 586 bytes
-rw-r--r--tests/test_progress.py44
20 files changed, 513 insertions, 136 deletions
diff --git a/apt/cache.py b/apt/cache.py
index 3962bb4f..26532c76 100644
--- a/apt/cache.py
+++ b/apt/cache.py
@@ -120,6 +120,7 @@ class Cache(object):
"""
if progress is None:
progress = apt.progress.base.OpProgress()
+ self.op_progress = progress
self._run_callbacks("cache_pre_open")
self._cache = apt_pkg.Cache(progress)
@@ -288,21 +289,28 @@ class Cache(object):
else:
return bool(pkg.has_provides and not pkg.has_versions)
- def get_providing_packages(self, virtual, candidate_only=True):
- """Return a list of all packages providing a virtual package.
+ def get_providing_packages(self, pkgname, candidate_only=True,
+ include_nonvirtual=False):
+ """Return a list of all packages providing a package.
Return a list of packages which provide the virtual package of the
- specified name. If 'candidate_only' is False, return all packages
- with at least one version providing the virtual package. Otherwise,
- return only those packages where the candidate version provides
- the virtual package.
+ specified name.
+
+ If 'candidate_only' is False, return all packages with at
+ least one version providing the virtual package. Otherwise,
+ return only those packages where the candidate version
+ provides the virtual package.
+
+ If 'include_nonvirtual' is True then it will search for all
+ packages providing pkgname, even if pkgname is not itself
+ a virtual pkg.
"""
providers = set()
get_candidate_ver = self._depcache.get_candidate_ver
try:
- vp = self._cache[virtual]
- if vp.has_versions:
+ vp = self._cache[pkgname]
+ if vp.has_versions and not include_nonvirtual:
return list(providers)
except KeyError:
return list(providers)
diff --git a/apt/debfile.py b/apt/debfile.py
index ccaa25e4..81cd1dd2 100644
--- a/apt/debfile.py
+++ b/apt/debfile.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2005-2009 Canonical
+# Copyright (c) 2005-2010 Canonical
#
# Author: Michael Vogt <michael.vogt@ubuntu.com>
#
@@ -17,45 +17,50 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
"""Classes for working with locally available Debian packages."""
+import apt
+import apt_inst
+import apt_pkg
+import gzip
import os
import sys
-import apt_inst
-import apt_pkg
from apt_pkg import gettext as _
-
-
-# Constants for comparing the local package file with the version in the cache
-(VERSION_NONE, VERSION_OUTDATED, VERSION_SAME, VERSION_NEWER) = range(4)
-
+from StringIO import StringIO
class NoDebArchiveException(IOError):
"""Exception which is raised if a file is no Debian archive."""
-
class DebPackage(object):
"""A Debian Package (.deb file)."""
+ # Constants for comparing the local package file with the version
+ # in the cache
+ (VERSION_NONE,
+ VERSION_OUTDATED,
+ VERSION_SAME,
+ VERSION_NEWER) = range(4)
+
_supported_data_members = ("data.tar.gz", "data.tar.bz2", "data.tar.lzma")
debug = 0
def __init__(self, filename=None, cache=None):
+ if cache is None:
+ cache = apt.Cache()
self._cache = cache
- self._need_pkgs = []
self._debfile = None
self.pkgname = ""
- self.filename = filename
self._sections = {}
- self._installed_conflicts = set()
- self._failure_string = ""
if filename:
self.open(filename)
def open(self, filename):
- " open given debfile "
+ """ open given debfile """
+ self._need_pkgs = []
+ self._installed_conflicts = set()
+ self._failure_string = ""
self.filename = filename
- self._debfile = apt_inst.DebFile(self.filename)
+ self._debfile = apt_inst.DebFile(open(self.filename))
control = self._debfile.control.extractdata("control")
self._sections = apt_pkg.TagSection(control)
self.pkgname = self._sections["Package"]
@@ -90,20 +95,35 @@ class DebPackage(object):
# check for virtual pkgs
if not depname in self._cache:
if self._cache.is_virtual_package(depname):
- self._dbg(3, "_isOrGroupSatisfied(): %s is virtual dep" %
- depname)
+ self._dbg(3, "_is_or_group_satisfied(): %s is virtual dep" % depname)
for pkg in self._cache.get_providing_packages(depname):
if pkg.is_installed:
return True
continue
-
+ # check real dependency
inst = self._cache[depname].installed
if inst is not None and apt_pkg.check_dep(inst.version, oper, ver):
return True
+
+ # if no real dependency is installed, check if there is
+ # a package installed that provides this dependency
+ # (e.g. scrollkeeper dependecies are provided by rarian-compat)
+ # but only do that if there is no version required in the
+ # dependency (we do not supprot versionized dependencies)
+ if not oper:
+ for ppkg in self._cache.get_providing_packages(
+ depname, include_nonvirtual=True):
+ if ppkg.is_installed:
+ self._dbg(3, "found installed '%s' that provides '%s'" % (ppkg.name, depname))
+ return True
return False
def _satisfy_or_group(self, or_group):
"""Try to satisfy the or_group."""
+
+ or_found = False
+ virtual_pkg = None
+
for dep in or_group:
depname, ver, oper = dep
@@ -136,19 +156,18 @@ class DebPackage(object):
or_str = ""
for dep in or_group:
or_str += dep[0]
- if dep != or_group[-1]:
+ if ver and oper:
+ or_str += " (%s %s)" % (dep[2], dep[1])
+ if dep != or_group[len(or_group)-1]:
or_str += "|"
- self._failure_string += _("Dependency is not satisfiable: %s\n" %
- or_str)
+ self._failure_string += _("Dependency is not satisfiable: %s\n") % or_str
return False
def _check_single_pkg_conflict(self, pkgname, ver, oper):
"""Return True if a pkg conflicts with a real installed/marked pkg."""
# FIXME: deal with conflicts against its own provides
# (e.g. Provides: ftp-server, Conflicts: ftp-server)
- self._dbg(3, "_checkSinglePkgConflict() pkg='%s' ver='%s' oper='%s'" %
- (pkgname, ver, oper))
-
+ self._dbg(3, "_check_single_pkg_conflict() pkg='%s' ver='%s' oper='%s'" % (pkgname, ver, oper))
pkg = self._cache[pkgname]
if pkg.is_installed:
pkgver = pkg.installed.version
@@ -163,7 +182,7 @@ class DebPackage(object):
if (apt_pkg.check_dep(pkgver, oper, ver) and not
self.replaces_real_pkg(pkgname, oper, ver)):
self._failure_string += _("Conflicts with the installed package "
- "'%s'" % pkg.name)
+ "'%s'") % pkg.name
return True
return False
@@ -171,6 +190,9 @@ class DebPackage(object):
"""Check the or-group for conflicts with installed pkgs."""
self._dbg(2, "_check_conflicts_or_group(): %s " % (or_group))
+ or_found = False
+ virtual_pkg = None
+
for dep in or_group:
depname = dep[0]
ver = dep[1]
@@ -187,7 +209,7 @@ class DebPackage(object):
if self.pkgname == pkg.name:
self._dbg(3, "conflict on self, ignoring")
continue
- if self._check_single_pkg_conflict(pkg.name, ver,
+ if self._check_single_pkg_conflict(pkg.name, ver,
oper):
self._installed_conflicts.add(pkg.name)
continue
@@ -209,7 +231,7 @@ class DebPackage(object):
"""List of package names on which this package depends on."""
depends = []
# find depends
- for key in "Depends", "PreDepends":
+ for key in "Depends", "Pre-Depends":
try:
depends.extend(apt_pkg.parse_depends(self._sections[key]))
except KeyError:
@@ -240,7 +262,7 @@ class DebPackage(object):
Return True if the deb packages replaces a real (not virtual)
packages named (pkgname, oper, ver).
"""
- self._dbg(3, "replacesPkg() %s %s %s" % (pkgname, oper, ver))
+ self._dbg(3, "replaces_real_pkg() %s %s %s" % (pkgname, oper, ver))
pkg = self._cache[pkgname]
if pkg.is_installed:
pkgver = pkg.installed.version
@@ -270,6 +292,68 @@ class DebPackage(object):
res = False
return res
+ def check_breaks_existing_packages(self):
+ """
+ check if installing the package would break exsisting
+ package on the system, e.g. system has:
+ smc depends on smc-data (= 1.4)
+ and user tries to installs smc-data 1.6
+ """
+ # show progress information as this step may take some time
+ size = float(len(self._cache))
+ steps = int(size/50)
+ debver = self._sections["Version"]
+ # 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):
+ if i%steps == 0:
+ self._cache.op_progress.update(float(i)/size*100.0)
+ if not pkg.is_installed:
+ continue
+ # check if the exising dependencies are still satisfied
+ # with the package
+ ver = pkg._pkg.current_ver
+ for dep_or in pkg.installed.dependencies:
+ for dep in dep_or.or_dependencies:
+ if dep.name == self.pkgname:
+ if not apt_pkg.check_dep(debver, dep.relation, dep.version):
+ self._dbg(2, "would break (depends) %s" % pkg.name)
+ # 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
+ self._failure_string += _("Breaks existing package '%(pkgname)s' dependency %(depname)s (%(deprelation)s %(depversion)s)") % {
+ 'pkgname' : pkg.name,
+ 'depname' : dep.name,
+ 'deprelation' : dep.relation,
+ 'depversion' : dep.version}
+ self._cache.op_progress.done()
+ return False
+ # now check if there are conflicts against this package on
+ # the existing system
+ 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 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
+ self._failure_string += _("Breaks existing package '%(pkgname)s' conflict: %(targetpkg)s (%(comptype)s %(targetver)s)") % {
+ 'pkgname' : pkg.name,
+ 'targetpkg' : c_or.target_pkg.name,
+ 'comptype' : c_or.comp_type,
+ 'targetver' : c_or.target_ver }
+ self._cache.op_progress.done()
+ return False
+ if c_or.target_pkg.name in provides:
+ self._dbg(2, "would break (conflicts) %s" % provides)
+ self._failure_string += _("Breaks existing package '%(pkgname)s' that conflict: '%(targetpkg)s'. But the '%(debfile)s' provides it via: '%(provides)s'") % {
+ 'provides' : ",".join(provides),
+ 'debfile' : self.filename,
+ 'targetpkg' : c_or.target_pkg.name,
+ 'pkgname' : pkg.name }
+ self._cache.op_progress.done()
+ return False
+ self._cache.op_progress.done()
+ return True
+
def compare_to_version_in_cache(self, use_installed=True):
"""Compare the package to the version available in the cache.
@@ -277,42 +361,49 @@ class DebPackage(object):
and if so in what version, returns one of (VERSION_NONE,
VERSION_OUTDATED, VERSION_SAME, VERSION_NEWER).
"""
- self._dbg(3, "compareToVersionInCache")
+ self._dbg(3, "compare_to_version_in_cache")
pkgname = self._sections["Package"]
debver = self._sections["Version"]
self._dbg(1, "debver: %s" % debver)
if pkgname in self._cache:
if use_installed and self._cache[pkgname].installed:
cachever = self._cache[pkgname].installed.version
- else:
+ elif not use_installed and self._cache[pkgname].candidate:
cachever = self._cache[pkgname].candidate.version
+ else:
+ return self.VERSION_NONE
if cachever is not None:
- cmpres = apt_pkg.version_compare(cachever, debver)
- self._dbg(1, "CompareVersion(debver,instver): %s" % cmpres)
- if cmpres == 0:
- return VERSION_SAME
- elif cmpres < 0:
- return VERSION_NEWER
- elif cmpres > 0:
- return VERSION_OUTDATED
- return VERSION_NONE
+ cmp = apt_pkg.version_compare(cachever, debver)
+ self._dbg(1, "CompareVersion(debver,instver): %s" % cmp)
+ if cmp == 0:
+ return self.VERSION_SAME
+ elif cmp < 0:
+ return self.VERSION_NEWER
+ elif cmp > 0:
+ return self.VERSION_OUTDATED
+ return self.VERSION_NONE
def check(self):
"""Check if the package is installable."""
self._dbg(3, "check_depends")
# check arch
+ if not "Architecture" in self._sections:
+ self._dbg(1, "ERROR: no architecture field")
+ self._failure_string = _("No Architecture field in the package")
+ 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)
+ self._failure_string = _("Wrong architecture '%s'") % arch
return False
# check version
- if self.compare_to_version_in_cache() == VERSION_OUTDATED:
- # the deb is older than the installed
- self._failure_string = _("A later version is already installed")
- return False
+ if self.compare_to_version_in_cache() == self.VERSION_OUTDATED:
+ if self._cache[self.pkgname].installed:
+ # the deb is older than the installed
+ self._failure_string = _("A later version is already installed")
+ return False
# FIXME: this sort of error handling sux
self._failure_string = ""
@@ -321,6 +412,11 @@ class DebPackage(object):
if not self.check_conflicts():
return False
+ # check if installing it would break anything on the
+ # current system
+ if not self.check_breaks_existing_packages():
+ return False
+
# try to satisfy the dependencies
if not self._satisfy_depends(self.depends):
return False
@@ -332,7 +428,7 @@ class DebPackage(object):
if self._cache._depcache.broken_count > 0:
self._failure_string = _("Failed to satisfy all dependencies "
- "(broken cache)")
+ "(broken cache)")
# clean the cache again
self._cache.clear()
return False
@@ -352,17 +448,16 @@ class DebPackage(object):
# check depends
for or_group in depends:
#print "or_group: %s" % or_group
- #print "or_group satified: %s" % self._is_or_group_satisfied(
- # or_group)
+ #print "or_group satified: %s" % self._is_or_group_satisfied(or_group)
if not self._is_or_group_satisfied(or_group):
if not self._satisfy_or_group(or_group):
return False
# now try it out in the cache
for pkg in self._need_pkgs:
try:
- self._cache[pkg].mark_install(fromUser=False)
- except SystemError:
- self._failure_string = _("Cannot install '%s'" % pkg)
+ self._cache[pkg].mark_install(from_user=False)
+ except SystemError, e:
+ self._failure_string = _("Cannot install '%s'") % pkg
self._cache.clear()
return False
return True
@@ -398,6 +493,75 @@ class DebPackage(object):
remove.append(pkg.name)
return (install, remove, unauthenticated)
+ @property
+ def control_filelist(self):
+ """ return the list of files in control.tar.gt """
+ try:
+ from debian.debfile import DebFile
+ except:
+ raise Exception(_("Python-debian module not available"))
+ content = []
+ for name in DebFile(self.filename).control:
+ if name and name != ".":
+ content.append(name)
+ return sorted(content)
+
+ def to_hex(self, in_data):
+ hex = ""
+ for (i, c) in enumerate(in_data):
+ if i%80 == 0:
+ hex += "\n"
+ hex += "%2.2x " % ord(c)
+ return hex
+
+ def to_strish(self, in_data):
+ s = ""
+ for c in in_data:
+ if ord(c) < 10 or ord(c) > 127:
+ s += " "
+ else:
+ s += c
+ return s
+
+ def _get_content(self, part, name, auto_decompress=True, auto_hex=True):
+ data = part.get_content(name)
+ # check for zip content
+ if name.endswith(".gz") and auto_decompress:
+ io = StringIO(data)
+ gz = gzip.GzipFile(fileobj=io)
+ data = _("Automatically decompressed:\n\n")
+ data += gz.read()
+ # auto-convert to hex
+ try:
+ data = unicode(data, "utf-8")
+ except Exception, e:
+ new_data = _("Automatically converted to printable ascii:\n")
+ new_data += self.to_strish(data)
+ return new_data
+ return data
+
+ def control_content(self, name):
+ """ return the content of a specific control.tar.gz file """
+ try:
+ from debian.debfile import DebFile
+ except:
+ raise Exception(_("Python-debian module not available"))
+ control = DebFile(self.filename).control
+ if name in control:
+ return self._get_content(control, name)
+ return ""
+
+ def data_content(self, name):
+ """ return the content of a specific control.tar.gz file """
+ try:
+ from debian.debfile import DebFile
+ except:
+ raise Exception(_("Python-debian module not available"))
+ data = DebFile(self.filename).data
+ if name in data:
+ return self._get_content(data, name)
+ return ""
+
def _dbg(self, level, msg):
"""Write debugging output to sys.stderr."""
if level <= self.debug:
@@ -419,18 +583,18 @@ class DebPackage(object):
install_progress.finishUpdate()
return res
-
class DscSrcPackage(DebPackage):
"""A locally available source package."""
def __init__(self, filename=None, cache=None):
DebPackage.__init__(self, None, cache)
+ self.filename = filename
self._depends = []
self._conflicts = []
self.pkgname = ""
self.binaries = []
- if filename is not None:
- self.open(filename)
+ if self.filename is not None:
+ self.open(self.filename)
@property
def depends(self):
@@ -446,7 +610,6 @@ class DscSrcPackage(DebPackage):
"""Open the package."""
depends_tags = ["Build-Depends", "Build-Depends-Indep"]
conflicts_tags = ["Build-Conflicts", "Build-Conflicts-Indep"]
-
fobj = open(file)
tagfile = apt_pkg.TagFile(fobj)
try:
@@ -481,11 +644,10 @@ class DscSrcPackage(DebPackage):
if self._cache[pkgname]._pkg.essential:
raise Exception(_("An essential package would be removed"))
self._cache[pkgname].mark_delete()
- # FIXME: a additional run of the checkConflicts()
- # after _satisfyDepends() should probably be done
+ # FIXME: a additional run of the check_conflicts()
+ # after _satisfy_depends() should probably be done
return self._satisfy_depends(self.depends)
-
def _test():
"""Test function"""
from apt.cache import Cache
@@ -494,7 +656,7 @@ def _test():
cache = Cache()
vp = "www-browser"
- #print "%s virtual: %s" % (vp, cache.isVirtualPackage(vp))
+ print "%s virtual: %s" % (vp, cache.is_virtual_package(vp))
providers = cache.get_providing_packages(vp)
print "Providers for %s :" % vp
for pkg in providers:
@@ -508,6 +670,8 @@ def _test():
print "missing deps: %s" % d.missing_deps
print d.required_changes
+ print d.filelist
+
print "Installing ..."
ret = d.install(DpkgInstallProgress())
print ret
diff --git a/apt/utils.py b/apt/utils.py
index 80ba6d65..4b3da39f 100644
--- a/apt/utils.py
+++ b/apt/utils.py
@@ -33,6 +33,9 @@ def get_maintenance_end_date(release_date, m_months):
support_end_year = (release_date.year + years +
(release_date.month + months)/12)
support_end_month = (release_date.month + months) % 12
+ if support_end_month == 0:
+ support_end_month = 12
+ support_end_year -= 1
return (support_end_year, support_end_month)
diff --git a/debian/changelog b/debian/changelog
index b1c7c1b5..b8ae49c1 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -15,6 +15,14 @@ python-apt (0.7.96) UNRELEASED; urgency=low
- add new "dpkg_journal_dirty" property that can be used to
detect a interrupted dpkg (the famous
"E: dpkg was interrupted, you must manually run 'dpkg --configure -a'")
+ * merged lp:~kiwinote/python-apt/merge-gdebi-changes, this port the
+ DebPackage class fixes from gdebi into python-apt so that gdebi can
+ use the class from python-apt directly
+ * apt/debfile.py:
+ - check if the debfiles provides are in conflict with the systems
+ packages
+ * tests/test_debs/*.deb, tests/test_debfile.py:
+ - add automatic test based on the test debs from gdebi
[ Martin Pitt ]
* tests/test_apt_cache.py: Test accessing the record of all packages during
diff --git a/po/python-apt.pot b/po/python-apt.pot
index b67d7988..9c10c43f 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: 2010-03-03 19:34+0100\n"
+"POT-Creation-Date: 2010-07-02 14:12+0200\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"
@@ -23,257 +23,267 @@ msgid "http://changelogs.ubuntu.com/changelogs/pool/%s/%s/%s/%s_%s/changelog"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:12
+#: ../data/templates/Ubuntu.info.in:13
+msgid "Ubuntu 10.10 'Maverick Meerkat'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:31
+msgid "Cdrom with Ubuntu 10.10 'Maverick Meerkat'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:74
msgid "Ubuntu 10.04 'Lucid Lynx'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:30
+#: ../data/templates/Ubuntu.info.in:92
msgid "Cdrom with Ubuntu 10.04 'Lucid Lynx'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:72
+#: ../data/templates/Ubuntu.info.in:135
msgid "Ubuntu 9.10 'Karmic Koala'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:90
+#: ../data/templates/Ubuntu.info.in:153
msgid "Cdrom with Ubuntu 9.10 'Karmic Koala'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:132
+#: ../data/templates/Ubuntu.info.in:196
msgid "Ubuntu 9.04 'Jaunty Jackalope'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:150
+#: ../data/templates/Ubuntu.info.in:214
msgid "Cdrom with Ubuntu 9.04 'Jaunty Jackalope'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:192
+#: ../data/templates/Ubuntu.info.in:257
msgid "Ubuntu 8.10 'Intrepid Ibex'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:210
+#: ../data/templates/Ubuntu.info.in:275
msgid "Cdrom with Ubuntu 8.10 'Intrepid Ibex'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:253
+#: ../data/templates/Ubuntu.info.in:319
msgid "Ubuntu 8.04 'Hardy Heron'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:271
+#: ../data/templates/Ubuntu.info.in:337
msgid "Cdrom with Ubuntu 8.04 'Hardy Heron'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:308
+#: ../data/templates/Ubuntu.info.in:382
msgid "Ubuntu 7.10 'Gutsy Gibbon'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:326
+#: ../data/templates/Ubuntu.info.in:400
msgid "Cdrom with Ubuntu 7.10 'Gutsy Gibbon'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:361
+#: ../data/templates/Ubuntu.info.in:445
msgid "Ubuntu 7.04 'Feisty Fawn'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:379
+#: ../data/templates/Ubuntu.info.in:463
msgid "Cdrom with Ubuntu 7.04 'Feisty Fawn'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:413
+#: ../data/templates/Ubuntu.info.in:505
msgid "Ubuntu 6.10 'Edgy Eft'"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:418
+#: ../data/templates/Ubuntu.info.in:510
msgid "Community-maintained"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:424
+#: ../data/templates/Ubuntu.info.in:516
msgid "Restricted software"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:431
+#: ../data/templates/Ubuntu.info.in:523
msgid "Cdrom with Ubuntu 6.10 'Edgy Eft'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:465
+#: ../data/templates/Ubuntu.info.in:565
msgid "Ubuntu 6.06 LTS 'Dapper Drake'"
msgstr ""
#. CompDescriptionLong
-#: ../data/templates/Ubuntu.info.in:468
+#: ../data/templates/Ubuntu.info.in:568
msgid "Canonical-supported Open Source software"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:470
+#: ../data/templates/Ubuntu.info.in:570
msgid "Community-maintained (universe)"
msgstr ""
#. CompDescriptionLong
-#: ../data/templates/Ubuntu.info.in:471
+#: ../data/templates/Ubuntu.info.in:571
msgid "Community-maintained Open Source software"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:473
+#: ../data/templates/Ubuntu.info.in:573
msgid "Non-free drivers"
msgstr ""
#. CompDescriptionLong
-#: ../data/templates/Ubuntu.info.in:474
+#: ../data/templates/Ubuntu.info.in:574
msgid "Proprietary drivers for devices"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:476
+#: ../data/templates/Ubuntu.info.in:576
msgid "Restricted software (Multiverse)"
msgstr ""
#. CompDescriptionLong
-#: ../data/templates/Ubuntu.info.in:477
+#: ../data/templates/Ubuntu.info.in:577
msgid "Software restricted by copyright or legal issues"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:483
+#: ../data/templates/Ubuntu.info.in:583
msgid "Cdrom with Ubuntu 6.06 LTS 'Dapper Drake'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:495
+#: ../data/templates/Ubuntu.info.in:599
msgid "Important security updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:500
+#: ../data/templates/Ubuntu.info.in:604
msgid "Recommended updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:505
+#: ../data/templates/Ubuntu.info.in:609
msgid "Pre-released updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:510
+#: ../data/templates/Ubuntu.info.in:614
msgid "Unsupported updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:517
+#: ../data/templates/Ubuntu.info.in:625
msgid "Ubuntu 5.10 'Breezy Badger'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:531
+#: ../data/templates/Ubuntu.info.in:639
msgid "Cdrom with Ubuntu 5.10 'Breezy Badger'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:543
+#: ../data/templates/Ubuntu.info.in:655
msgid "Ubuntu 5.10 Security Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:548
+#: ../data/templates/Ubuntu.info.in:660
msgid "Ubuntu 5.10 Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:553
+#: ../data/templates/Ubuntu.info.in:665
msgid "Ubuntu 5.10 Backports"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:560
+#: ../data/templates/Ubuntu.info.in:676
msgid "Ubuntu 5.04 'Hoary Hedgehog'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:574
+#: ../data/templates/Ubuntu.info.in:690
msgid "Cdrom with Ubuntu 5.04 'Hoary Hedgehog'"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:577 ../data/templates/Debian.info.in:149
+#: ../data/templates/Ubuntu.info.in:693 ../data/templates/Debian.info.in:149
msgid "Officially supported"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:586
+#: ../data/templates/Ubuntu.info.in:706
msgid "Ubuntu 5.04 Security Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:591
+#: ../data/templates/Ubuntu.info.in:711
msgid "Ubuntu 5.04 Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:596
+#: ../data/templates/Ubuntu.info.in:716
msgid "Ubuntu 5.04 Backports"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:602
+#: ../data/templates/Ubuntu.info.in:722
msgid "Ubuntu 4.10 'Warty Warthog'"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:608
+#: ../data/templates/Ubuntu.info.in:728
msgid "Community-maintained (Universe)"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:610
+#: ../data/templates/Ubuntu.info.in:730
msgid "Non-free (Multiverse)"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:616
+#: ../data/templates/Ubuntu.info.in:736
msgid "Cdrom with Ubuntu 4.10 'Warty Warthog'"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:619
+#: ../data/templates/Ubuntu.info.in:739
msgid "No longer officially supported"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:621
+#: ../data/templates/Ubuntu.info.in:741
msgid "Restricted copyright"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:628
+#: ../data/templates/Ubuntu.info.in:748
msgid "Ubuntu 4.10 Security Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:633
+#: ../data/templates/Ubuntu.info.in:753
msgid "Ubuntu 4.10 Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:638
+#: ../data/templates/Ubuntu.info.in:758
msgid "Ubuntu 4.10 Backports"
msgstr ""
@@ -384,11 +394,11 @@ msgstr ""
msgid "Invalid unicode in description for '%s' (%s). Please report."
msgstr ""
-#: ../apt/package.py:999 ../apt/package.py:1105
+#: ../apt/package.py:1007 ../apt/package.py:1112
msgid "The list of changes is not available"
msgstr ""
-#: ../apt/package.py:1109
+#: ../apt/package.py:1118
#, python-format
msgid ""
"The list of changes is not available yet.\n"
@@ -397,52 +407,97 @@ msgid ""
"until the changes become available or try again later."
msgstr ""
-#: ../apt/package.py:1115
+#: ../apt/package.py:1125
msgid ""
"Failed to download the list of changes. \n"
"Please check your Internet connection."
msgstr ""
-#: ../apt/debfile.py:73
+#: ../apt/debfile.py:142
#, python-format
-msgid "List of files for '%s' could not be read"
+msgid "Dependency is not satisfiable: %s\n"
msgstr ""
-#: ../apt/debfile.py:141
+#: ../apt/debfile.py:163
#, python-format
-msgid "Dependency is not satisfiable: %s\n"
+msgid "Conflicts with the installed package '%s'"
msgstr ""
-#: ../apt/debfile.py:165
+#. 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:297
#, python-format
-msgid "Conflicts with the installed package '%s'"
+msgid ""
+"Breaks existing package '%(pkgname)s' dependency %(depname)s (%(deprelation)"
+"s %(depversion)s)"
msgstr ""
-#: ../apt/debfile.py:308
+#. 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:313
+#, python-format
+msgid ""
+"Breaks existing package '%(pkgname)s' conflict: %(targetpkg)s (%(comptype)s %"
+"(targetver)s)"
+msgstr ""
+
+#: ../apt/debfile.py:359
+msgid "No Architecture field in the package"
+msgstr ""
+
+#: ../apt/debfile.py:364
#, python-format
msgid "Wrong architecture '%s'"
msgstr ""
#. the deb is older than the installed
-#: ../apt/debfile.py:314
+#: ../apt/debfile.py:371
msgid "A later version is already installed"
msgstr ""
-#: ../apt/debfile.py:334
+#: ../apt/debfile.py:396
msgid "Failed to satisfy all dependencies (broken cache)"
msgstr ""
-#: ../apt/debfile.py:365
+#: ../apt/debfile.py:425
#, python-format
msgid "Cannot install '%s'"
msgstr ""
-#: ../apt/debfile.py:472
+#: ../apt/debfile.py:467 ../apt/debfile.py:513 ../apt/debfile.py:524
+msgid "Python-debian module not available"
+msgstr ""
+
+#: ../apt/debfile.py:497
+msgid ""
+"Automatically decompressed:\n"
+"\n"
+msgstr ""
+
+#: ../apt/debfile.py:503
+msgid "Automatically converted to printable ascii:\n"
+msgstr ""
+
+#: ../apt/debfile.py:549
+msgid "List of files could not be read, please report this as a bug"
+msgstr ""
+
+#: ../apt/debfile.py:552
+#, python-format
+msgid "IOError during filelist read: %s"
+msgstr ""
+
+#. Translators: it's for missing entries in the deb package,
+#. e.g. a missing "Maintainer" field
+#: ../apt/debfile.py:559
+#, python-format
+msgid "%s is not available"
+msgstr ""
+
+#: ../apt/debfile.py:632
#, python-format
msgid "Install Build-Dependencies for source package '%s' that builds %s\n"
msgstr ""
-#: ../apt/debfile.py:482
+#: ../apt/debfile.py:642
msgid "An essential package would be removed"
msgstr ""
@@ -493,6 +548,6 @@ msgstr ""
msgid "Please insert a Disc in the drive and press enter"
msgstr ""
-#: ../apt/cache.py:131
+#: ../apt/cache.py:135
msgid "Building data structures"
msgstr ""
diff --git a/tests/data/fake-packages/Packages b/tests/data/fake-packages/Packages
new file mode 100644
index 00000000..9fbab957
--- /dev/null
+++ b/tests/data/fake-packages/Packages
@@ -0,0 +1,21 @@
+Package: 2vcard
+Priority: optional
+Section: universe/utils
+Installed-Size: 108
+Maintainer: Arvind Autar <Autar022@planet.nl>
+Architecture: amd64
+Version: 0.5-1ubuntu1
+Filename: pool/universe/2/2vcard/2vcard_0.5-1ubuntu1_amd64.deb
+Size: 14164
+MD5sum: 105ea91f0a75417d0f9e8e9624513b2a
+SHA1: d55beee01c08efc33cd131e106330dca72ee14be
+SHA256: 4a72edaf87cdb826e5508b85311fcf0bec9b7e019a55740ded7feb1b9e197f11
+Description: A little perl script to convert an adressbook to VCARD file format
+ 2vcard is a little perl script that you can use to convert the popular vcard
+ file format. Currently 2vcard can only convert adressbooks and alias files from
+ the following formats: abook,eudora,juno,ldif,mutt,mh and pine.
+ .
+ The VCARD format is used by gnomecard, for example, which is turn is used by
+ the balsa email client.
+Bugs: mailto:ubuntu-users@lists.ubuntu.com
+Origin: Ubuntu
diff --git a/tests/data/fake-packages/Packages.gz b/tests/data/fake-packages/Packages.gz
new file mode 100644
index 00000000..506bc8d4
--- /dev/null
+++ b/tests/data/fake-packages/Packages.gz
Binary files differ
diff --git a/tests/test_apt_cache.py b/tests/test_apt_cache.py
index b27ed778..653a0f48 100644
--- a/tests/test_apt_cache.py
+++ b/tests/test_apt_cache.py
@@ -6,12 +6,15 @@
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.
"""Unit tests for verifying the correctness of check_dep, etc in apt_pkg."""
+import os
+import tempfile
import unittest
+import sys
+sys.path.insert(0, "..")
+
import apt
import apt_pkg
-import os
-import tempfile
class TestAptCache(unittest.TestCase):
@@ -42,6 +45,21 @@ class TestAptCache(unittest.TestCase):
self.assert_(len(r['Description']) > 0)
self.assert_(str(r).startswith('Package: %s\n' % pkg.name))
+ def test_get_provided_packages(self):
+ cache = apt.Cache()
+ # a true virtual pkg
+ l = cache.get_providing_packages("mail-transport-agent")
+ self.assertTrue(len(l) > 0)
+ # this is a not virtual (transitional) package provided by another
+ l = cache.get_providing_packages("scrollkeeper")
+ self.assertEqual(l, [])
+ # now inlcude nonvirtual packages in the search (rarian-compat
+ # provides scrollkeeper)
+ l = cache.get_providing_packages("scrollkeeper",
+ include_nonvirtual=True)
+ self.assertTrue(len(l), 1)
+
+
def test_dpkg_journal_dirty(self):
# backup old value
old_status = apt_pkg.Config.find_file("Dir::State::status")
diff --git a/tests/test_debfile.py b/tests/test_debfile.py
new file mode 100644
index 00000000..02e25117
--- /dev/null
+++ b/tests/test_debfile.py
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+#
+# 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
+
+import sys
+sys.path.insert(0, "..")
+
+import apt.debfile
+
+
+class TestDebfilee(unittest.TestCase):
+ """ test the apt cache """
+
+ TEST_DEBS = [
+ # conflicts with apt
+ ('gdebi-test1.deb', False),
+ # impossible dependency
+ ('gdebi-test2.deb', False),
+ # or-group (impossible-dependency|apt)
+ ('gdebi-test3.deb', True),
+ # Conflicts: apt (<= 0.1)
+ ('gdebi-test4.deb', True),
+ # Conflicts: apt (>= 0.1)
+ ('gdebi-test5.deb', False),
+ # invalid unicode in descr
+ ('gdebi-test6.deb', True),
+ # provides/conflicts against "foobarbaz"
+ ('gdebi-test7.deb', True),
+ # provides/conflicts/replaces against "mail-transport-agent"
+ # (should fails if mail-transport-agent is installed)
+ ('gdebi-test8.deb', False),
+ # provides/conflicts against real pkg
+ ('gdebi-test9.deb', True),
+ # provides debconf-tiny and the real debconf conflicts with
+ ('gdebi-test10.deb', False),
+ ]
+
+ def testDebFile(self):
+ deb = apt.debfile.DebPackage()
+ for (filename, expected_res) in self.TEST_DEBS:
+ logging.debug("testing %s, expecting %s" % (filename, expected_res))
+ deb.open(os.path.join("test_debs", filename))
+ res = deb.check()
+ self.assertEqual(res, expected_res)
+
+if __name__ == "__main__":
+ #logging.basicConfig(level=logging.DEBUG)
+ unittest.main()
diff --git a/tests/test_debs/gdebi-test1.deb b/tests/test_debs/gdebi-test1.deb
new file mode 100644
index 00000000..ea9991ac
--- /dev/null
+++ b/tests/test_debs/gdebi-test1.deb
Binary files differ
diff --git a/tests/test_debs/gdebi-test10.deb b/tests/test_debs/gdebi-test10.deb
new file mode 100644
index 00000000..ca43ace6
--- /dev/null
+++ b/tests/test_debs/gdebi-test10.deb
Binary files differ
diff --git a/tests/test_debs/gdebi-test2.deb b/tests/test_debs/gdebi-test2.deb
new file mode 100644
index 00000000..307ac689
--- /dev/null
+++ b/tests/test_debs/gdebi-test2.deb
Binary files differ
diff --git a/tests/test_debs/gdebi-test3.deb b/tests/test_debs/gdebi-test3.deb
new file mode 100644
index 00000000..436b9258
--- /dev/null
+++ b/tests/test_debs/gdebi-test3.deb
Binary files differ
diff --git a/tests/test_debs/gdebi-test4.deb b/tests/test_debs/gdebi-test4.deb
new file mode 100644
index 00000000..9eb92d1b
--- /dev/null
+++ b/tests/test_debs/gdebi-test4.deb
Binary files differ
diff --git a/tests/test_debs/gdebi-test5.deb b/tests/test_debs/gdebi-test5.deb
new file mode 100644
index 00000000..0c98c03f
--- /dev/null
+++ b/tests/test_debs/gdebi-test5.deb
Binary files differ
diff --git a/tests/test_debs/gdebi-test6.deb b/tests/test_debs/gdebi-test6.deb
new file mode 100644
index 00000000..32fd1800
--- /dev/null
+++ b/tests/test_debs/gdebi-test6.deb
Binary files differ
diff --git a/tests/test_debs/gdebi-test7.deb b/tests/test_debs/gdebi-test7.deb
new file mode 100644
index 00000000..c0414990
--- /dev/null
+++ b/tests/test_debs/gdebi-test7.deb
Binary files differ
diff --git a/tests/test_debs/gdebi-test8.deb b/tests/test_debs/gdebi-test8.deb
new file mode 100644
index 00000000..439f8ca7
--- /dev/null
+++ b/tests/test_debs/gdebi-test8.deb
Binary files differ
diff --git a/tests/test_debs/gdebi-test9.deb b/tests/test_debs/gdebi-test9.deb
new file mode 100644
index 00000000..9901d906
--- /dev/null
+++ b/tests/test_debs/gdebi-test9.deb
Binary files differ
diff --git a/tests/test_progress.py b/tests/test_progress.py
new file mode 100644
index 00000000..2ab8ce5e
--- /dev/null
+++ b/tests/test_progress.py
@@ -0,0 +1,44 @@
+#!/usr/bin/python
+#
+# 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 apt.progress"""
+import unittest
+
+import apt
+import apt_pkg
+import os
+
+class TestAcquireProgress(apt.progress.base.AcquireProgress):
+ def pulse(self, owner):
+ self.pulsed = True
+
+class TestProgress(unittest.TestCase):
+
+ def setUp(self):
+ basedir = os.path.abspath(os.path.dirname(__file__))
+ # setup apt_pkg config
+ apt_pkg.init()
+ apt_pkg.config.set("APT::Architecture", "amd64")
+ apt_pkg.config.set("Dir::Etc", basedir)
+ apt_pkg.config.set("Dir::Etc::sourceparts", "/xxx")
+ # setup lists dir
+ if not os.path.exists("./tmp/partial"):
+ os.makedirs("./tmp/partial")
+ apt_pkg.config.set("Dir::state::lists", "./tmp")
+ # create artifical line
+ deb_line = "deb file:%s/data/fake-packages/ /\n" % basedir
+ open("fetch_sources.list","w").write(deb_line)
+ apt_pkg.config.set("Dir::Etc::sourcelist", "fetch_sources.list")
+
+ def test_acquire_progress(self):
+ progress = TestAcquireProgress()
+ cache = apt.Cache()
+ res = cache.update(progress)
+ self.assertTrue(progress.pulsed)
+
+if __name__ == "__main__":
+ unittest.main()