summaryrefslogtreecommitdiff
path: root/apt/cache.py
diff options
context:
space:
mode:
Diffstat (limited to 'apt/cache.py')
-rw-r--r--apt/cache.py161
1 files changed, 95 insertions, 66 deletions
diff --git a/apt/cache.py b/apt/cache.py
index 79e58282..0065d14c 100644
--- a/apt/cache.py
+++ b/apt/cache.py
@@ -1,62 +1,68 @@
# cache.py - apt cache abstraction
-#
+#
# Copyright (c) 2005 Canonical
-#
+#
# Author: Michael Vogt <michael.vogt@ubuntu.com>
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
-#
+#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
-#
+#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
+import os
+import sys
+
import apt_pkg
from apt import Package
import apt.progress
-import os
-import sys
+
class FetchCancelledException(IOError):
- " Exception that is thrown when the user cancels a fetch operation "
- pass
+ """Exception that is thrown when the user cancels a fetch operation."""
+
+
class FetchFailedException(IOError):
- " Exception that is thrown when fetching fails "
- pass
+ """Exception that is thrown when fetching fails."""
+
+
class LockFailedException(IOError):
- " Exception that is thrown when locking fails "
- pass
+ """Exception that is thrown when locking fails."""
+
class Cache(object):
- """ Dictionary-like package cache
- This class has all the packages that are available in it's
- dictionary
+ """Dictionary-like package cache.
+
+ This class has all the packages that are available in it's
+ dictionary
"""
def __init__(self, progress=None, rootdir=None, memonly=False):
self._callbacks = {}
if memonly:
# force apt to build its caches in memory
- apt_pkg.Config.Set("Dir::Cache::pkgcache","")
+ apt_pkg.Config.Set("Dir::Cache::pkgcache", "")
if rootdir:
apt_pkg.Config.Set("Dir", rootdir)
- apt_pkg.Config.Set("Dir::State::status", rootdir + "/var/lib/dpkg/status")
+ apt_pkg.Config.Set("Dir::State::status",
+ rootdir + "/var/lib/dpkg/status")
self.open(progress)
def _runCallbacks(self, name):
""" internal helper to run a callback """
- if self._callbacks.has_key(name):
+ if name in self._callbacks:
for callback in self._callbacks[name]:
callback()
-
+
def open(self, progress):
""" Open the package cache, after that it can be used like
a dictionary
@@ -70,12 +76,12 @@ class Cache(object):
self._dict = {}
# build the packages dict
- if progress != None:
+ if progress is not None:
progress.Op = "Building data structures"
i=last=0
size=len(self._cache.Packages)
for pkg in self._cache.Packages:
- if progress != None and last+100 < i:
+ if progress is not None and last+100 < i:
progress.update(i/float(size)*100)
last=i
# drop stuff with no versions (cruft)
@@ -83,12 +89,12 @@ class Cache(object):
self._dict[pkg.Name] = Package(self._cache, self._depcache,
self._records, self._list,
self, pkg)
-
+
i += 1
- if progress != None:
+ if progress is not None:
progress.done()
self._runCallbacks("cache_post_open")
-
+
def __getitem__(self, key):
""" look like a dictionary (get key) """
return self._dict[key]
@@ -99,10 +105,10 @@ class Cache(object):
raise StopIteration
def has_key(self, key):
- return self._dict.has_key(key)
+ return (key in self._dict)
def __contains__(self, key):
- return key in self._dict
+ return (key in self._dict)
def __len__(self):
return len(self._dict)
@@ -112,7 +118,7 @@ class Cache(object):
def getChanges(self):
""" Get the marked changes """
- changes = []
+ changes = []
for name in self._dict.keys():
p = self._dict[name]
if p.markedUpgrade or p.markedInstall or p.markedDelete or \
@@ -130,21 +136,23 @@ class Cache(object):
@property
def requiredDownload(self):
- """ get the size of the packages that are required to download """
+ """Get the size of the packages that are required to download."""
pm = apt_pkg.GetPackageManager(self._depcache)
fetcher = apt_pkg.GetAcquire()
pm.GetArchives(fetcher, self._list, self._records)
return fetcher.FetchNeeded
+
@property
def additionalRequiredSpace(self):
- """ get the size of the additional required space on the fs """
+ """Get the size of the additional required space on the fs."""
return self._depcache.UsrSize
+
@property
def reqReinstallPkgs(self):
- " return the packages not downloadable packages in reqreinst state "
+ """Return the packages not downloadable packages in reqreinst state."""
reqreinst = set()
for pkg in self:
- if (not pkg.candidateDownloadable and
+ if (not pkg.candidateDownloadable and
(pkg._pkg.InstState == apt_pkg.InstStateReInstReq or
pkg._pkg.InstState == apt_pkg.InstStateHoldReInstReq)):
reqreinst.add(pkg.name)
@@ -153,7 +161,7 @@ class Cache(object):
def _runFetcher(self, fetcher):
# do the actual fetching
res = fetcher.Run()
-
+
# now check the result (this is the code from apt-get.cc)
failed = False
transient = False
@@ -164,14 +172,15 @@ class Cache(object):
if item.StatIdle:
transient = True
continue
- errMsg += "Failed to fetch %s %s\n" % (item.DescURI,item.ErrorText)
+ errMsg += "Failed to fetch %s %s\n" % (item.DescURI,
+ item.ErrorText)
failed = True
# we raise a exception if the download failed or it was cancelt
if res == fetcher.ResultCancelled:
- raise FetchCancelledException, errMsg
+ raise FetchCancelledException(errMsg)
elif failed:
- raise FetchFailedException, errMsg
+ raise FetchFailedException(errMsg)
return res
def _fetchArchives(self, fetcher, pm):
@@ -181,7 +190,7 @@ class Cache(object):
lockfile = apt_pkg.Config.FindDir("Dir::Cache::Archives") + "lock"
lock = apt_pkg.GetLock(lockfile)
if lock < 0:
- raise LockFailedException, "Failed to lock %s" % lockfile
+ raise LockFailedException("Failed to lock %s" % lockfile)
try:
# this may as well throw a SystemError exception
@@ -193,6 +202,11 @@ class Cache(object):
finally:
os.close(lock)
+ def isVirtualPackage(self, pkgname):
+ """Return whether the package is a virtual package."""
+ pkg = self._cache[pkgname]
+ return bool(pkg.ProvidesList and not pkg.VersionList)
+
def getProvidingPackages(self, virtual):
"""
Return a list of packages which provide the virtual package of the
@@ -207,7 +221,7 @@ class Cache(object):
return providers
for pkg in self:
v = self._depcache.GetCandidateVer(pkg._pkg)
- if v == None:
+ if v is None:
continue
for p in v.ProvidesList:
if virtual == p[0]:
@@ -220,21 +234,21 @@ class Cache(object):
lockfile = apt_pkg.Config.FindDir("Dir::State::Lists") + "lock"
lock = apt_pkg.GetLock(lockfile)
if lock < 0:
- raise LockFailedException, "Failed to lock %s" % lockfile
+ raise LockFailedException("Failed to lock %s" % lockfile)
try:
- if fetchProgress == None:
+ if fetchProgress is None:
fetchProgress = apt.progress.FetchProgress()
return self._cache.Update(fetchProgress, self._list)
finally:
os.close(lock)
-
+
def installArchives(self, pm, installProgress):
installProgress.startUpdate()
res = installProgress.run(pm)
installProgress.finishUpdate()
return res
-
+
def commit(self, fetchProgress=None, installProgress=None):
""" Apply the marked changes to the cache """
# FIXME:
@@ -244,9 +258,9 @@ class Cache(object):
# Current a failed download will just display "error"
# which is less than optimal!
- if fetchProgress == None:
+ if fetchProgress is None:
fetchProgress = apt.progress.FetchProgress()
- if installProgress == None:
+ if installProgress is None:
installProgress = apt.progress.InstallProgress()
pm = apt_pkg.GetPackageManager(self._depcache)
@@ -260,16 +274,17 @@ class Cache(object):
if res == pm.ResultCompleted:
break
if res == pm.ResultFailed:
- raise SystemError, "installArchives() failed"
+ raise SystemError("installArchives() failed")
# reload the fetcher for media swaping
fetcher.Shutdown()
return (res == pm.ResultCompleted)
def clear(self):
- """ Unmark all changes """
- self._depcache.Init()
+ """ Unmark all changes """
+ self._depcache.Init()
# cache changes
+
def cachePostChange(self):
" called internally if the cache has changed, emit a signal then "
self._runCallbacks("cache_post_change")
@@ -282,34 +297,42 @@ class Cache(object):
def connect(self, name, callback):
""" connect to a signal, currently only used for
cache_{post,pre}_{changed,open} """
- if not self._callbacks.has_key(name):
+ if not name in self._callbacks:
self._callbacks[name] = []
self._callbacks[name].append(callback)
+
# ----------------------------- experimental interface
+
+
class Filter(object):
""" Filter base class """
+
def apply(self, pkg):
""" Filter function, return True if the package matchs a
filter criteria and False otherwise
"""
return True
+
class MarkedChangesFilter(Filter):
""" Filter that returns all marked changes """
+
def apply(self, pkg):
if pkg.markedInstall or pkg.markedDelete or pkg.markedUpgrade:
return True
else:
return False
+
class FilteredCache(object):
""" A package cache that is filtered.
Can work on a existing cache or create a new one
"""
+
def __init__(self, cache=None, progress=None):
- if cache == None:
+ if cache is None:
self.cache = Cache(progress)
else:
self.cache = cache
@@ -317,17 +340,25 @@ class FilteredCache(object):
self.cache.connect("cache_post_open", self.filterCachePostChange)
self._filtered = {}
self._filters = []
+
def __len__(self):
return len(self._filtered)
-
+
def __getitem__(self, key):
return self.cache._dict[key]
+ def __iter__(self):
+ for pkgname in self._filtered:
+ yield self.cache[pkgname]
+
def keys(self):
return self._filtered.keys()
def has_key(self, key):
- return self._filtered.has_key(key)
+ return (key in self._filtered)
+
+ def __contains__(self, key):
+ return (key in self._filtered)
def _reapplyFilter(self):
" internal helper to refilter "
@@ -337,9 +368,9 @@ class FilteredCache(object):
if f.apply(self.cache._dict[pkg]):
self._filtered[pkg] = 1
break
-
+
def setFilter(self, filter):
- " set the current active filter "
+ """Set the current active filter."""
self._filters = []
self._filters.append(filter)
#self._reapplyFilter()
@@ -347,7 +378,7 @@ class FilteredCache(object):
self.cache.cachePostChange()
def filterCachePostChange(self):
- " called internally if the cache changes, emit a signal then "
+ """Called internally if the cache changes, emit a signal then."""
#print "filterCachePostChange()"
self._reapplyFilter()
@@ -355,17 +386,15 @@ class FilteredCache(object):
# self.cache.connect(name, callback)
def __getattr__(self, key):
- " we try to look exactly like a real cache "
+ """we try to look exactly like a real cache."""
#print "getattr: %s " % key
- if self.__dict__.has_key(key):
- return self.__dict__[key]
- else:
- return getattr(self.cache, key)
-
+ return getattr(self.cache, key)
+
def cache_pre_changed():
print "cache pre changed"
+
def cache_post_changed():
print "cache post changed"
@@ -377,7 +406,7 @@ if __name__ == "__main__":
c = Cache(apt.progress.OpTextProgress())
c.connect("cache_pre_change", cache_pre_changed)
c.connect("cache_post_change", cache_post_changed)
- print c.has_key("aptitude")
+ print ("aptitude" in c)
p = c["aptitude"]
print p.name
print len(c)
@@ -397,7 +426,7 @@ if __name__ == "__main__":
for d in ["/tmp/pytest", "/tmp/pytest/partial"]:
if not os.path.exists(d):
os.mkdir(d)
- apt_pkg.Config.Set("Dir::Cache::Archives","/tmp/pytest")
+ apt_pkg.Config.Set("Dir::Cache::Archives", "/tmp/pytest")
pm = apt_pkg.GetPackageManager(c._depcache)
fetcher = apt_pkg.GetAcquire(apt.progress.TextFetchProgress())
c._fetchArchives(fetcher, pm)
@@ -413,7 +442,7 @@ if __name__ == "__main__":
for pkg in f.keys():
#print c[pkg].name
x = f[pkg].name
-
+
print len(f)
print "Testing filtered cache (no argument)"
@@ -426,5 +455,5 @@ if __name__ == "__main__":
for pkg in f.keys():
#print c[pkg].name
x = f[pkg].name
-
+
print len(f)