diff options
| -rw-r--r-- | apt/auth.py | 3 | ||||
| -rw-r--r-- | apt/cache.py | 23 | ||||
| -rw-r--r-- | apt/package.py | 2 | ||||
| -rw-r--r-- | aptsources/distinfo.py | 3 | ||||
| -rw-r--r-- | aptsources/distro.py | 8 | ||||
| -rw-r--r-- | aptsources/sourceslist.py | 2 | ||||
| -rw-r--r-- | data/templates/Ubuntu.info.in | 129 | ||||
| -rw-r--r-- | debian/changelog | 72 | ||||
| -rw-r--r-- | debian/control | 1 | ||||
| -rw-r--r-- | debian/tests/control | 2 | ||||
| -rw-r--r-- | debian/tests/run-tests | 8 | ||||
| -rw-r--r-- | python/cache.cc | 8 | ||||
| -rw-r--r-- | python/generic.h | 4 | ||||
| -rw-r--r-- | tests/test_all.py | 13 | ||||
| -rw-r--r-- | tests/test_apt_cache.py | 69 | ||||
| -rw-r--r-- | tests/test_aptsources.py | 3 | ||||
| -rw-r--r-- | tests/test_auth.py | 67 | ||||
| -rw-r--r-- | tests/test_debfile.py | 4 | ||||
| -rw-r--r-- | tests/test_debfile_multiarch.py | 10 | ||||
| -rw-r--r-- | tests/test_lp659438.py | 6 | ||||
| -rw-r--r-- | tests/test_progress.py | 2 | ||||
| -rw-r--r-- | tests/test_tagfile.py | 4 |
22 files changed, 402 insertions, 41 deletions
diff --git a/apt/auth.py b/apt/auth.py index eff13b1a..c1b8da2a 100644 --- a/apt/auth.py +++ b/apt/auth.py @@ -78,7 +78,8 @@ def _call_apt_key_script(*args, **kwargs): stderr=subprocess.PIPE) content = kwargs.get("stdin", None) - if isinstance(content, unicode): + # py2 needs this encoded, py3.3 will crash if it is + if isinstance(content, unicode) and sys.version_info[:2] < (3, 3): content = content.encode("utf-8") output, stderr = proc.communicate(content) diff --git a/apt/cache.py b/apt/cache.py index 86a788bb..9842cb2a 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -42,6 +42,9 @@ class FetchFailedException(IOError): class LockFailedException(IOError): """Exception that is thrown when locking fails.""" +class CacheClosedException(Exception): + """Exception that is thrown when the cache is used after close().""" + class Cache(object): """Dictionary-like package cache. @@ -139,6 +142,8 @@ class Cache(object): """ if progress is None: progress = apt.progress.base.OpProgress() + # close old cache on (re)open + self.close() self.op_progress = progress self._run_callbacks("cache_pre_open") @@ -172,6 +177,20 @@ class Cache(object): progress.done() self._run_callbacks("cache_post_open") + def close(self): + """ Close the package cache """ + # explicitely free the FDs that _records has open + del self._records + self._records = None + + def __enter__(self): + """ Enter the with statement """ + return self + + def __exit__(self, exc_type, exc_value, traceback): + """ Exit the with statement """ + self.close() + def __getitem__(self, key): """ look like a dictionary (get key) """ try: @@ -238,6 +257,8 @@ class Cache(object): @property def required_download(self): """Get the size of the packages that are required to download.""" + if self._records is None: + raise CacheClosedException("Cache object used after close() called") pm = apt_pkg.PackageManager(self._depcache) fetcher = apt_pkg.Acquire() pm.get_archives(fetcher, self._list, self._records) @@ -288,6 +309,8 @@ class Cache(object): def _fetch_archives(self, fetcher, pm): """ fetch the needed archives """ + if self._records is None: + raise CacheClosedException("Cache object used after close() called") # get lock lockfile = apt_pkg.config.find_dir("Dir::Cache::Archives") + "lock" diff --git a/apt/package.py b/apt/package.py index 51da95f8..dbaab320 100644 --- a/apt/package.py +++ b/apt/package.py @@ -137,6 +137,7 @@ class Origin(object): component - The component (eg. main) label - The Label, as set in the Release file origin - The Origin, as set in the Release file + codename - The Codename, as set in the Release file site - The hostname of the site. trusted - Boolean value whether this is trustworthy. """ @@ -146,6 +147,7 @@ class Origin(object): self.component = packagefile.component self.label = packagefile.label self.origin = packagefile.origin + self.codename = packagefile.codename self.site = packagefile.site self.not_automatic = packagefile.not_automatic # check the trust diff --git a/aptsources/distinfo.py b/aptsources/distinfo.py index e0ee915d..d80721e5 100644 --- a/aptsources/distinfo.py +++ b/aptsources/distinfo.py @@ -172,7 +172,8 @@ class DistInfo(object): stdout=PIPE).communicate()[0].strip() except OSError as exc: if exc.errno != errno.ENOENT: - logging.warn('lsb_release failed, using defaults:' % exc) + logging.warning( + 'lsb_release failed, using defaults:' % exc) dist = "Debian" self.dist = dist diff --git a/aptsources/distro.py b/aptsources/distro.py index 15b93823..e9facbfb 100644 --- a/aptsources/distro.py +++ b/aptsources/distro.py @@ -164,7 +164,11 @@ class Distribution(object): fname = "/usr/share/xml/iso-codes/iso_3166.xml" if os.path.exists(fname): et = ElementTree(file=fname) - it = et.getiterator('iso_3166_entry') + # python2.6 compat, the next two lines can get removed + # once we do not use py2.6 anymore + if getattr(et, "iter", None) is None: + et.iter = et.getiterator + it = et.iter('iso_3166_entry') for elm in it: try: descr = elm.attrib["common_name"] @@ -466,7 +470,7 @@ def _lsb_release(): result.update(l.split(":\t") for l in out.split("\n") if ':\t' in l) except OSError as exc: if exc.errno != errno.ENOENT: - logging.warn('lsb_release failed, using defaults:' % exc) + logging.warning('lsb_release failed, using defaults:' % exc) return result diff --git a/aptsources/sourceslist.py b/aptsources/sourceslist.py index 40902d84..f5a86ecb 100644 --- a/aptsources/sourceslist.py +++ b/aptsources/sourceslist.py @@ -375,7 +375,7 @@ class SourcesList(object): source = SourceEntry(line, file) self.list.append(source) except: - logging.warn("could not open file '%s'\n" % file) + logging.warning("could not open file '%s'\n" % file) def save(self): """ save the current sources """ diff --git a/data/templates/Ubuntu.info.in b/data/templates/Ubuntu.info.in index 2aba269e..567456b3 100644 --- a/data/templates/Ubuntu.info.in +++ b/data/templates/Ubuntu.info.in @@ -1,5 +1,124 @@ _ChangelogURI: http://changelogs.ubuntu.com/changelogs/pool/%s/%s/%s/%s_%s/changelog +Suite: raring +RepositoryType: deb +BaseURI: http://ports.ubuntu.com/ubuntu-ports/ +MatchURI: ports.ubuntu.com/ubuntu-ports +BaseURI-amd64: http://archive.ubuntu.com/ubuntu +MatchURI-amd64: archive.ubuntu.com/ubuntu +BaseURI-i386: http://archive.ubuntu.com/ubuntu +MatchURI-i386: archive.ubuntu.com/ubuntu +MirrorsFile-amd64: Ubuntu.mirrors +MirrorsFile-i386: Ubuntu.mirrors +_Description: Ubuntu 13.04 'Raring Ringtail' +Component: main +_CompDescription: Officially supported +_CompDescriptionLong: Canonical-supported free and open-source software +Component: universe +_CompDescription: Community-maintained +_CompDescriptionLong: Community-maintained free and open-source software +Component: restricted +_CompDescription: Non-free drivers +_CompDescriptionLong: Proprietary drivers for devices +Component: multiverse +ParentComponent: universe +_CompDescription: Restricted software +_CompDescriptionLong: Software restricted by copyright or legal issues + +Suite: raring +ParentSuite: raring +RepositoryType: deb-src +BaseURI: http://archive.ubuntu.com/ubuntu/ +MatchURI: archive.ubuntu.com/ubuntu|ports.ubuntu.com/ubuntu-ports +_Description: Ubuntu 13.04 'Raring Ringtail' + +Suite: raring +RepositoryType: deb +MatchName: .* +BaseURI: cdrom:\[Ubuntu.*13.04 +MatchURI: cdrom:\[Ubuntu.*13.04 +_Description: Cdrom with Ubuntu 13.04 'Raring Ringtail' +Available: False +Component: main +_CompDescription: Officially supported +Component: restricted +_CompDescription: Restricted copyright + +Suite: raring +Official: false +RepositoryType: deb +BaseURI: http://archive.canonical.com +MatchURI: archive.canonical.com +_Description: Canonical Partners +Component: partner +_CompDescription: Software packaged by Canonical for their partners +_CompDescriptionLong: This software is not part of Ubuntu. + +Suite: raring +Official: false +RepositoryType: deb +BaseURI: http://extras.ubuntu.com +MatchURI: extras.ubuntu.com +_Description: Independent +Component: main +_CompDescription: Provided by third-party software developers +_CompDescriptionLong: Software offered by third party developers. + +Suite: raring-security +ParentSuite: raring +RepositoryType: deb +BaseURI: http://ports.ubuntu.com/ubuntu-ports/ +MatchURI: ports.ubuntu.com/ubuntu-ports +BaseURI-amd64: http://security.ubuntu.com/ubuntu/ +MatchURI-amd64: archive.ubuntu.com/ubuntu|security.ubuntu.com +BaseURI-i386: http://security.ubuntu.com/ubuntu/ +MatchURI-i386: archive.ubuntu.com/ubuntu|security.ubuntu.com +_Description: Important security updates + +Suite: raring-security +ParentSuite: raring +RepositoryType: deb-src +BaseURI: http://archive.ubuntu.com/ubuntu/ +MatchURI: archive.ubuntu.com/ubuntu|ports.ubuntu.com/ubuntu-ports|security.ubuntu.com +_Description: Important security updates + +Suite: raring-updates +ParentSuite: raring +RepositoryType: deb +_Description: Recommended updates + +Suite: raring-updates +ParentSuite: raring +RepositoryType: deb-src +BaseURI: http://archive.ubuntu.com/ubuntu/ +MatchURI: archive.ubuntu.com/ubuntu|ports.ubuntu.com/ubuntu-ports +_Description: Recommended updates + +Suite: raring-proposed +ParentSuite: raring +RepositoryType: deb +_Description: Pre-released updates + +Suite: raring-proposed +ParentSuite: raring +RepositoryType: deb-src +BaseURI: http://archive.ubuntu.com/ubuntu/ +MatchURI: archive.ubuntu.com/ubuntu|ports.ubuntu.com/ubuntu-ports +_Description: Pre-released updates + +Suite: raring-backports +ParentSuite: raring +RepositoryType: deb +_Description: Unsupported updates + +Suite: raring-backports +ParentSuite: raring +RepositoryType: deb-src +BaseURI: http://archive.ubuntu.com/ubuntu/ +MatchURI: archive.ubuntu.com/ubuntu|ports.ubuntu.com/ubuntu-ports +_Description: Unsupported updates + + Suite: quantal RepositoryType: deb BaseURI: http://ports.ubuntu.com/ubuntu-ports/ @@ -10,7 +129,7 @@ BaseURI-i386: http://archive.ubuntu.com/ubuntu MatchURI-i386: archive.ubuntu.com/ubuntu MirrorsFile-amd64: Ubuntu.mirrors MirrorsFile-i386: Ubuntu.mirrors -_Description: Ubuntu 12.04 'Precise Pangolin' +_Description: Ubuntu 12.10 'Quantal Quetzal' Component: main _CompDescription: Officially supported _CompDescriptionLong: Canonical-supported free and open-source software @@ -30,14 +149,14 @@ ParentSuite: quantal RepositoryType: deb-src BaseURI: http://archive.ubuntu.com/ubuntu/ MatchURI: archive.ubuntu.com/ubuntu|ports.ubuntu.com/ubuntu-ports -_Description: Ubuntu 12.04 'Precise Pangolin' +_Description: Ubuntu 12.10 'Quantal Quetzal' Suite: quantal RepositoryType: deb MatchName: .* -BaseURI: cdrom:\[Ubuntu.*12.04 -MatchURI: cdrom:\[Ubuntu.*12.04 -_Description: Cdrom with Ubuntu 12.04 'Precise Pangolin' +BaseURI: cdrom:\[Ubuntu.*12.10 +MatchURI: cdrom:\[Ubuntu.*12.10 +_Description: Cdrom with Ubuntu 12.10 'Quantal Quetzal' Available: False Component: main _CompDescription: Officially supported diff --git a/debian/changelog b/debian/changelog index 2bea7d52..53197196 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,73 @@ +python-apt (0.8.9) unstable; urgency=low + + * upload previous experimental upload to sid + + -- Michael Vogt <mvo@debian.org> Wed, 08 May 2013 18:23:36 +0200 + +python-apt (0.8.9~exp2) experimental; urgency=low + + * apt/package.py: + - export codename in apt.package.Origin as well + (closes: #703401) + + -- Michael Vogt <mvo@debian.org> Tue, 19 Mar 2013 16:57:40 +0100 + +python-apt (0.8.9~exp1) experimental; urgency=low + + [ Michael Vogt ] + * python/tag.cc: + - make TagSecString_FromStringAndSize, TagSecString_FromString + static, thanks to jcristau + * python/cache.cc: + - add "Codename" to PackageFile object + * add dep8 style autopkgtest support + * build fixes for python3.3 + * data/templates/Ubuntu.info.in: + - add raring + * tests/test_all.py, aptsources/distro.py: + - python2.6 compat fixes + + [ Jason Conti ] + * lp:~jconti/python-apt/closeable-cache: + - add apt.Cache.close() method + + [ Martin Pitt ] + * tests/*.py: Do not prepend None to sys.path, Python 3.3 redeems that with + an unintelligible crash. + * tests/test_auth.py: In test_add_key_from_server_mitm(), show the exception + if it does not match the expectation, so that this becomes possible to + debug. + * aptsources/distro.py: Replace the deprecated getiterator() ElementTree + method with iter(), to avoid raising a PendingDeprecationWarning. + * tests/test_auth.py: Temporarily disable $http_proxy for the tests, as + gnupg does not get along with proxies (LP #789049) + + [ Colin Watson ] + * tests/test_apt_cache.py, tests/test_lp659438.py, tests/test_progress.py: + - Clear out APT::Update::Post-Invoke and + APT::Update::Post-Invoke-Success in tests that call cache.update to + avoid pollution from the host system. + * tests/test_auth.py: + - Discard stderr from gpg. + - Try successive keyserver ports if 19191 is already in use. + * aptsources/distinfo.py, aptsources/distro.py, aptsources/sourceslist.py, + tests/test_apt_cache.py, tests/test_debfile_multiarch.py: + - Use logging.warning rather than the deprecated logging.warn. + * tests/test_debfile_multiarch.py: + - Don't log warnings when skipping tests; the resulting stderr output + causes autopkgtest to fail. + * tests/test_all.py: + - Write general test status output to stdout, not stderr. + * tests/test_aptsources.py: + - Clean up file object in test_enable_component. + * tests/test_lp659438.py: + - Add an Architecture: line to the test Packages file so that apt + doesn't get upset with it. + * data/templates/Ubuntu.info.in: + - Fix descriptions of quantal and raring. + + -- Michael Vogt <mvo@debian.org> Wed, 13 Mar 2013 18:36:37 +0100 + python-apt (0.8.8.3) UNRELEASED; urgency=low * aptsources/distro.py: @@ -33,7 +103,7 @@ python-apt (0.8.8) unstable; urgency=low [ Program translation updates ] * po/pl.po: Polish (Michał Kułach) (closes: #684308) * po/da.po: Danish (Joe Hansen) (closes: #689827) - + [ Michael Vogt ] * merged lp:~sampo555/python-apt/fix_1042916 reuse existing but disabled sources.list entries instead of duplicating them. diff --git a/debian/control b/debian/control index 1619aacb..dd951ed2 100644 --- a/debian/control +++ b/debian/control @@ -21,6 +21,7 @@ Build-Depends: apt (>= 0.9.6), python-unittest2 Vcs-Bzr: http://bzr.debian.org/apt/python-apt/debian-sid Vcs-Browser: http://bzr.debian.org/loggerhead/apt/python-apt/debian-sid/changes +XS-Testsuite: autopkgtest Package: python-apt Architecture: any diff --git a/debian/tests/control b/debian/tests/control new file mode 100644 index 00000000..2ca0a401 --- /dev/null +++ b/debian/tests/control @@ -0,0 +1,2 @@ +Tests: run-tests +Depends: @, apt-utils, python-debian, fakeroot, intltool diff --git a/debian/tests/run-tests b/debian/tests/run-tests new file mode 100644 index 00000000..bb980c6b --- /dev/null +++ b/debian/tests/run-tests @@ -0,0 +1,8 @@ +#!/bin/sh + +set -e + +# from debian/rules +for python in $(utils/pyversions -r); do + $python tests/test_all.py -q +done diff --git a/python/cache.cc b/python/cache.cc index 10561ca0..e527faba 100644 --- a/python/cache.cc +++ b/python/cache.cc @@ -1247,6 +1247,12 @@ static PyObject *PackageFile_GetArchitecture(PyObject *Self,void*) return Safe_FromString(File.Architecture()); } +static PyObject *PackageFile_GetCodename(PyObject *Self,void*) +{ + pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); + return Safe_FromString(File.Codename()); +} + static PyObject *PackageFile_GetSite(PyObject *Self,void*) { pkgCache::PkgFileIterator &File = GetCpp<pkgCache::PkgFileIterator>(Self); @@ -1305,6 +1311,8 @@ static PyGetSetDef PackageFileGetSet[] = { "The archive of the package file (i.e. 'Suite' in the Release file)."}, {"component",PackageFile_GetComponent,0, "The component of this package file (e.g. 'main')."}, + {"codename",PackageFile_GetCodename,0, + "The codename of this package file (e.g. squeeze-updates)."}, {"filename",PackageFile_GetFileName,0, "The path to the file."}, {"id",PackageFile_GetID,0, diff --git a/python/generic.h b/python/generic.h index f9680ca5..914456e2 100644 --- a/python/generic.h +++ b/python/generic.h @@ -80,10 +80,14 @@ typedef int Py_ssize_t; static inline const char *PyUnicode_AsString(PyObject *op) { // Convert to bytes object, using the default encoding. +#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 3 + return PyUnicode_AsUTF8(op); +#else // Use Python-internal API, there is no other way to do this // without a memory leak. PyObject *bytes = _PyUnicode_AsDefaultEncodedString(op, 0); return bytes ? PyBytes_AS_STRING(bytes) : 0; +#endif } // Convert any type of string based object to a const char. diff --git a/tests/test_all.py b/tests/test_all.py index 80526d76..25774617 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -40,17 +40,22 @@ def get_library_dir(): plat_specifier) return os.path.abspath(library_dir) +class MyTestRunner(unittest.runner.TextTestRunner): + def __init__(self, *args, **kwargs): + kwargs["stream"] = sys.stdout + super(MyTestRunner, self).__init__(*args, **kwargs) + if __name__ == '__main__': if not os.access("/etc/apt/sources.list", os.R_OK): - sys.stderr.write("[tests] Skipping because sources.list is not readable\n") + sys.stdout.write("[tests] Skipping because sources.list is not readable\n") sys.exit(0) - sys.stderr.write("[tests] Running on %s\n" % sys.version.replace("\n", "")) + sys.stdout.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() - sys.stderr.write("Using library_dir: '%s'" % library_dir) + sys.stdout.write("Using library_dir: '%s'" % library_dir) if library_dir: sys.path.insert(0, os.path.abspath(library_dir)) @@ -58,4 +63,4 @@ if __name__ == '__main__': if path.endswith('.py') and os.path.isfile(path): exec('from %s import *' % path[:-3]) - unittest.main() + unittest.main(testRunner=MyTestRunner) diff --git a/tests/test_apt_cache.py b/tests/test_apt_cache.py index 448aed75..21dfeb98 100644 --- a/tests/test_apt_cache.py +++ b/tests/test_apt_cache.py @@ -7,29 +7,49 @@ # 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 glob +import logging import os +import shutil +import sys import tempfile import unittest +if sys.version_info[0] == 2 and sys.version_info[1] == 6: + from unittest2 import TestCase +else: + from unittest import TestCase + + from test_all import get_library_dir -import sys -sys.path.insert(0, get_library_dir()) +libdir = get_library_dir() +if libdir: + sys.path.insert(0, libdir) import apt import apt_pkg -import shutil -import glob -import logging + def if_sources_list_is_readable(f): def wrapper(*args, **kwargs): if os.access("/etc/apt/sources.list", os.R_OK): f(*args, **kwargs) else: - logging.warn("skipping '%s' because sources.list is not readable" % f) + logging.warning("skipping '%s' because sources.list is not readable" % f) return wrapper -class TestAptCache(unittest.TestCase): + +def get_open_file_descriptors(): + try: + fds = os.listdir("/proc/self/fd") + except OSError: + logging.warning("failed to list /proc/self/fd") + return set([]) + return set(map(int, fds)) + + +class TestAptCache(TestCase): """ test the apt cache """ def setUp(self): @@ -39,6 +59,8 @@ class TestAptCache(unittest.TestCase): self._cnf = {} for item in apt_pkg.config.keys(): self._cnf[item] = apt_pkg.config.find(item) + apt_pkg.config.clear("APT::Update::Post-Invoke") + apt_pkg.config.clear("APT::Update::Post-Invoke-Success") def tearDown(self): for item in self._cnf: @@ -68,14 +90,41 @@ class TestAptCache(unittest.TestCase): self.assertEqual(r['Package'], pkg.shortname) self.assertTrue('Version' in r) self.assertTrue(len(r['Description']) > 0) - self.assertTrue(str(r).startswith('Package: %s\n' % pkg.shortname)) + self.assertTrue( + str(r).startswith('Package: %s\n' % pkg.shortname)) + + @if_sources_list_is_readable + def test_cache_close_leak_fd(self): + fds_before_open = get_open_file_descriptors() + cache = apt.Cache() + opened_fd = get_open_file_descriptors().difference(fds_before_open) + cache.close() + fds_after_close = get_open_file_descriptors() + unclosed_fd = opened_fd.intersection(fds_after_close) + self.assertEqual(fds_before_open, fds_after_close) + self.assertEqual(unclosed_fd, set()) + + def test_cache_open_twice_leaks_fds(self): + cache = apt.Cache() + fds_before_open = get_open_file_descriptors() + cache.open() + fds_after_open_twice = get_open_file_descriptors() + self.assertEqual(fds_before_open, fds_after_open_twice) + + @if_sources_list_is_readable + def test_cache_close_download_fails(self): + cache = apt.Cache() + self.assertEqual(cache.required_download, 0) + cache.close() + with self.assertRaises(apt.cache.CacheClosedException): + cache.required_download def test_get_provided_packages(self): apt.apt_pkg.config.set("Apt::architecture", "i386") cache = apt.Cache(rootdir="./data/test-provides/") cache.open() if len(cache) == 0: - logging.warn("skipping test_get_provided_packages, cache empty?!?") + logging.warning("skipping test_get_provided_packages, cache empty?!?") return # a true virtual pkg l = cache.get_providing_packages("mail-transport-agent") @@ -88,7 +137,7 @@ class TestAptCache(unittest.TestCase): # create highlevel cache and get the lowlevel one from it highlevel_cache = apt.Cache(rootdir="./data/test-provides") if len(highlevel_cache) == 0: - logging.warn("skipping test_log_level_pkg_provides, cache empty?!?") + logging.warning("skipping test_log_level_pkg_provides, cache empty?!?") return # low level cache provides list of the pkg cache = highlevel_cache._cache diff --git a/tests/test_aptsources.py b/tests/test_aptsources.py index 41cfabb3..75dd91c1 100644 --- a/tests/test_aptsources.py +++ b/tests/test_aptsources.py @@ -164,7 +164,8 @@ class TestAptSources(unittest.TestCase): from subprocess import Popen, PIPE target = "./data/aptsources/sources.list.enable_comps" line = "deb http://archive.ubuntu.com/ubuntu lucid main\n" - open(target, "w").write(line) + with open(target, "w") as target_file: + target_file.write(line) apt_pkg.config.set("Dir::Etc::sourcelist", target) sources = aptsources.sourceslist.SourcesList(True, self.templates) distro = aptsources.distro.get_distro(id="Ubuntu") diff --git a/tests/test_auth.py b/tests/test_auth.py index 2b524d28..bc353427 100644 --- a/tests/test_auth.py +++ b/tests/test_auth.py @@ -1,5 +1,10 @@ #!/usr/bin/env python +from __future__ import print_function + +import contextlib +import errno +import itertools import os import shutil import sys @@ -152,6 +157,21 @@ class TestAuthKeys(TestCase): for item in cnf: apt_pkg.config.set(item, cnf[item]) + @contextlib.contextmanager + def _discard_stderr(self): + stderr_fd = sys.stderr.fileno() + stderr_save = os.dup(stderr_fd) + try: + devnull = os.open('/dev/null', os.O_WRONLY) + try: + os.dup2(devnull, stderr_fd) + yield + finally: + os.close(devnull) + finally: + os.dup2(stderr_save, stderr_fd) + os.close(stderr_save) + def testAddAndExportKey(self): """Add an example key.""" apt.auth.add_key(WHEEZY_KEY) @@ -202,20 +222,22 @@ class TestAuthKeys(TestCase): self._start_keyserver() self.addCleanup(self._stop_keyserver) with self.assertRaises(apt.auth.AptKeyError) as cm: - apt.auth.add_key_from_keyserver( - "0101010178F7FE5C3E65D8AF8B48AD6246925553", - "hkp://localhost:19191") + with self._discard_stderr(): + apt.auth.add_key_from_keyserver( + "0101010178F7FE5C3E65D8AF8B48AD6246925553", + "hkp://localhost:%d" % self.keyserver_port) self.assertTrue( - str(cm.exception).startswith("Fingerprints do not match")) + str(cm.exception).startswith("Fingerprints do not match"), cm.exception) def testAddKeyFromServer(self): """Install a GnuPG key from a remote server.""" self._start_keyserver() self.addCleanup(self._stop_keyserver) - apt.auth.add_key_from_keyserver( - "0xa1bD8E9D78F7FE5C3E65D8AF8B48AD6246925553", - "hkp://localhost:19191") + with self._discard_stderr(): + apt.auth.add_key_from_keyserver( + "0xa1bD8E9D78F7FE5C3E65D8AF8B48AD6246925553", + "hkp://localhost:%d" % self.keyserver_port) ret = apt.auth.list_keys() self.assertEqual(len(ret), 1) @@ -228,6 +250,8 @@ class TestAuthKeys(TestCase): def _start_keyserver(self): """Start a fake keyserver on http://localhost:19191 + If port 19191 is unavailable, try successive ports until one is. + Store the port actually in use in self.keyserver_port. Thanks pitti. """ dir = tempfile.mkdtemp() @@ -236,15 +260,39 @@ class TestAuthKeys(TestCase): with open(os.path.join(dir, "pks", "lookup"), "w") as key_file: key_file.write(WHEEZY_KEY) + keyserver_pipe = os.pipe() self.keyserver_pid = os.fork() if self.keyserver_pid == 0: + os.close(keyserver_pipe[0]) # quiesce server log os.dup2(os.open('/dev/null', os.O_WRONLY), sys.stderr.fileno()) os.chdir(dir) - httpd = HTTPServer(('localhost', 19191), HTTPRequestHandler) + for port in itertools.count(19191): + try: + httpd = HTTPServer(('localhost', port), HTTPRequestHandler) + break + except IOError as e: + if e.errno != errno.EADDRINUSE: + raise + keyserver_write = os.fdopen(keyserver_pipe[1], 'w') + print(port, file=keyserver_write) + keyserver_write.close() httpd.serve_forever() os._exit(0) + os.close(keyserver_pipe[1]) + keyserver_read = os.fdopen(keyserver_pipe[0]) + self.keyserver_port = int(keyserver_read.readline()) + keyserver_read.close() + + # temporarily disable proxy, as gnupg does not get along with that + # (LP #789049) + self.orig_proxy = os.environ.get('http_proxy') + try: + del os.environ['http_proxy'] + except KeyError: + pass + # wait a bit until server is ready time.sleep(0.5) @@ -255,6 +303,9 @@ class TestAuthKeys(TestCase): os.kill(self.keyserver_pid, 15) os.wait() + # restore proxy + if self.orig_proxy is not None: + os.environ['http_proxy'] = self.orig_proxy if __name__ == "__main__": unittest.main() diff --git a/tests/test_debfile.py b/tests/test_debfile.py index 04a6b65a..75c46966 100644 --- a/tests/test_debfile.py +++ b/tests/test_debfile.py @@ -13,7 +13,9 @@ import unittest from test_all import get_library_dir import sys -sys.path.insert(0, get_library_dir()) +libdir = get_library_dir() +if libdir: + sys.path.insert(0, libdir) import apt_pkg import apt.debfile diff --git a/tests/test_debfile_multiarch.py b/tests/test_debfile_multiarch.py index 7c02a32a..bbf62016 100644 --- a/tests/test_debfile_multiarch.py +++ b/tests/test_debfile_multiarch.py @@ -13,7 +13,9 @@ import unittest from test_all import get_library_dir import sys -sys.path.insert(0, get_library_dir()) +libdir = get_library_dir() +if libdir: + sys.path.insert(0, libdir) import apt import apt_pkg import apt.debfile @@ -23,7 +25,8 @@ class TestDebfileMultiarch(unittest.TestCase): def test_multiarch_deb_check(self): if apt_pkg.get_architectures() != ["amd64", "i386"]: - logging.warn("skipping test because running on a non-multiarch system") + # TODO: use unittest.skip + #logging.warning("skipping test because running on a non-multiarch system") return deb = apt.debfile.DebPackage( "./data/test_debs/multiarch-test1_i386.deb") @@ -37,7 +40,8 @@ class TestDebfileMultiarch(unittest.TestCase): # use "lib3ds-1-3" as a test to see if non-multiach lib conflicts work canary = "lib3ds-1-3" if not canary in cache: - logging.warn("skipping test because %s is missing" % canary) + # TODO: use unittest.skip + #logging.warning("skipping test because %s is missing" % canary) return cache[canary].mark_install() deb = apt.debfile.DebPackage( diff --git a/tests/test_lp659438.py b/tests/test_lp659438.py index d3bdd910..b9a837b4 100644 --- a/tests/test_lp659438.py +++ b/tests/test_lp659438.py @@ -39,6 +39,8 @@ class RegressionTestCase(unittest.TestCase): def setUp(self): apt_pkg.init_config() + apt_pkg.config.clear("APT::Update::Post-Invoke") + apt_pkg.config.clear("APT::Update::Post-Invoke-Success") self.chroot_path = chroot_path = tempfile.mkdtemp() # Create a damaged status file self.cache = apt.cache.Cache(rootdir=chroot_path) @@ -48,8 +50,8 @@ class RegressionTestCase(unittest.TestCase): Status: install reinstreq half-installed Priority: optional Section: admin -Architecture: all -Version: 3.6.9+build1+nobinonly-0ubuntu1""") +Version: 3.6.9+build1+nobinonly-0ubuntu1 +Architecture: all""") sources_list_path = apt_pkg.config.find_file("Dir::Etc::sourcelist") repo_path = os.path.abspath("./data/test-repo") with open(sources_list_path, "w") as sources_list: diff --git a/tests/test_progress.py b/tests/test_progress.py index 3b6285d6..b7bba02f 100644 --- a/tests/test_progress.py +++ b/tests/test_progress.py @@ -37,6 +37,8 @@ class TestProgress(unittest.TestCase): with open("fetch_sources.list","w") as fobj: fobj.write(deb_line) apt_pkg.config.set("Dir::Etc::sourcelist", "fetch_sources.list") + apt_pkg.config.clear("APT::Update::Post-Invoke") + apt_pkg.config.clear("APT::Update::Post-Invoke-Success") def test_acquire_progress(self): progress = TestAcquireProgress() diff --git a/tests/test_tagfile.py b/tests/test_tagfile.py index 33197e6a..f26f851b 100644 --- a/tests/test_tagfile.py +++ b/tests/test_tagfile.py @@ -21,7 +21,9 @@ import tempfile import unittest from test_all import get_library_dir -sys.path.insert(0, get_library_dir()) +libdir = get_library_dir() +if libdir: + sys.path.insert(0, libdir) import apt_pkg |
