summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vogt <michael.vogt@ubuntu.com>2010-07-28 11:09:00 +0200
committerMichael Vogt <michael.vogt@ubuntu.com>2010-07-28 11:09:00 +0200
commitcee5d33d44130ce8ceb7b563f7b97f2bf9a3ca5c (patch)
tree8157a049457a566f6ac5b2e665cba01629aadd58
parent3b4330920da718d2dbb2a4a94577c07eaa58a8c5 (diff)
parentd642c9ea22f5705acfcba79493f48293626771c3 (diff)
downloadpython-apt-cee5d33d44130ce8ceb7b563f7b97f2bf9a3ca5c.tar.gz
merged from the debian-sid bzr branch
-rw-r--r--apt/__init__.py1
-rw-r--r--apt/cache.py52
-rw-r--r--apt/debfile.py285
-rw-r--r--debian/changelog99
-rw-r--r--debian/control6
-rwxr-xr-xdebian/rules4
-rw-r--r--doc/source/conf.py9
-rw-r--r--doc/source/library/apt_pkg.rst4
-rw-r--r--po/python-apt.pot289
-rw-r--r--python/apt_pkgmodule.cc2
-rw-r--r--python/progress.cc5
-rw-r--r--python/tag.cc5
-rw-r--r--tests/data/fake-packages/Packages21
-rw-r--r--tests/data/fake-packages/Packages.gzbin0 -> 555 bytes
-rw-r--r--tests/data/test_debs/gdebi-test1.debbin0 -> 934 bytes
-rw-r--r--tests/data/test_debs/gdebi-test10.debbin0 -> 614 bytes
-rw-r--r--tests/data/test_debs/gdebi-test2.debbin0 -> 554 bytes
-rw-r--r--tests/data/test_debs/gdebi-test3.debbin0 -> 570 bytes
-rw-r--r--tests/data/test_debs/gdebi-test4.debbin0 -> 2306 bytes
-rw-r--r--tests/data/test_debs/gdebi-test5.debbin0 -> 2306 bytes
-rw-r--r--tests/data/test_debs/gdebi-test6.debbin0 -> 600 bytes
-rw-r--r--tests/data/test_debs/gdebi-test7.debbin0 -> 578 bytes
-rw-r--r--tests/data/test_debs/gdebi-test8.debbin0 -> 598 bytes
-rw-r--r--tests/data/test_debs/gdebi-test9.debbin0 -> 586 bytes
-rw-r--r--tests/data/test_debs/var/lib/dpkg/status53
-rw-r--r--tests/test_all.py32
-rw-r--r--tests/test_apt_cache.py53
-rw-r--r--tests/test_aptsources.py4
-rw-r--r--tests/test_debfile.py66
-rw-r--r--tests/test_progress.py47
-rwxr-xr-xutils/pyversions2
31 files changed, 854 insertions, 185 deletions
diff --git a/apt/__init__.py b/apt/__init__.py
index a8a8b8fc..677a625b 100644
--- a/apt/__init__.py
+++ b/apt/__init__.py
@@ -16,7 +16,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
-
# import the core of apt_pkg
"""High-Level Interface for working with apt."""
import apt_pkg
diff --git a/apt/cache.py b/apt/cache.py
index 8e07e4d0..f64b489a 100644
--- a/apt/cache.py
+++ b/apt/cache.py
@@ -19,6 +19,7 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
+import fnmatch
import os
import weakref
@@ -64,6 +65,7 @@ class Cache(object):
self._callbacks = {}
self._weakref = weakref.WeakValueDictionary()
self._set = set()
+ self._sorted_set = None
if memonly:
# force apt to build its caches in memory
apt_pkg.config.set("Dir::Cache::pkgcache", "")
@@ -118,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)
@@ -126,6 +129,7 @@ class Cache(object):
self._list = apt_pkg.SourceList()
self._list.read_main_list()
self._set.clear()
+ self._sorted_set = None
self._weakref.clear()
progress.op = _("Building data structures")
@@ -157,7 +161,15 @@ class Cache(object):
raise KeyError('The cache has no package named %r' % key)
def __iter__(self):
- for pkgname in self._set:
+ # We iterate sorted over package names here. With this we read the
+ # package lists linearly if we need to access the package records,
+ # instead of having to do thousands of random seeks; the latter
+ # is disastrous if we use compressed package indexes, and slower than
+ # necessary for uncompressed indexes.
+ if self._sorted_set is None:
+ self._sorted_set = sorted(self._set)
+
+ for pkgname in self._sorted_set:
yield self[pkgname]
raise StopIteration
@@ -277,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)
@@ -445,6 +464,21 @@ class Cache(object):
return apt_pkg.ActionGroup(self._depcache)
@property
+ def dpkg_journal_dirty(self):
+ """Return True if the dpkg was interrupted
+
+ All dpkg operations will fail until this is fixed, the action to
+ fix the system if dpkg got interrupted is to run
+ 'dpkg --configure -a' as root.
+ """
+ dpkg_status_dir = os.path.dirname(
+ apt_pkg.config.find_file("Dir::State::status"))
+ for f in os.listdir(os.path.join(dpkg_status_dir, "updates")):
+ if fnmatch.fnmatch(f, "[0-9]*"):
+ return True
+ return False
+
+ @property
def broken_count(self):
"""Return the number of packages with broken dependencies."""
return self._depcache.broken_count
diff --git a/apt/debfile.py b/apt/debfile.py
index ccaa25e4..ea83c5b3 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,47 +17,53 @@
# 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)
+ # hm, 'replace' is probably better but python2.6 test fail with that
+ self._sections = apt_pkg.TagSection(control.decode("UTF-8", 'ignore'))
self.pkgname = self._sections["Package"]
def __getitem__(self, key):
@@ -90,20 +96,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 +157,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 +183,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 +191,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 +210,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 +232,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 +263,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 +293,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 = max(int(size/50), 1)
+ 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 +362,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 +413,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 +429,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 +449,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 +494,77 @@ 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)
+
+ @staticmethod
+ 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
+
+ @staticmethod
+ 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 +586,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 +613,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 +647,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 +659,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 +673,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/debian/changelog b/debian/changelog
index 9fe79188..d95f87e5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,75 @@
+python-apt (0.7.96.1ubuntu1) maverick; urgency=low
+
+ [ Julian Andres Klode ]
+ * python/tag.cc:
+ - Support gzip compression for control files (Closes: #383617),
+ requires APT (>> 0.7.26~exp10) to work.
+ * doc/conf.py:
+ - Correctly handle non-digit characters in version (ignore everything
+ after them).
+ * python/apt_pkgmodule.cc:
+ - Bind pkgAcquire::Item::StatTransientNetworkError (Closes: #589010)
+
+ [ Michael Vogt ]
+ * merge from debian-sid bzr branch, remaining changes:
+ - do not build for python2.5
+
+ -- Michael Vogt <michael.vogt@ubuntu.com> Wed, 28 Jul 2010 10:54:25 +0200
+
+python-apt (0.7.96.1) unstable; urgency=low
+
+ * tests/test_debfile.py:
+ - properly setup fixture data to make debfile test pass
+ (closes: #588796)
+
+ -- Michael Vogt <mvo@debian.org> Mon, 12 Jul 2010 14:14:51 +0200
+
+python-apt (0.7.96) unstable; urgency=low
+
+ [ Michael Vogt ]
+ * data/templates/gNewSense.info.in,
+ data/templates/gNewSense.mirrors:
+ - add gNewSense template and mirrors, thanks to Karl Goetz
+ * data/templates/Ubuntu.info.in,
+ data/templates/Ubuntu.mirrors:
+ - updated for Ubuntu maverick
+ * doc/source/conf.py:
+ - do not fail on non-digits in the version number
+ * utils/get_debian_mirrors.py:
+ - ignore mirrors without a county
+ * apt/cache.py:
+ - 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
+ - fix py3 compatibility
+ * tests/test_debs/*.deb, tests/test_debfile.py:
+ - add automatic test based on the test debs from gdebi
+ * python/progress.cc:
+ - deal with missing return value from the acquire progress in pulse()
+
+ [ Martin Pitt ]
+ * tests/test_apt_cache.py: Test accessing the record of all packages during
+ iteration. This both ensures that it's well-formatted and structured, and
+ also that accessing it does not take an inordinate amount of time. This
+ exposes a severe performance problem when using gzip compressed package
+ indexes.
+ * apt/cache.py: When iterating over the cache, do so sorted by package name.
+ With this we read the the package lists linearly if we need to access the
+ package records, instead of having to do thousands of random seeks; the
+ latter is disastrous if we use compressed package indexes, and slower than
+ necessary for uncompressed indexes.
+
+ [ Julian Andres Klode ]
+ * Re-enable Python 3 support for latest python-default changes (hack).
+
+ -- Michael Vogt <mvo@debian.org> Mon, 12 Jul 2010 08:58:42 +0200
+
python-apt (0.7.95ubuntu2) maverick; urgency=low
* apt/utils.py:
@@ -751,6 +823,9 @@ python-apt (0.7.11.0) unstable; urgency=low
(LP: #372224)
* python/progress.cc:
- fix crash in RunSimpleCallback()
+ * apt/cache.py:
+ - when the cache is run with a alternative rootdir, create
+ required dirs/files automatically
-- Michael Vogt <mvo@debian.org> Mon, 20 Jul 2009 15:35:27 +0200
@@ -1026,7 +1101,7 @@ python-apt (0.7.9~exp2) experimental; urgency=low
* Merge Ben Finney's do not use has_key() (Closes: #481878)
* Do not use deprecated form of raise statement (Closes: #494259)
* Add support for PkgRecords.SHA256Hash (Closes: #456113)
-
+
[ Michael Vogt ]
* apt/package.py:
- fix bug in candidateInstalledSize property
@@ -1036,7 +1111,7 @@ python-apt (0.7.9~exp2) experimental; urgency=low
- only add nearest_server and server to the mirrors if
they are defined
- -- Julian Andres Klode <jak@debian.org> Sun, 11 Jan 2009 20:01:59 +0100
+ -- Michael Vogt <mvo@debian.org> Fri, 16 Jan 2009 11:28:17 +0100
python-apt (0.7.9~exp1) experimental; urgency=low
@@ -1227,7 +1302,7 @@ python-apt (0.7.7.1) unstable; urgency=low
* aptsources/distinfo.py:
- fix template matching for arch specific code (LP: #244093)
- -- Michael Vogt <michael.vogt@ubuntu.com> Fri, 25 Jul 2008 18:34:28 +0200
+ -- Michael Vogt <mvo@debian.org> Fri, 25 Jul 2008 18:13:53 +0200
python-apt (0.7.7ubuntu2) intrepid; urgency=low
@@ -1266,7 +1341,7 @@ python-apt (0.7.7) unstable; urgency=low
[ Michael Vogt ]
* python/apt_pkgmodule.cc:
- fix bug in hashsum calculation when the original string
- contains \0 charackters (thanks to Celso Providelo and
+ contains \0 charackters (thanks to Celso Providelo and
Ryan Hass for the test-case) LP: #243630
* tests/test_hashsums.py:
- add tests for the hashsum code
@@ -1346,14 +1421,14 @@ python-apt (0.7.5) unstable; urgency=low
- export the Homepage field
* python/tar.cc:
- fix .lzma extraction (thanks to bigjools)
- * python/sourcelist.cc:
- - support GetIndexes() GetAll argument to implement
- something like --print-uris
- * python/apt_pkgmodule.cc:
- - add InstState{Ok,ReInstReq,Hold,HoldReInstReq} constants
- * apt/cache.py:
- - add reqReinstallPkgs property that lists all packages in
- ReInstReq or HoldReInstReq
+ * python/sourcelist.cc:
+ - support GetIndexes() GetAll argument to implement
+ something like --print-uris
+ * python/apt_pkgmodule.cc:
+ - add InstState{Ok,ReInstReq,Hold,HoldReInstReq} constants
+ * apt/cache.py:
+ - add reqReinstallPkgs property that lists all packages in
+ ReInstReq or HoldReInstReq
-- Michael Vogt <mvo@debian.org> Tue, 19 Feb 2008 21:06:36 +0100
diff --git a/debian/control b/debian/control
index b553dee7..65f72367 100644
--- a/debian/control
+++ b/debian/control
@@ -9,8 +9,8 @@ XS-Python-Version: all
Build-Depends: apt-utils,
debhelper (>= 7.3.5),
libapt-pkg-dev (>= 0.7.22~),
- python-all-dbg,
python-all-dev,
+ python-all-dbg,
python-central (>= 0.5),
python-distutils-extra (>= 2.0),
python-sphinx (>= 0.5)
@@ -19,8 +19,8 @@ Vcs-Browser: http://bzr.debian.org/loggerhead/apt/python-apt/debian-sid/changes
Package: python-apt
Architecture: any
-Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, lsb-release
-Recommends: iso-codes
+Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}
+Recommends: lsb-release, iso-codes, python2.6
Breaks: debdelta (<< 0.28~), packagekit-backend-apt (<= 0.4.8-0ubuntu4)
Provides: ${python:Provides}
Suggests: python-apt-dbg, python-gtk2, python-vte, python-apt-doc
diff --git a/debian/rules b/debian/rules
index cc1cabee..f7cca130 100755
--- a/debian/rules
+++ b/debian/rules
@@ -3,6 +3,8 @@
export DH_PYCENTRAL=nomove
export DEBVER=$(shell dpkg-parsechangelog | sed -n -e 's/^Version: //p')
export CFLAGS=-Wno-write-strings -DCOMPAT_0_7
+export PATH :=$(CURDIR)/utils:$(PATH)
+export SHELL = env PATH=$(PATH) sh
%:
dh --with python-central $@
@@ -20,7 +22,7 @@ override_dh_installdocs:
override_dh_strip:
dh_strip --dbg-package=python-apt-dbg
-
+
override_dh_compress:
dh_compress -X.js -X_static/* -X _sources/* -X_sources/*/* -X.inv
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 05490da7..18c8642e 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -78,8 +78,13 @@ except KeyError:
release = p2.communicate()[0]
# Handle the alpha release scheme
-release_raw = release.split("~")[0].split(".")[2]
-if release_raw.isdigit() and int(release_raw) >= 90:
+release_raw = "0"
+for c in release.split("~")[0].split(".")[2]:
+ if not c.isdigit():
+ break
+ release_raw += c
+
+if int(release_raw) >= 90:
version_s = release.split("~")[0].split(".")[:3]
# Set the version to 0.X.100 if the release is 0.X.9Y (0.7.90 => 0.7.100)
# Use
diff --git a/doc/source/library/apt_pkg.rst b/doc/source/library/apt_pkg.rst
index dd958959..b91790db 100644
--- a/doc/source/library/apt_pkg.rst
+++ b/doc/source/library/apt_pkg.rst
@@ -1381,6 +1381,10 @@ installation.
The item is yet to be fetched.
+ .. attribute:: STAT_TRANSIENT_NETWORK_ERROR
+
+ There was a network error.
+
.. class:: AcquireFile(owner, uri[, md5, size, descr, short_descr, destdir, destfile])
diff --git a/po/python-apt.pot b/po/python-apt.pot
index b7168e6e..0d683700 100644
--- a/po/python-apt.pot
+++ b/po/python-apt.pot
@@ -8,10 +8,11 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-08-21 15:34+0200\n"
+"POT-Creation-Date: 2010-07-12 09:45+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"
+"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -24,236 +25,266 @@ msgstr ""
#. Description
#: ../data/templates/Ubuntu.info.in:13
-msgid "Ubuntu 9.04 'Jaunty Jackalope'"
+msgid "Ubuntu 10.10 'Maverick Meerkat'"
msgstr ""
#. Description
#: ../data/templates/Ubuntu.info.in:31
-msgid "Cdrom with Ubuntu 9.04 'Jaunty Jackalope'"
+msgid "Cdrom with Ubuntu 10.10 'Maverick Meerkat'"
msgstr ""
#. Description
#: ../data/templates/Ubuntu.info.in:74
-msgid "Ubuntu 8.10 'Intrepid Ibex'"
+msgid "Ubuntu 10.04 'Lucid Lynx'"
msgstr ""
#. Description
#: ../data/templates/Ubuntu.info.in:92
+msgid "Cdrom with Ubuntu 10.04 'Lucid Lynx'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:135
+msgid "Ubuntu 9.10 'Karmic Koala'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:153
+msgid "Cdrom with Ubuntu 9.10 'Karmic Koala'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:196
+msgid "Ubuntu 9.04 'Jaunty Jackalope'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:214
+msgid "Cdrom with Ubuntu 9.04 'Jaunty Jackalope'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:257
+msgid "Ubuntu 8.10 'Intrepid Ibex'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Ubuntu.info.in:275
msgid "Cdrom with Ubuntu 8.10 'Intrepid Ibex'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:136
+#: ../data/templates/Ubuntu.info.in:319
msgid "Ubuntu 8.04 'Hardy Heron'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:154
+#: ../data/templates/Ubuntu.info.in:337
msgid "Cdrom with Ubuntu 8.04 'Hardy Heron'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:191
+#: ../data/templates/Ubuntu.info.in:382
msgid "Ubuntu 7.10 'Gutsy Gibbon'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:209
+#: ../data/templates/Ubuntu.info.in:400
msgid "Cdrom with Ubuntu 7.10 'Gutsy Gibbon'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:244
+#: ../data/templates/Ubuntu.info.in:445
msgid "Ubuntu 7.04 'Feisty Fawn'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:262
+#: ../data/templates/Ubuntu.info.in:463
msgid "Cdrom with Ubuntu 7.04 'Feisty Fawn'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:296
+#: ../data/templates/Ubuntu.info.in:505
msgid "Ubuntu 6.10 'Edgy Eft'"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:301
+#: ../data/templates/Ubuntu.info.in:510
msgid "Community-maintained"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:307
+#: ../data/templates/Ubuntu.info.in:516
msgid "Restricted software"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:314
+#: ../data/templates/Ubuntu.info.in:523
msgid "Cdrom with Ubuntu 6.10 'Edgy Eft'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:348
+#: ../data/templates/Ubuntu.info.in:565
msgid "Ubuntu 6.06 LTS 'Dapper Drake'"
msgstr ""
#. CompDescriptionLong
-#: ../data/templates/Ubuntu.info.in:351
+#: ../data/templates/Ubuntu.info.in:568
msgid "Canonical-supported Open Source software"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:353
+#: ../data/templates/Ubuntu.info.in:570
msgid "Community-maintained (universe)"
msgstr ""
#. CompDescriptionLong
-#: ../data/templates/Ubuntu.info.in:354
+#: ../data/templates/Ubuntu.info.in:571
msgid "Community-maintained Open Source software"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:356
+#: ../data/templates/Ubuntu.info.in:573
msgid "Non-free drivers"
msgstr ""
#. CompDescriptionLong
-#: ../data/templates/Ubuntu.info.in:357
+#: ../data/templates/Ubuntu.info.in:574
msgid "Proprietary drivers for devices"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:359
+#: ../data/templates/Ubuntu.info.in:576
msgid "Restricted software (Multiverse)"
msgstr ""
#. CompDescriptionLong
-#: ../data/templates/Ubuntu.info.in:360
+#: ../data/templates/Ubuntu.info.in:577
msgid "Software restricted by copyright or legal issues"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:366
+#: ../data/templates/Ubuntu.info.in:583
msgid "Cdrom with Ubuntu 6.06 LTS 'Dapper Drake'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:378
+#: ../data/templates/Ubuntu.info.in:599
msgid "Important security updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:383
+#: ../data/templates/Ubuntu.info.in:604
msgid "Recommended updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:388
+#: ../data/templates/Ubuntu.info.in:609
msgid "Pre-released updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:393
+#: ../data/templates/Ubuntu.info.in:614
msgid "Unsupported updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:400
+#: ../data/templates/Ubuntu.info.in:625
msgid "Ubuntu 5.10 'Breezy Badger'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:414
+#: ../data/templates/Ubuntu.info.in:639
msgid "Cdrom with Ubuntu 5.10 'Breezy Badger'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:426
+#: ../data/templates/Ubuntu.info.in:655
msgid "Ubuntu 5.10 Security Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:431
+#: ../data/templates/Ubuntu.info.in:660
msgid "Ubuntu 5.10 Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:436
+#: ../data/templates/Ubuntu.info.in:665
msgid "Ubuntu 5.10 Backports"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:443
+#: ../data/templates/Ubuntu.info.in:676
msgid "Ubuntu 5.04 'Hoary Hedgehog'"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:457
+#: ../data/templates/Ubuntu.info.in:690
msgid "Cdrom with Ubuntu 5.04 'Hoary Hedgehog'"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:460 ../data/templates/Debian.info.in:123
+#: ../data/templates/Ubuntu.info.in:693 ../data/templates/Debian.info.in:149
msgid "Officially supported"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:469
+#: ../data/templates/Ubuntu.info.in:706
msgid "Ubuntu 5.04 Security Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:474
+#: ../data/templates/Ubuntu.info.in:711
msgid "Ubuntu 5.04 Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:479
+#: ../data/templates/Ubuntu.info.in:716
msgid "Ubuntu 5.04 Backports"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:485
+#: ../data/templates/Ubuntu.info.in:722
msgid "Ubuntu 4.10 'Warty Warthog'"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:491
+#: ../data/templates/Ubuntu.info.in:728
msgid "Community-maintained (Universe)"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:493
+#: ../data/templates/Ubuntu.info.in:730
msgid "Non-free (Multiverse)"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:499
+#: ../data/templates/Ubuntu.info.in:736
msgid "Cdrom with Ubuntu 4.10 'Warty Warthog'"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:502
+#: ../data/templates/Ubuntu.info.in:739
msgid "No longer officially supported"
msgstr ""
#. CompDescription
-#: ../data/templates/Ubuntu.info.in:504
+#: ../data/templates/Ubuntu.info.in:741
msgid "Restricted copyright"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:511
+#: ../data/templates/Ubuntu.info.in:748
msgid "Ubuntu 4.10 Security Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:516
+#: ../data/templates/Ubuntu.info.in:753
msgid "Ubuntu 4.10 Updates"
msgstr ""
#. Description
-#: ../data/templates/Ubuntu.info.in:521
+#: ../data/templates/Ubuntu.info.in:758
msgid "Ubuntu 4.10 Backports"
msgstr ""
@@ -265,56 +296,61 @@ msgstr ""
#. Description
#: ../data/templates/Debian.info.in:8
-msgid "Debian 5.0 'Lenny' "
+msgid "Debian 6.0 'Squeeze' "
msgstr ""
#. Description
#: ../data/templates/Debian.info.in:33
-msgid "Debian 4.0 'Etch'"
+msgid "Debian 5.0 'Lenny' "
msgstr ""
#. Description
#: ../data/templates/Debian.info.in:58
+msgid "Debian 4.0 'Etch'"
+msgstr ""
+
+#. Description
+#: ../data/templates/Debian.info.in:83
msgid "Debian 3.1 'Sarge'"
msgstr ""
#. Description
-#: ../data/templates/Debian.info.in:69
+#: ../data/templates/Debian.info.in:94
msgid "Proposed updates"
msgstr ""
#. Description
-#: ../data/templates/Debian.info.in:76
+#: ../data/templates/Debian.info.in:101
msgid "Security updates"
msgstr ""
#. Description
-#: ../data/templates/Debian.info.in:83
+#: ../data/templates/Debian.info.in:108
msgid "Debian current stable release"
msgstr ""
#. Description
-#: ../data/templates/Debian.info.in:96
+#: ../data/templates/Debian.info.in:121
msgid "Debian testing"
msgstr ""
#. Description
-#: ../data/templates/Debian.info.in:121
+#: ../data/templates/Debian.info.in:147
msgid "Debian 'Sid' (unstable)"
msgstr ""
#. CompDescription
-#: ../data/templates/Debian.info.in:125
+#: ../data/templates/Debian.info.in:151
msgid "DFSG-compatible Software with Non-Free Dependencies"
msgstr ""
#. CompDescription
-#: ../data/templates/Debian.info.in:127
+#: ../data/templates/Debian.info.in:153
msgid "Non-DFSG-compatible Software"
msgstr ""
#. TRANSLATORS: %s is a country
-#: ../aptsources/distro.py:207 ../aptsources/distro.py:422
+#: ../aptsources/distro.py:208 ../aptsources/distro.py:423
#, python-format
msgid "Server for %s"
msgstr ""
@@ -322,48 +358,48 @@ msgstr ""
#. More than one server is used. Since we don't handle this case
#. in the user interface we set "custom servers" to true and
#. append a list of all used servers
-#: ../aptsources/distro.py:225 ../aptsources/distro.py:231
-#: ../aptsources/distro.py:247
+#: ../aptsources/distro.py:226 ../aptsources/distro.py:232
+#: ../aptsources/distro.py:248
msgid "Main server"
msgstr ""
-#: ../aptsources/distro.py:251
+#: ../aptsources/distro.py:252
msgid "Custom servers"
msgstr ""
-#: ../apt/gtk/widgets.py:243
+#: ../apt/progress/gtk2.py:260 ../apt/progress/gtk2.py:316
#, python-format
msgid "Downloading file %(current)li of %(total)li with %(speed)s/s"
msgstr ""
-#: ../apt/gtk/widgets.py:249
+#: ../apt/progress/gtk2.py:266 ../apt/progress/gtk2.py:322
#, python-format
msgid "Downloading file %(current)li of %(total)li"
msgstr ""
#. Setup some child widgets
-#: ../apt/gtk/widgets.py:269
+#: ../apt/progress/gtk2.py:342
msgid "Details"
msgstr ""
-#: ../apt/gtk/widgets.py:351
+#: ../apt/progress/gtk2.py:430
msgid "Starting..."
msgstr ""
-#: ../apt/gtk/widgets.py:357
+#: ../apt/progress/gtk2.py:436
msgid "Complete"
msgstr ""
-#: ../apt/package.py:315
+#: ../apt/package.py:342
#, python-format
msgid "Invalid unicode in description for '%s' (%s). Please report."
msgstr ""
-#: ../apt/package.py:878 ../apt/package.py:982
+#: ../apt/package.py:1007 ../apt/package.py:1112
msgid "The list of changes is not available"
msgstr ""
-#: ../apt/package.py:986
+#: ../apt/package.py:1118
#, python-format
msgid ""
"The list of changes is not available yet.\n"
@@ -372,56 +408,143 @@ msgid ""
"until the changes become available or try again later."
msgstr ""
-#: ../apt/package.py:992
+#: ../apt/package.py:1125
msgid ""
"Failed to download the list of changes. \n"
"Please check your Internet connection."
msgstr ""
-#: ../apt/debfile.py:56
-#, python-format
-msgid "This is not a valid DEB archive, missing '%s' member"
-msgstr ""
-
-#: ../apt/debfile.py:81
+#: ../apt/debfile.py:79
#, python-format
msgid "List of files for '%s' could not be read"
msgstr ""
-#: ../apt/debfile.py:149
+#: ../apt/debfile.py:164
#, python-format
msgid "Dependency is not satisfiable: %s\n"
msgstr ""
-#: ../apt/debfile.py:173
+#: ../apt/debfile.py:185
#, python-format
msgid "Conflicts with the installed package '%s'"
msgstr ""
-#: ../apt/debfile.py:319
+#. 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:323
+#, python-format
+msgid ""
+"Breaks existing package '%(pkgname)s' dependency %(depname)s "
+"(%(deprelation)s %(depversion)s)"
+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:339
+#, python-format
+msgid ""
+"Breaks existing package '%(pkgname)s' conflict: %(targetpkg)s (%(comptype)s "
+"%(targetver)s)"
+msgstr ""
+
+#: ../apt/debfile.py:348
+#, 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:394
+msgid "No Architecture field in the package"
+msgstr ""
+
+#: ../apt/debfile.py:399
#, python-format
msgid "Wrong architecture '%s'"
msgstr ""
#. the deb is older than the installed
-#: ../apt/debfile.py:325
+#: ../apt/debfile.py:406
msgid "A later version is already installed"
msgstr ""
-#: ../apt/debfile.py:345
+#: ../apt/debfile.py:431
msgid "Failed to satisfy all dependencies (broken cache)"
msgstr ""
-#: ../apt/debfile.py:376
+#: ../apt/debfile.py:461
#, python-format
msgid "Cannot install '%s'"
msgstr ""
-#: ../apt/debfile.py:484
+#: ../apt/debfile.py:503 ../apt/debfile.py:551 ../apt/debfile.py:562
+msgid "Python-debian module not available"
+msgstr ""
+
+#: ../apt/debfile.py:535
+msgid ""
+"Automatically decompressed:\n"
+"\n"
+msgstr ""
+
+#: ../apt/debfile.py:541
+msgid "Automatically converted to printable ascii:\n"
+msgstr ""
+
+#: ../apt/debfile.py:638
#, python-format
msgid "Install Build-Dependencies for source package '%s' that builds %s\n"
msgstr ""
-#: ../apt/debfile.py:494
+#: ../apt/debfile.py:648
msgid "An essential package would be removed"
msgstr ""
+
+#: ../apt/progress/text.py:81
+#, python-format
+msgid "%c%s... Done"
+msgstr ""
+
+#: ../apt/progress/text.py:120
+msgid "Hit "
+msgstr ""
+
+#: ../apt/progress/text.py:129
+msgid "Ign "
+msgstr ""
+
+#: ../apt/progress/text.py:131
+msgid "Err "
+msgstr ""
+
+#: ../apt/progress/text.py:142
+msgid "Get:"
+msgstr ""
+
+#: ../apt/progress/text.py:202
+msgid " [Working]"
+msgstr ""
+
+#: ../apt/progress/text.py:213
+#, python-format
+msgid ""
+"Media change: please insert the disc labeled\n"
+" '%s'\n"
+"in the drive '%s' and press enter\n"
+msgstr ""
+
+#. Trick for getting a translation from apt
+#: ../apt/progress/text.py:222
+#, python-format
+msgid "Fetched %sB in %s (%sB/s)\n"
+msgstr ""
+
+#: ../apt/progress/text.py:238
+msgid "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'"
+msgstr ""
+
+#: ../apt/progress/text.py:254
+msgid "Please insert a Disc in the drive and press enter"
+msgstr ""
+
+#: ../apt/cache.py:135
+msgid "Building data structures"
+msgstr ""
diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc
index a1e9ada0..cacbf77a 100644
--- a/python/apt_pkgmodule.cc
+++ b/python/apt_pkgmodule.cc
@@ -905,6 +905,8 @@ extern "C" void initapt_pkg()
Py_BuildValue("i", pkgAcquire::Item::StatFetching));
PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_DONE",
Py_BuildValue("i", pkgAcquire::Item::StatDone));
+ PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_TRANSIENT_NETWORK_ERROR",
+ Py_BuildValue("i", pkgAcquire::Item::StatTransientNetworkError));
PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_ERROR",
Py_BuildValue("i", pkgAcquire::Item::StatError));
PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_AUTH_ERROR",
diff --git a/python/progress.cc b/python/progress.cc
index 9002b3eb..437309cf 100644
--- a/python/progress.cc
+++ b/python/progress.cc
@@ -300,7 +300,10 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
Py_INCREF(pyAcquire);
if (RunSimpleCallback("pulse", TUPLEIZE(pyAcquire) , &result1)) {
- if (result1 != NULL && PyArg_Parse(result1, "b", &res1) && res1 == false) {
+ if (result1 != NULL &&
+ result1 != Py_None &&
+ PyArg_Parse(result1, "b", &res1) &&
+ res1 == false) {
// the user returned a explicit false here, stop
PyCbObj_BEGIN_ALLOW_THREADS
return false;
diff --git a/python/tag.cc b/python/tag.cc
index 9fe12a1a..97039bc4 100644
--- a/python/tag.cc
+++ b/python/tag.cc
@@ -393,7 +393,12 @@ static PyObject *TagFileNew(PyTypeObject *type,PyObject *Args,PyObject *kwds)
return 0;
TagFileData *New = (TagFileData*)type->tp_alloc(type, 0);
+#ifdef APT_HAS_GZIP
+ new (&New->Fd) FileFd();
+ New->Fd.OpenDescriptor(fileno, FileFd::ReadOnlyGzip, false);
+#else
new (&New->Fd) FileFd(fileno,false);
+#endif
New->Owner = File;
Py_INCREF(New->Owner);
new (&New->Object) pkgTagFile(&New->Fd);
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/data/test_debs/gdebi-test1.deb b/tests/data/test_debs/gdebi-test1.deb
new file mode 100644
index 00000000..ea9991ac
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test1.deb
Binary files differ
diff --git a/tests/data/test_debs/gdebi-test10.deb b/tests/data/test_debs/gdebi-test10.deb
new file mode 100644
index 00000000..ca43ace6
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test10.deb
Binary files differ
diff --git a/tests/data/test_debs/gdebi-test2.deb b/tests/data/test_debs/gdebi-test2.deb
new file mode 100644
index 00000000..307ac689
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test2.deb
Binary files differ
diff --git a/tests/data/test_debs/gdebi-test3.deb b/tests/data/test_debs/gdebi-test3.deb
new file mode 100644
index 00000000..436b9258
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test3.deb
Binary files differ
diff --git a/tests/data/test_debs/gdebi-test4.deb b/tests/data/test_debs/gdebi-test4.deb
new file mode 100644
index 00000000..9eb92d1b
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test4.deb
Binary files differ
diff --git a/tests/data/test_debs/gdebi-test5.deb b/tests/data/test_debs/gdebi-test5.deb
new file mode 100644
index 00000000..0c98c03f
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test5.deb
Binary files differ
diff --git a/tests/data/test_debs/gdebi-test6.deb b/tests/data/test_debs/gdebi-test6.deb
new file mode 100644
index 00000000..8ceacadc
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test6.deb
Binary files differ
diff --git a/tests/data/test_debs/gdebi-test7.deb b/tests/data/test_debs/gdebi-test7.deb
new file mode 100644
index 00000000..c0414990
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test7.deb
Binary files differ
diff --git a/tests/data/test_debs/gdebi-test8.deb b/tests/data/test_debs/gdebi-test8.deb
new file mode 100644
index 00000000..439f8ca7
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test8.deb
Binary files differ
diff --git a/tests/data/test_debs/gdebi-test9.deb b/tests/data/test_debs/gdebi-test9.deb
new file mode 100644
index 00000000..9901d906
--- /dev/null
+++ b/tests/data/test_debs/gdebi-test9.deb
Binary files differ
diff --git a/tests/data/test_debs/var/lib/dpkg/status b/tests/data/test_debs/var/lib/dpkg/status
new file mode 100644
index 00000000..f0c48151
--- /dev/null
+++ b/tests/data/test_debs/var/lib/dpkg/status
@@ -0,0 +1,53 @@
+Package: apt
+Status: install ok installed
+Priority: important
+Section: admin
+Installed-Size: 5456
+Maintainer: APT Development Team <deity@lists.debian.org>
+Architecture: i386
+Version: 0.7.25.3
+Replaces: libapt-pkg-dev (<< 0.3.7), libapt-pkg-doc (<< 0.3.7)
+Provides: libapt-pkg-libc6.10-6-4.8
+Description: Advanced front-end for dpkg
+ This is Debian's next generation front-end for the dpkg package manager.
+ It provides the apt-get utility and APT dselect method that provides a
+ simpler, safer way to install and upgrade packages.
+ .
+ APT features complete installation ordering, multiple source capability
+ and several other unique features, see the Users Guide in apt-doc.
+
+Package: postfix
+Status: install ok installed
+Priority: extra
+Section: mail
+Installed-Size: 3488
+Maintainer: LaMont Jones <lamont@debian.org>
+Architecture: i386
+Version: 2.7.0-1
+Replaces: mail-transport-agent, postfix-tls
+Provides: default-mta, mail-transport-agent, postfix-tls
+Recommends: python
+Conflicts: libnss-db (<< 2.2-3), mail-transport-agent, postfix-tls, smail
+Description: High-performance mail transport agent
+ Postfix is Wietse Venema's mail transport agent that started life as an
+ alternative to the widely-used Sendmail program. Postfix attempts to
+ be fast, easy to administer, and secure, while at the same time being
+ sendmail compatible enough to not upset existing users. Thus, the outside
+ has a sendmail-ish flavor, but the inside is completely different.
+
+Package: debconf
+Status: install ok installed
+Priority: important
+Section: admin
+Installed-Size: 924
+Maintainer: Debconf Developers <debconf-devel@lists.alioth.debian.org>
+Architecture: all
+Version: 1.5.28
+Replaces: debconf-tiny
+Provides: debconf-2.0
+Recommends: apt-utils (>= 0.5.1)
+Conflicts: apt (<< 0.3.12.1), cdebconf (<< 0.96), debconf-tiny, debconf-utils (<< 1.3.22), dialog (<< 0.9b-20020814-1), menu (<= 2.1.3-1), whiptail (<< 0.51.4-11), whiptail-utf8 (<= 0.50.17-13)
+Description: Debian configuration management system
+ Debconf is a configuration management system for debian packages. Packages
+ use Debconf to ask questions when they are installed.
+Python-Version: 2.6, 3.1
diff --git a/tests/test_all.py b/tests/test_all.py
index d561a9ae..d6370747 100644
--- a/tests/test_all.py
+++ b/tests/test_all.py
@@ -9,21 +9,29 @@ import os
import unittest
import sys
-if __name__ == '__main__':
- sys.stderr.write("[tests] Running on %s\n" % sys.version.replace("\n", ""))
- os.chdir(os.path.dirname(__file__))
+def get_library_dir():
# Find the path to the built apt_pkg and apt_inst extensions
- if os.path.exists("../build"):
- from distutils.util import get_platform
- from distutils.sysconfig import get_python_version
- # Set the path to the build directory.
- plat_specifier = ".%s-%s" % (get_platform(), get_python_version())
- if sys.version_info[0] >= 3 or sys.version_info[1] >= 6:
- library_dir = "../build/lib%s%s" % (plat_specifier,
+ if not os.path.exists("../build"):
+ return None
+ from distutils.util import get_platform
+ from distutils.sysconfig import get_python_version
+ # Set the path to the build directory.
+ plat_specifier = ".%s-%s" % (get_platform(), get_python_version())
+ if sys.version_info[0] >= 3 or sys.version_info[1] >= 6:
+ library_dir = "../build/lib%s%s" % (plat_specifier,
(sys.pydebug and "-pydebug" or ""))
- else:
- library_dir = "../build/lib%s%s" % ((sys.pydebug and "_d" or ""),
+ else:
+ library_dir = "../build/lib%s%s" % ((sys.pydebug and "_d" or ""),
plat_specifier)
+ return os.path.abspath(library_dir)
+
+if __name__ == '__main__':
+ sys.stderr.write("[tests] Running on %s\n" % sys.version.replace("\n", ""))
+ dirname = os.path.dirname(__file__)
+ if dirname:
+ os.chdir(dirname)
+ library_dir = get_library_dir()
+ if library_dir:
sys.path.insert(0, os.path.abspath(library_dir))
for path in os.listdir('.'):
diff --git a/tests/test_apt_cache.py b/tests/test_apt_cache.py
index fdcf482d..a43e92d2 100644
--- a/tests/test_apt_cache.py
+++ b/tests/test_apt_cache.py
@@ -6,9 +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
class TestAptCache(unittest.TestCase):
@@ -30,5 +36,52 @@ class TestAptCache(unittest.TestCase):
self.assertTrue(isinstance(dep.relation, str))
self.assertTrue(dep.pre_depend in (True, False))
+ # accessing record should take a reasonable time; in
+ # particular, when using compressed indexes, it should not use
+ # tons of seek operations
+ r = pkg.candidate.record
+ self.assertEqual(r['Package'], pkg.name)
+ self.assert_('Version' in r)
+ 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")
+ # create tmp env
+ tmpdir = tempfile.mkdtemp()
+ dpkg_dir = os.path.join(tmpdir,"var","lib","dpkg")
+ os.makedirs(os.path.join(dpkg_dir,"updates"))
+ open(os.path.join(dpkg_dir,"status"), "w")
+ apt_pkg.config.set("Dir::State::status",
+ os.path.join(dpkg_dir,"status"))
+ cache = apt.Cache()
+ # test empty
+ self.assertFalse(cache.dpkg_journal_dirty)
+ # that is ok, only [0-9] are dpkg jounral entries
+ open(os.path.join(dpkg_dir,"updates","xxx"), "w")
+ self.assertFalse(cache.dpkg_journal_dirty)
+ # that is a dirty journal
+ open(os.path.join(dpkg_dir,"updates","000"), "w")
+ self.assertTrue(cache.dpkg_journal_dirty)
+ # reset config value
+ apt_pkg.config.set("Dir::State::status", old_status)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/tests/test_aptsources.py b/tests/test_aptsources.py
index 767f5244..3ef20f64 100644
--- a/tests/test_aptsources.py
+++ b/tests/test_aptsources.py
@@ -98,7 +98,7 @@ class TestAptSources(unittest.TestCase):
apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/"
"sources.list.testDistribution")
sources = aptsources.sourceslist.SourcesList(True, self.templates)
- distro = aptsources.distro.get_distro()
+ distro = aptsources.distro.get_distro(id="Ubuntu")
distro.get_sources(sources)
# test if all suits of the current distro were detected correctly
dist_templates = set()
@@ -111,7 +111,7 @@ class TestAptSources(unittest.TestCase):
apt_pkg.config.set("Dir::Etc::sourcelist", "data/aptsources/"
"sources.list.testDistribution")
sources = aptsources.sourceslist.SourcesList(True, self.templates)
- distro = aptsources.distro.get_distro()
+ distro = aptsources.distro.get_distro(id="Ubuntu")
distro.get_sources(sources)
# test if all suits of the current distro were detected correctly
dist_templates = set()
diff --git a/tests/test_debfile.py b/tests/test_debfile.py
new file mode 100644
index 00000000..bb9fd62c
--- /dev/null
+++ b/tests/test_debfile.py
@@ -0,0 +1,66 @@
+#!/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
+
+from test_all import get_library_dir
+import sys
+sys.path.insert(0, get_library_dir())
+import apt_pkg
+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 setUp(self):
+ apt_pkg.init_config()
+ apt_pkg.config.set("APT::Architecture","i386")
+ apt_pkg.config.set("Dir::State::status",
+ "./data/test_debs/var/lib/dpkg/status")
+ apt_pkg.init_system()
+ self.cache = apt.Cache()
+
+ def testDebFile(self):
+ deb = apt.debfile.DebPackage(cache=self.cache)
+ for (filename, expected_res) in self.TEST_DEBS:
+ logging.debug("testing %s, expecting %s" % (filename, expected_res))
+ deb.open(os.path.join("data", "test_debs", filename))
+ res = deb.check()
+ self.assertEqual(res, expected_res,
+ "Unexpected result for package '%s' (got %s wanted %s)\n%s" % (
+ filename, res, expected_res, deb._failure_string))
+
+if __name__ == "__main__":
+ #logging.basicConfig(level=logging.DEBUG)
+ unittest.main()
diff --git a/tests/test_progress.py b/tests/test_progress.py
new file mode 100644
index 00000000..ffab5bc0
--- /dev/null
+++ b/tests/test_progress.py
@@ -0,0 +1,47 @@
+#!/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
+ # there should be a return value here, either (True,False)
+ # but often this is forgoten (and causes odd error messages)
+ # so the lib supports it. we test the lack of support value here
+
+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()
diff --git a/utils/pyversions b/utils/pyversions
new file mode 100755
index 00000000..3accad3f
--- /dev/null
+++ b/utils/pyversions
@@ -0,0 +1,2 @@
+#!/bin/sh
+(/usr/bin/pyversions "$@"; /usr/bin/py3versions "$@"; ) | tr '\n' ' '