summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vogt <michael.vogt@ubuntu.com>2012-10-15 11:08:38 +0200
committerMichael Vogt <michael.vogt@ubuntu.com>2012-10-15 11:08:38 +0200
commitc2cf3de2f95a9d1dfa6def5db41f7508b83a5a8d (patch)
tree5608168db59f57185932e36c41e05e51264a0d61
parentfafe0098d1afdfdd7c491fd814286b0c3ea03486 (diff)
parent44c2dafdd59c98f629b812f6e741c14073908eb2 (diff)
downloadpython-apt-c2cf3de2f95a9d1dfa6def5db41f7508b83a5a8d.tar.gz
merged lp:~jconti/python-apt/closeable-cache
-rw-r--r--apt/cache.py20
-rw-r--r--tests/test_apt_cache.py30
2 files changed, 46 insertions, 4 deletions
diff --git a/apt/cache.py b/apt/cache.py
index 86a788bb..adc936ef 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.
@@ -172,6 +175,19 @@ class Cache(object):
progress.done()
self._run_callbacks("cache_post_open")
+ def close(self):
+ """ Close the package cache """
+ 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 +254,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 +306,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/tests/test_apt_cache.py b/tests/test_apt_cache.py
index 448aed75..fc429cf3 100644
--- a/tests/test_apt_cache.py
+++ b/tests/test_apt_cache.py
@@ -7,19 +7,21 @@
# 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
from test_all import get_library_dir
-import sys
sys.path.insert(0, get_library_dir())
import apt
import apt_pkg
-import shutil
-import glob
-import logging
+
def if_sources_list_is_readable(f):
def wrapper(*args, **kwargs):
@@ -29,6 +31,16 @@ def if_sources_list_is_readable(f):
logging.warn("skipping '%s' because sources.list is not readable" % f)
return wrapper
+
+def get_open_file_descriptors():
+ try:
+ fds = os.listdir("/proc/self/fd")
+ except OSError:
+ logging.warn("failed to list /proc/self/fd")
+ return set([])
+ return set(map(int, fds))
+
+
class TestAptCache(unittest.TestCase):
""" test the apt cache """
@@ -70,6 +82,16 @@ class TestAptCache(unittest.TestCase):
self.assertTrue(len(r['Description']) > 0)
self.assertTrue(str(r).startswith('Package: %s\n' % pkg.shortname))
+ @if_sources_list_is_readable
+ def test_closeable_cache(self):
+ fd_0 = get_open_file_descriptors()
+ cache = apt.Cache()
+ opened_fd = get_open_file_descriptors().difference(fd_0)
+ cache.close()
+ fd_1 = get_open_file_descriptors()
+ unclosed_fd = opened_fd.intersection(fd_1)
+ self.assertEqual(unclosed_fd, set())
+
def test_get_provided_packages(self):
apt.apt_pkg.config.set("Apt::architecture", "i386")
cache = apt.Cache(rootdir="./data/test-provides/")