diff options
Diffstat (limited to 'apt/cache.py')
| -rw-r--r-- | apt/cache.py | 161 |
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) |
