From 5363fda9e7ebdc4dd191183ece2e6e070d68d716 Mon Sep 17 00:00:00 2001 From: Emanuele Rocca Date: Sat, 4 Oct 2008 22:13:00 +0200 Subject: Add tests/getcache_mem_corruption.py --- tests/getcache_mem_corruption.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/getcache_mem_corruption.py diff --git a/tests/getcache_mem_corruption.py b/tests/getcache_mem_corruption.py new file mode 100644 index 00000000..e127f66e --- /dev/null +++ b/tests/getcache_mem_corruption.py @@ -0,0 +1,11 @@ +#!/usr/bin/python +import apt_pkg +import re + +apt_pkg.InitConfig() +apt_pkg.InitSystem() +apt_cache = apt_pkg.GetCache() +# wrong +apt_depcache = apt_pkg.GetCache(apt_cache) +# correct: apt_depcache = apt_pkg.GetDepCache(apt_cache) +re.compile('a') -- cgit v1.2.3 From 754744630ff6228029cd025074dc0cfe3de08495 Mon Sep 17 00:00:00 2001 From: Emanuele Rocca Date: Mon, 6 Oct 2008 10:31:30 +0200 Subject: Test case and proposed fix for Debian bug #497049 --- python/cache.cc | 17 ++++++++++++++--- tests/getcache_mem_corruption.py | 27 ++++++++++++++++++++------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/python/cache.cc b/python/cache.cc index bd280dec..523444b5 100644 --- a/python/cache.cc +++ b/python/cache.cc @@ -936,14 +936,25 @@ PyObject *TmpGetCache(PyObject *Self,PyObject *Args) pkgCacheFile *Cache = new pkgCacheFile(); if(pyCallbackInst != 0) { + if (PyObject_HasAttrString(pyCallbackInst, "done") != 1) { + PyErr_SetString(PyExc_ValueError, + "progress object must implement done()"); + return 0; + } + if (PyObject_HasAttrString(pyCallbackInst, "update") != 1) { + PyErr_SetString(PyExc_ValueError, + "progress object must implement update()"); + return 0; + } PyOpProgress progress; progress.setCallbackInst(pyCallbackInst); if (Cache->Open(progress,false) == false) - return HandleErrors(); - } else { + return HandleErrors(); + } + else { OpTextProgress Prog; if (Cache->Open(Prog,false) == false) - return HandleErrors(); + return HandleErrors(); } CppOwnedPyObject *CacheFileObj = diff --git a/tests/getcache_mem_corruption.py b/tests/getcache_mem_corruption.py index e127f66e..42e9af00 100644 --- a/tests/getcache_mem_corruption.py +++ b/tests/getcache_mem_corruption.py @@ -1,11 +1,24 @@ #!/usr/bin/python +import apt import apt_pkg import re -apt_pkg.InitConfig() -apt_pkg.InitSystem() -apt_cache = apt_pkg.GetCache() -# wrong -apt_depcache = apt_pkg.GetCache(apt_cache) -# correct: apt_depcache = apt_pkg.GetDepCache(apt_cache) -re.compile('a') +import unittest + +class TestGetCache(unittest.TestCase): + + def setUp(self): + apt_pkg.InitConfig() + apt_pkg.InitSystem() + + def testWrongInvocation(self): + # wrongly invoke GetCache() rather than GetDepCache() + apt_cache = apt_pkg.GetCache() + self.assertRaises(ValueError, apt_pkg.GetCache, apt_cache) + + def testProperInvocation(self): + apt_cache = apt_pkg.GetCache(apt.progress.OpTextProgress()) + apt_depcache = apt_pkg.GetDepCache(apt_cache) + +if __name__ == "__main__": + unittest.main() -- cgit v1.2.3 From 1237c81910c2e4b9757aa9b023993f77d45cee69 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 14 Jan 2009 14:47:02 +0100 Subject: * debian/changelog: Close some more bugs. --- debian/changelog | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 976c72da..c5b1f252 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,7 +3,7 @@ python-apt (0.7.9~exp2) experimental; urgency=low [ Julian Andres Klode ] * apt/*.py: - Almost complete cleanup of the code - - Remove inconsistent use of tabs and spaces (Closes: #505443) + - Fix inconsistent use of tabs and spaces (Closes: #505443) (LP: #297207) - Improved documentation * apt/debfile.py: - Drop get*() methods, as they are deprecated and were @@ -11,7 +11,7 @@ python-apt (0.7.9~exp2) experimental; urgency=low - Make DscSrcPackage working * apt/gtk/widgets.py: - Fix the code and document the signals - * Introduce new documentation build with Sphinx + * Introduce new documentation build with Sphinx (Closes: #204818) - Contains style Guide (Closes: #481562) - debian/rules: Build the documentation here - setup.py: Remove pydoc building and add new docs. @@ -42,7 +42,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 Sun, 11 Jan 2009 20:01:59 +0100 + -- Julian Andres Klode Wed, 14 Jan 2009 13:39:56 +0100 python-apt (0.7.9~exp1) experimental; urgency=low -- cgit v1.2.3 From 66f9141c1bce95290ea087e1dc2bedeecc0ae156 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 14 Jan 2009 14:48:58 +0100 Subject: Add Vcs-Browser --- debian/changelog | 3 ++- debian/control | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index c5b1f252..4b2406f0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -26,6 +26,7 @@ python-apt (0.7.9~exp2) experimental; urgency=low - Remove the Conflicts on python2.3-apt, python2.4-apt, as they are only needed for oldstable (sarge) - Build-Depend on python-sphinx (>= 0.5) + - Add Vcs-Browser * aptsources/distinfo.py: - Allow @ in mirror urls (Closes: #478171) (LP: #223097) * Merge Ben Finney's whitespace changes (Closes: #481563) @@ -42,7 +43,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 Wed, 14 Jan 2009 13:39:56 +0100 + -- Julian Andres Klode Wed, 14 Jan 2009 14:48:20 +0100 python-apt (0.7.9~exp1) experimental; urgency=low diff --git a/debian/control b/debian/control index 0cb6e215..32739d44 100644 --- a/debian/control +++ b/debian/control @@ -7,6 +7,7 @@ Standards-Version: 3.7.2.2 XS-Python-Version: all Build-Depends: debhelper (>= 5.0.37.1), libapt-pkg-dev (>= 0.7.10), apt-utils, python-all-dev, python-distutils-extra (>= 1.9.0), cdbs, python-central (>= 0.5), python-all-dbg, python-sphinx (>= 0.5) Vcs-Bzr: http://bzr.debian.org/apt/python-apt/debian-sid +Vcs-Browser: http://bzr.debian.org/loggerhead/apt/python-apt/debian-sid/changes Package: python-apt Architecture: any -- cgit v1.2.3 From 39ee07ea10a802342cfdc6f20842c489673fcb00 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 22 Jan 2009 17:27:40 +0100 Subject: apt/debfile.py, aptsources/distro.py: Fix styling This fixes some styling issues. --- apt/debfile.py | 6 ++++-- aptsources/distro.py | 33 +++++++++++++++++---------------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/apt/debfile.py b/apt/debfile.py index f24f19f4..820326b9 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -202,7 +202,8 @@ 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, oper): + if self._check_single_pkg_conflict(pkg.name, ver, + oper): self._installed_conflicts.add(pkg.name) continue if self._check_single_pkg_conflict(depname, ver, oper): @@ -366,7 +367,8 @@ 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 diff --git a/aptsources/distro.py b/aptsources/distro.py index 36ab0ff8..d81c6e4a 100644 --- a/aptsources/distro.py +++ b/aptsources/distro.py @@ -103,22 +103,22 @@ class Distribution: self.is_codename(source.template.name)): #print "yeah! found a distro repo: %s" % source.line # cdroms need do be handled differently - if (source.uri.startswith("cdrom:") and + if (source.uri.startswith("cdrom:") and source.disabled == False): self.cdrom_sources.append(source) cdrom_comps.extend(source.comps) - elif (source.uri.startswith("cdrom:") and + elif (source.uri.startswith("cdrom:") and source.disabled == True): self.cdrom_sources.append(source) - elif (source.type == self.binary_type and + elif (source.type == self.binary_type and source.disabled == False): self.main_sources.append(source) comps.extend(source.comps) media.append(source.uri) - elif (source.type == self.binary_type and + elif (source.type == self.binary_type and source.disabled == True): self.disabled_sources.append(source) - elif (source.type == self.source_type + elif (source.type == self.source_type and source.disabled == False): self.source_code_sources.append(source) elif (source.type == self.source_type and @@ -126,10 +126,10 @@ class Distribution: self.disabled_sources.append(source) if (source.invalid == False and source.template in self.source_template.children): - if (source.disabled == False + if (source.disabled == False and source.type == self.binary_type): self.child_sources.append(source) - elif (source.disabled == False + elif (source.disabled == False and source.type == self.source_type): self.source_code_sources.append(source) else: @@ -167,15 +167,16 @@ class Distribution: et = ElementTree(file=fname) it = et.getiterator('iso_3166_entry') for elm in it: - if elm.attrib.has_key("common_name"): + try: descr = elm.attrib["common_name"] - else: + except KeyError: descr = elm.attrib["name"] - if elm.attrib.has_key("alpha_2_code"): + try: code = elm.attrib["alpha_2_code"] - else: + except KeyError: code = elm.attrib["alpha_3_code"] - self.countries[code.lower()] = gettext.dgettext('iso_3166',descr) + self.countries[code.lower()] = gettext.dgettext('iso_3166', + descr) # try to guess the nearest mirror from the locale self.country = None @@ -219,14 +220,14 @@ class Distribution: # Store all available servers: # Name, URI, active mirrors = [] - if (len(self.used_servers) < 1 or - (len(self.used_servers) == 1 and + if (len(self.used_servers) < 1 or + (len(self.used_servers) == 1 and compare_mirrors(self.used_servers[0], self.main_server))): mirrors.append([_("Main server"), self.main_server, True]) if self.nearest_server: mirrors.append([self._get_mirror_name(self.nearest_server), self.nearest_server, False]) - elif (len(self.used_servers) == 1 and not + elif (len(self.used_servers) == 1 and not compare_mirrors(self.used_servers[0], self.main_server)): mirrors.append([_("Main server"), self.main_server, False]) # Only one server is used @@ -384,7 +385,7 @@ class Distribution: change_server_of_source(source, uri, seen_binary) for source in self.child_sources: # Do not change the forces server of a child source - if (source.template.base_uri is None or + if (source.template.base_uri is None or source.template.base_uri != source.uri): change_server_of_source(source, uri, seen_binary) for source in self.source_code_sources: -- cgit v1.2.3 From b9a649803801c8925a4109d252c52846bfd020fd Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Mon, 16 Feb 2009 13:51:47 +0100 Subject: aptsources/sourceslist.py: use apt_pkg.Config.FindFile --- aptsources/sourceslist.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/aptsources/sourceslist.py b/aptsources/sourceslist.py index dc2a5d45..f4d88822 100644 --- a/aptsources/sourceslist.py +++ b/aptsources/sourceslist.py @@ -219,7 +219,7 @@ class NullMatcher(object): return True -class SourcesList: +class SourcesList(object): """ represents the full sources.list + sources.list.d file """ def __init__(self, @@ -236,9 +236,8 @@ class SourcesList: """ update the list of known entries """ self.list = [] # read sources.list - dir = apt_pkg.Config.FindDir("Dir::Etc") - file = apt_pkg.Config.Find("Dir::Etc::sourcelist") - self.load(dir+file) + file = apt_pkg.Config.FindFile("Dir::Etc::sourcelist") + self.load(file) # read sources.list.d partsdir = apt_pkg.Config.FindDir("Dir::Etc::sourceparts") for file in glob.glob("%s/*.list" % partsdir): @@ -312,11 +311,10 @@ class SourcesList: def restoreBackup(self, backup_ext): " restore sources.list files based on the backup extension " - dir = apt_pkg.Config.FindDir("Dir::Etc") - file = apt_pkg.Config.Find("Dir::Etc::sourcelist") - if os.path.exists(dir+file+backup_ext) and \ - os.path.exists(dir+file): - shutil.copy(dir+file+backup_ext, dir+file) + file = apt_pkg.Config.FindFile("Dir::Etc::sourcelist") + if os.path.exists(file+backup_ext) and \ + os.path.exists(file): + shutil.copy(file+backup_ext, file) # now sources.list.d partsdir = apt_pkg.Config.FindDir("Dir::Etc::sourceparts") for file in glob.glob("%s/*.list" % partsdir): @@ -353,8 +351,7 @@ class SourcesList: files = {} # write an empty default config file if there aren't any sources if len(self.list) == 0: - path = "%s%s" % (apt_pkg.Config.FindDir("Dir::Etc"), - apt_pkg.Config.Find("Dir::Etc::sourcelist")) + path = apt_pkg.Config.FindFile("Dir::Etc::sourcelist" header = ( "## See sources.list(5) for more information, especialy\n" "# Remember that you can only use http, ftp or file URIs\n" -- cgit v1.2.3 From 19bd571a866fbe66d1bf024d458cfff8193c3f4d Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 25 Feb 2009 19:40:08 +0100 Subject: add a bunch of #!/usr/bin/python to the examples --- doc/examples/acquire.py | 1 + doc/examples/desc.py | 1 + doc/examples/indexfile.py | 1 + doc/examples/metaindex.py | 1 + doc/examples/progress.py | 2 ++ doc/examples/update.py | 1 + 6 files changed, 7 insertions(+) diff --git a/doc/examples/acquire.py b/doc/examples/acquire.py index 58372961..a23c41c6 100644 --- a/doc/examples/acquire.py +++ b/doc/examples/acquire.py @@ -1,3 +1,4 @@ +#!/usr/bin/python import apt import apt_pkg import os diff --git a/doc/examples/desc.py b/doc/examples/desc.py index f47517cf..2febf348 100644 --- a/doc/examples/desc.py +++ b/doc/examples/desc.py @@ -1,3 +1,4 @@ +#!/usr/bin/python import apt_pkg diff --git a/doc/examples/indexfile.py b/doc/examples/indexfile.py index 22d0b635..2f1f27f8 100644 --- a/doc/examples/indexfile.py +++ b/doc/examples/indexfile.py @@ -1,3 +1,4 @@ +#!/usr/bin/python import apt_pkg diff --git a/doc/examples/metaindex.py b/doc/examples/metaindex.py index f00a7e01..816a3fd7 100644 --- a/doc/examples/metaindex.py +++ b/doc/examples/metaindex.py @@ -1,3 +1,4 @@ +#!/usr/bin/python import apt_pkg diff --git a/doc/examples/progress.py b/doc/examples/progress.py index 83847598..304bd117 100644 --- a/doc/examples/progress.py +++ b/doc/examples/progress.py @@ -1,3 +1,5 @@ +#!/usr/bin/python + import sys import time diff --git a/doc/examples/update.py b/doc/examples/update.py index 364fa1c9..5929c9f8 100755 --- a/doc/examples/update.py +++ b/doc/examples/update.py @@ -1,3 +1,4 @@ +#!/usr/bin/python import apt import apt_pkg import os.path -- cgit v1.2.3 From 46c29108ea76d1ca336042be99bbe11e8e5061b8 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 26 Feb 2009 11:53:50 +0100 Subject: avoid duplicated internal references of the Package object for _cache, _depcache, _records, _list - they add up to ~10mb for the full cache on my test system and all information is available via Package._pcache --- apt/cache.py | 4 +-- apt/package.py | 86 +++++++++++++++++++++++++++----------------------------- debian/changelog | 2 ++ 3 files changed, 44 insertions(+), 48 deletions(-) diff --git a/apt/cache.py b/apt/cache.py index 01c12c94..cd9c5fe9 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -90,9 +90,7 @@ class Cache(object): last=i # drop stuff with no versions (cruft) if len(pkg.VersionList) > 0: - self._dict[pkg.Name] = Package(self._cache, self._depcache, - self._records, self._list, - self, pkg) + self._dict[pkg.Name] = Package(self, pkg) i += 1 if progress is not None: diff --git a/apt/package.py b/apt/package.py index f5262fff..8b4e1803 100644 --- a/apt/package.py +++ b/apt/package.py @@ -85,7 +85,7 @@ class Origin(object): self.site = VerFileIter.Site self.not_automatic = VerFileIter.NotAutomatic # check the trust - indexfile = pkg._list.FindIndex(VerFileIter) + indexfile = pkg._pcache._list.FindIndex(VerFileIter) if indexfile and indexfile.IsTrusted: self.trusted = True else: @@ -145,13 +145,9 @@ class Package(object): much more. """ - def __init__(self, cache, depcache, records, sourcelist, pcache, pkgiter): + def __init__(self, pcache, pkgiter): """ Init the Package object """ - self._cache = cache # low level cache - self._depcache = depcache - self._records = records self._pkg = pkgiter - self._list = sourcelist # sourcelist self._pcache = pcache # python cache in cache.py self._changelog = "" # Cached changelog @@ -161,7 +157,7 @@ class Package(object): Must be called before _records is accessed. """ if UseCandidate: - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) else: ver = self._pkg.CurrentVer @@ -175,7 +171,7 @@ class Package(object): print "No FileList for: %s " % self._pkg.Name() return False f, index = ver.FileList.pop(0) - self._records.Lookup((f, index)) + self._pcache._records.Lookup((f, index)) return True @property @@ -208,7 +204,7 @@ class Package(object): @property def candidateVersion(self): """Return the candidate version as string.""" - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) if ver is not None: return ver.VerStr else: @@ -234,7 +230,7 @@ class Package(object): @property def candidateDependencies(self): """Return a list of candidate dependencies.""" - candver = self._depcache.GetCandidateVer(self._pkg) + candver = self._pcache._depcache.GetCandidateVer(self._pkg) if candver is None: return [] return self._getDependencies(candver) @@ -252,7 +248,7 @@ class Package(object): """Return the Architecture of the package""" if not self._lookupRecord(): return None - sec = apt_pkg.ParseSection(self._records.Record) + sec = apt_pkg.ParseSection(self._pcache._records.Record) try: return sec["Architecture"] except KeyError: @@ -261,7 +257,7 @@ class Package(object): def _downloadable(self, useCandidate=True): """Return True if the package is downloadable.""" if useCandidate: - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) else: ver = self._pkg.CurrentVer if ver is None: @@ -284,7 +280,7 @@ class Package(object): if not self._lookupRecord(): if not self._lookupRecord(False): return self._pkg.Name - src = self._records.SourcePkg + src = self._pcache._records.SourcePkg if src != "": return src else: @@ -295,7 +291,7 @@ class Package(object): """Return the homepage field as string.""" if not self._lookupRecord(): return None - return self._records.Homepage + return self._pcache._records.Homepage @property def section(self): @@ -305,7 +301,7 @@ class Package(object): @property def priority(self): """Return the priority (of the candidate version).""" - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) if ver: return ver.PriorityStr else: @@ -314,7 +310,7 @@ class Package(object): @property def installedPriority(self): """Return the priority (of the installed version).""" - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) if ver: return ver.PriorityStr else: @@ -325,10 +321,10 @@ class Package(object): """Return the short description (one line summary).""" if not self._lookupRecord(): return "" - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) desc_iter = ver.TranslatedDescription - self._records.Lookup(desc_iter.FileList.pop(0)) - return self._records.ShortDesc + self._pcache._records.Lookup(desc_iter.FileList.pop(0)) + return self._pcache._records.ShortDesc @property def description(self, format=True, useDots=False): @@ -344,12 +340,12 @@ class Package(object): if not self._lookupRecord(): return "" # get the translated description - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) desc_iter = ver.TranslatedDescription - self._records.Lookup(desc_iter.FileList.pop(0)) + self._pcache._records.Lookup(desc_iter.FileList.pop(0)) desc = "" try: - dsc = unicode(self._records.LongDesc, "utf-8") + dsc = unicode(self._pcache._records.LongDesc, "utf-8") except UnicodeDecodeError, err: dsc = _("Invalid unicode in description for '%s' (%s). " "Please report.") % (self.name, err) @@ -391,53 +387,53 @@ class Package(object): """return the long description (raw).""" if not self._lookupRecord(): return "" - return self._records.LongDesc + return self._pcache._records.LongDesc @property def candidateRecord(self): """Return the Record of the candidate version of the package.""" if not self._lookupRecord(True): return None - return Record(self._records.Record) + return Record(self._pcache._records.Record) @property def installedRecord(self): """Return the Record of the candidate version of the package.""" if not self._lookupRecord(False): return None - return Record(self._records.Record) + return Record(self._pcache._records.Record) # depcache states @property def markedInstall(self): """Return True if the package is marked for install.""" - return self._depcache.MarkedInstall(self._pkg) + return self._pcache._depcache.MarkedInstall(self._pkg) @property def markedUpgrade(self): """Return True if the package is marked for upgrade.""" - return self._depcache.MarkedUpgrade(self._pkg) + return self._pcache._depcache.MarkedUpgrade(self._pkg) @property def markedDelete(self): """Return True if the package is marked for delete.""" - return self._depcache.MarkedDelete(self._pkg) + return self._pcache._depcache.MarkedDelete(self._pkg) @property def markedKeep(self): """Return True if the package is marked for keep.""" - return self._depcache.MarkedKeep(self._pkg) + return self._pcache._depcache.MarkedKeep(self._pkg) @property def markedDowngrade(self): """ Package is marked for downgrade """ - return self._depcache.MarkedDowngrade(self._pkg) + return self._pcache._depcache.MarkedDowngrade(self._pkg) @property def markedReinstall(self): """Return True if the package is marked for reinstall.""" - return self._depcache.MarkedReinstall(self._pkg) + return self._pcache._depcache.MarkedReinstall(self._pkg) @property def isInstalled(self): @@ -447,7 +443,7 @@ class Package(object): @property def isUpgradable(self): """Return True if the package is upgradable.""" - return self.isInstalled and self._depcache.IsUpgradable(self._pkg) + return self.isInstalled and self._pcache._depcache.IsUpgradable(self._pkg) @property def isAutoRemovable(self): @@ -457,14 +453,14 @@ class Package(object): another package, and if no packages depend on it anymore, the package is no longer required. """ - return self.isInstalled and self._depcache.IsGarbage(self._pkg) + return self.isInstalled and self._pcache._depcache.IsGarbage(self._pkg) # sizes @property def packageSize(self): """Return the size of the candidate deb package.""" - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) return ver.Size @property @@ -476,7 +472,7 @@ class Package(object): @property def candidateInstalledSize(self, UseCandidate=True): """Return the size of the candidate installed package.""" - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) if ver: return ver.Size else: @@ -545,7 +541,7 @@ class Package(object): # assume "main" section src_section = "main" # use the section of the candidate as a starting point - section = self._depcache.GetCandidateVer(self._pkg).Section + section = self._pcache._depcache.GetCandidateVer(self._pkg).Section # get the source version, start with the binaries version bin_ver = self.candidateVersion @@ -661,7 +657,7 @@ class Package(object): @property def candidateOrigin(self): """Return the Origin() of the candidate version.""" - ver = self._depcache.GetCandidateVer(self._pkg) + ver = self._pcache._depcache.GetCandidateVer(self._pkg) if not ver: return None origins = [] @@ -674,7 +670,7 @@ class Package(object): def markKeep(self): """Mark a package for keep.""" self._pcache.cachePreChange() - self._depcache.MarkKeep(self._pkg) + self._pcache._depcache.MarkKeep(self._pkg) self._pcache.cachePostChange() def markDelete(self, autoFix=True, purge=False): @@ -687,10 +683,10 @@ class Package(object): well. The default is to keep the configuration. """ self._pcache.cachePreChange() - self._depcache.MarkDelete(self._pkg, purge) + self._pcache._depcache.MarkDelete(self._pkg, purge) # try to fix broken stuffsta - if autoFix and self._depcache.BrokenCount > 0: - Fix = apt_pkg.GetPkgProblemResolver(self._depcache) + if autoFix and self._pcache._depcache.BrokenCount > 0: + Fix = apt_pkg.GetPkgProblemResolver(self._pcache._depcache) Fix.Clear(self._pkg) Fix.Protect(self._pkg) Fix.Remove(self._pkg) @@ -713,10 +709,10 @@ class Package(object): it. """ self._pcache.cachePreChange() - self._depcache.MarkInstall(self._pkg, autoInst, fromUser) + self._pcache._depcache.MarkInstall(self._pkg, autoInst, fromUser) # try to fix broken stuff - if autoFix and self._depcache.BrokenCount > 0: - fixer = apt_pkg.GetPkgProblemResolver(self._depcache) + if autoFix and self._pcache._depcache.BrokenCount > 0: + fixer = apt_pkg.GetPkgProblemResolver(self._pcache._depcache) fixer.Clear(self._pkg) fixer.Protect(self._pkg) fixer.Resolve(True) @@ -740,7 +736,7 @@ class Package(object): The parameter `iprogress` refers to an InstallProgress() object, as found in apt.progress. """ - self._depcache.Commit(fprogress, iprogress) + self._pcache._depcache.Commit(fprogress, iprogress) def _test(): diff --git a/debian/changelog b/debian/changelog index ffacbec0..f8494712 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,8 @@ python-apt (0.7.9~exp3) experimental; urgency=low config from it as well * python/configuration.cc, python/apt_pkgmodule.cc: - add apt_pkg.ReadConfigDir() + * apt/package.py: + - avoid uneeded interal references in the Package objects -- -- cgit v1.2.3 From dc7440e55ea06cc4e0a6e53cd7bb6e3eee3af452 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 16:44:42 +0100 Subject: * apt/gtk/widgets.py: Handle older versions of python-gobject which do not ship glib --- apt/gtk/widgets.py | 5 ++++- debian/changelog | 23 ++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/apt/gtk/widgets.py b/apt/gtk/widgets.py index 34cc2759..435265d4 100644 --- a/apt/gtk/widgets.py +++ b/apt/gtk/widgets.py @@ -29,7 +29,10 @@ import time import pygtk pygtk.require('2.0') import gtk -import glib +try: + import glib +except ImportError: + import gobject as glib import gobject import pango import vte diff --git a/debian/changelog b/debian/changelog index 400b15f5..81e25b17 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,13 @@ python-apt (0.7.9~exp3) experimental; urgency=low + [ Julian Andres Klode ] + * apt/gtk/widgets.py: + - Handle older versions of python-gobject which do not ship glib + + [ Michael Vogt ] * aptsources/distro.py: - use iso_3166.xml instead of iso_3166.tab - - fix incorrect indent + - fix incorrect indent * debian/control: - add Recommends to iso-codes (for iso_3166.xml) @@ -42,7 +47,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 @@ -59,7 +64,7 @@ python-apt (0.7.9~exp1) experimental; urgency=low * Merged python-apt consolidation branch by Sebastian Heinlein (many thanks) * apt/cache.py: - - new method "isVirtualPackage()" + - new method "isVirtualPackage()" - new method "getProvidingPackages()" - new method "getRequiredDownload()" - new method "additionalRequiredSpace()" @@ -68,7 +73,7 @@ python-apt (0.7.9~exp1) experimental; urgency=low provides interfaces for querrying and installing .deb files and .dsc files * apt/package.py: - - better description parsing + - better description parsing - new method "installedFiles()" - new method "getChangelog()" * apt/gtk/widgets.py: @@ -77,7 +82,7 @@ python-apt (0.7.9~exp1) experimental; urgency=low - new gobject GInstallProgress - new gobject GDpkgInstallProgress - new widget GtkAptProgress - * doc/examples/gui-inst.py: + * doc/examples/gui-inst.py: - updated to use the new widgets * debian/control: - add suggests for python-gtk2 and python-vte @@ -85,7 +90,7 @@ python-apt (0.7.9~exp1) experimental; urgency=low - build html/ help of the apt and aptsources modules into /usr/share/doc/python-apt/html * apt/__init__.py: - - remove the future warning + - remove the future warning -- Michael Vogt Mon, 15 Dec 2008 14:29:47 +0100 @@ -93,7 +98,7 @@ python-apt (0.7.8) unstable; urgency=low [ Michael Vogt ] * python/cache.cc: - - fix crash if Ver.PriorityType() returns NULL + - fix crash if Ver.PriorityType() returns NULL - fix GetCandidateVer() reporting incorrect versions after SetCandidateVer() was used. Thanks to Julian Andres Klode for the test-case (LP: #237372) @@ -158,7 +163,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 @@ -180,7 +185,7 @@ python-apt (0.7.6) unstable; urgency=low race condition in the pkgcache.bin handling) * data/templates/Ubuntu.info.in: - added ubuntu 'intrepid' - * debian/README.source: + * debian/README.source: - added (basic) documentation how to build python-apt * aptsources/distinfo.py: - support arch specific BaseURI, MatchURI and MirrosFile fields -- cgit v1.2.3 From a81e4f2f93808aeaeac1887aba9b41c1ee1c9b11 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 16:46:39 +0100 Subject: * apt/package.py: Introduce the Version class - Deprecate Package.candidate*() and Package.installed*(), except for installedFiles. - Provide Version.get_source() (LP: #118788) --- apt/package.py | 550 +++++++++++++++++++++++++++------------------ debian/changelog | 4 + doc/source/apt/package.rst | 5 + 3 files changed, 337 insertions(+), 222 deletions(-) diff --git a/apt/package.py b/apt/package.py index ecfd8b61..a44eb2a6 100644 --- a/apt/package.py +++ b/apt/package.py @@ -21,15 +21,19 @@ """Functionality related to packages.""" import gettext import httplib +import os import sys import re import socket +import subprocess import urllib2 +import warnings import apt_pkg +import apt.progress - -__all__ = 'BaseDependency', 'Dependency', 'Origin', 'Package', 'Record' +__all__ = ('BaseDependency', 'Dependency', 'Origin', 'Package', 'Record', + 'Version') # Set a timeout for the changelog download @@ -57,6 +61,10 @@ class BaseDependency(object): self.version = ver self.preDepend = pre + def __repr__(self): + return ('' + % (self.name, self.relation, self.version, self.preDepend)) + class Dependency(object): """Represent an Or-group of dependencies. @@ -68,6 +76,26 @@ class Dependency(object): def __init__(self, alternatives): self.or_dependencies = alternatives + def __repr__(self): + return repr(self.or_dependencies) + +class DeprecatedProperty(property): + """A property which gives DeprecationWarning on access. + + This is only used for providing the properties in Package, which have been + replaced by the ones in Version. + """ + + def __init__(self, fget=None, fset=None, fdel=None, doc=None): + property.__init__(self, fget, fset, fdel, doc) + self.__doc__ = ':Deprecated: ' + (doc or fget.__doc__ or '') + + def __get__(self, obj, type=None): + warnings.warn("Accessed deprecated property %s.%s, please see the " + "Version class for alternatives." % + ((obj.__class__.__name__ or type.__name__), + self.fget.func_name), DeprecationWarning, 2) + return property.__get__(self, obj, type) class Origin(object): """The origin of a version. @@ -95,10 +123,10 @@ class Origin(object): self.trusted = False def __repr__(self): - return ("") % (self.component, self.archive, - self.origin, self.label, - self.site, self.trusted) + return ("") % (self.component, self.archive, + self.origin, self.label, + self.site, self.trusted) class Record(object): @@ -139,6 +167,208 @@ class Record(object): """deprecated form of 'key in x'.""" return self._rec.has_key(key) +class Version(object): + """Representation of a package version. + + :since: 0.7.9 + """ + + def __init__(self, package, cand): + self.package = package + self._cand = cand + + def __eq__(self, other): + return self._cand.ID == other._cand.ID + + def __gt__(self, other): + return apt_pkg.VersionCompare(self.version, other.version) > 0 + + def __lt__(self, other): + return apt_pkg.VersionCompare(self.version, other.version) < 0 + + def __ne__(self, other): + return not self.__eq__(other) + + def __hash__(self): + return self._cand.Hash + + def __repr__(self): + return '' % (self.package.name, + self.version) + + @property + def _records(self): + """Internal helper that moves the Records to the right position.""" + if self.package._records.Lookup(self._cand.FileList[0]): + return self.package._records + + @property + def installed_size(self): + """Return the size of the package when installed.""" + return self._cand.InstalledSize + + @property + def homepage(self): + """Return the homepage for the package.""" + return self._records.Homepage + + @property + def size(self): + """Return the size of the package.""" + return self._cand.Size + + @property + def architecture(self): + """Return the architecture of the package version.""" + return self._cand.Arch + + @property + def downloadable(self): + """Return whether the version of the package is downloadable.""" + return bool(self._cand.Downloadable) + + @property + def version(self): + """Return the version as a string.""" + return self._cand.VerStr + + @property + def summary(self): + """Return the short description (one line summary).""" + desc_iter = self._cand.TranslatedDescription + self.package._records.Lookup(desc_iter.FileList.pop(0)) + return self.package._records.ShortDesc + + @property + def raw_description(self): + """return the long description (raw).""" + return self._records.LongDesc + + @property + def section(self): + """Return the section of the package.""" + return self._cand.Section + + @property + def description(self, format=True, useDots=False): + """Return the formatted long description. + + Return the formated long description according to the Debian policy + (Chapter 5.6.13). + See http://www.debian.org/doc/debian-policy/ch-controlfields.html + for more information. + """ + self.summary # This does the lookup for us. + desc = '' + try: + dsc = unicode(self.package._records.LongDesc, "utf-8") + except UnicodeDecodeError, err: + return _("Invalid unicode in description for '%s' (%s). " + "Please report.") % (self.name, err) + + lines = iter(dsc.split("\n")) + # Skip the first line, since its a duplication of the summary + lines.next() + for raw_line in lines: + if raw_line.strip() == ".": + # The line is just line break + if not desc.endswith("\n"): + desc += "\n\n" + continue + if raw_line.startswith(" "): + # The line should be displayed verbatim without word wrapping + if not desc.endswith("\n"): + line = "\n%s\n" % raw_line[2:] + else: + line = "%s\n" % raw_line[2:] + elif raw_line.startswith(" "): + # The line is part of a paragraph. + if desc.endswith("\n") or desc == "": + # Skip the leading white space + line = raw_line[1:] + else: + line = raw_line + else: + line = raw_line + # Add current line to the description + desc += line + return desc + + @property + def source_name(self): + """Return the name of the source package.""" + try: + return self._records.SourcePkg or self.package.name + except IndexError: + return self.package.name + + @property + def priority(self): + """Return the priority of the package, as string.""" + return self._cand.PriorityStr + + @property + def record(self): + """Return a Record() object for this version.""" + return Record(self._records.Record) + + @property + def dependencies(self): + """Return the dependencies of the package version.""" + depends_list = [] + depends = self._cand.DependsList + for t in ["PreDepends", "Depends"]: + try: + for depVerList in depends[t]: + base_deps = [] + for depOr in depVerList: + base_deps.append(BaseDependency(depOr.TargetPkg.Name, + depOr.CompType, depOr.TargetVer, + (t == "PreDepends"))) + depends_list.append(Dependency(base_deps)) + except KeyError: + pass + return depends_list + + @property + def origins(self): + """Return a list of origins for the package version.""" + origins = [] + for (verFileIter, index) in self._cand.FileList: + origins.append(Origin(self.package, verFileIter)) + return origins + + def fetch_source(self): + """Get the source code of a package""" + src = apt_pkg.GetPkgSrcRecords() + acq = apt_pkg.GetAcquire(apt.progress.TextFetchProgress()) + dsc = None + src.Lookup(self.package.name) + try: + while self.version != src.Version: + src.Lookup(self.package.name) + except AttributeError: + raise ValueError("No source for %r" % self) + for md5, size, path, type in src.Files: + base = os.path.basename(path) + if type == 'dsc': + dsc = base + if os.path.exists(base) and os.path.getsize(base) == size: + fobj = open(base) + try: + if apt_pkg.md5sum(fobj) == md5: + print 'Ignoring already existing file', base + continue + finally: + fobj.close() + apt_pkg.GetPkgAcqFile(acq, src.Index.ArchiveURI(path), md5, size, + base) + acq.Run() + + outdir = src.Package + '-' + apt_pkg.UpstreamVersion(src.Version) + subprocess.check_call(["dpkg-source", "-x", dsc, outdir]) + return os.path.abspath(outdir) + class Package(object): """Representation of a package in a cache. @@ -158,28 +388,23 @@ class Package(object): self._pcache = pcache # python cache in cache.py self._changelog = "" # Cached changelog - def _lookupRecord(self, UseCandidate=True): - """Internal helper that moves the Records to the right position. + def __repr__(self): + return '' % (self._pkg.Name, self._pkg.ID) - Must be called before _records is accessed. - """ - if UseCandidate: - ver = self._depcache.GetCandidateVer(self._pkg) - else: - ver = self._pkg.CurrentVer + @property + def candidate(self): + """Return the candidate version of the package. - # check if we found a version - if ver is None: - #print "No version for: %s (Candidate: %s)" % (self._pkg.Name, - # UseCandidate) - return False + :since: 0.7.9""" + return Version(self, self._depcache.GetCandidateVer(self._pkg)) - if ver.FileList is None: - print "No FileList for: %s " % self._pkg.Name() - return False - f, index = ver.FileList.pop(0) - self._records.Lookup((f, index)) - return True + @property + def installed(self): + """Return the currently installed version of the package. + + :since: 0.7.9""" + if self._pkg.CurrentVer is not None: + return Version(self, self._pkg.CurrentVer) @property def name(self): @@ -199,142 +424,81 @@ class Package(object): This returns the same value as ID, which is unique.""" return self._pkg.ID - @property + @DeprecatedProperty def installedVersion(self): - """Return the installed version as string.""" - ver = self._pkg.CurrentVer - if ver is not None: - return ver.VerStr - else: - return None + """Return the installed version as string. - @property + Deprecated, please use installed.version instead.""" + return getattr(self.installed, 'version', None) + + @DeprecatedProperty def candidateVersion(self): """Return the candidate version as string.""" - ver = self._depcache.GetCandidateVer(self._pkg) - if ver is not None: - return ver.VerStr - else: - return None - - def _getDependencies(self, ver): - """Get the dependencies for a given version of a package.""" - depends_list = [] - depends = ver.DependsList - for t in ["PreDepends", "Depends"]: - try: - for depVerList in depends[t]: - base_deps = [] - for depOr in depVerList: - base_deps.append(BaseDependency(depOr.TargetPkg.Name, - depOr.CompType, depOr.TargetVer, - (t == "PreDepends"))) - depends_list.append(Dependency(base_deps)) - except KeyError: - pass - return depends_list + return self.candidate.version - @property + @DeprecatedProperty def candidateDependencies(self): """Return a list of candidate dependencies.""" - candver = self._depcache.GetCandidateVer(self._pkg) - if candver is None: - return [] - return self._getDependencies(candver) + return self.candidate.dependencies - @property + @DeprecatedProperty def installedDependencies(self): """Return a list of installed dependencies.""" - ver = self._pkg.CurrentVer - if ver is None: - return [] - return self._getDependencies(ver) + return getattr(self.installed, 'dependencies', []) - @property + @DeprecatedProperty def architecture(self): """Return the Architecture of the package""" - if not self._lookupRecord(): - return None - sec = apt_pkg.ParseSection(self._records.Record) - try: - return sec["Architecture"] - except KeyError: - return None - - def _downloadable(self, useCandidate=True): - """Return True if the package is downloadable.""" - if useCandidate: - ver = self._depcache.GetCandidateVer(self._pkg) - else: - ver = self._pkg.CurrentVer - if ver is None: - return False - return ver.Downloadable + return self.candidate.architecture - @property + @DeprecatedProperty def candidateDownloadable(self): """Return True if the candidate is downloadable.""" - return self._downloadable(True) + return self.candidate.downloadable - @property + @DeprecatedProperty def installedDownloadable(self): """Return True if the installed version is downloadable.""" - return self._downloadable(False) + return getattr(self.installed, 'downloadable', False) - @property + @DeprecatedProperty def sourcePackageName(self): """Return the source package name as string.""" - if not self._lookupRecord(): - if not self._lookupRecord(False): + try: + return self.candidate._records.SourcePkg or self._pkg.Name + except AttributeError: + try: + return self.installed._records.SourcePkg or self._pkg.Name + except AttributeError: return self._pkg.Name - src = self._records.SourcePkg - if src != "": - return src - else: - return self._pkg.Name - @property + @DeprecatedProperty def homepage(self): """Return the homepage field as string.""" - if not self._lookupRecord(): - return None - return self._records.Homepage + return self.candidate.homepage @property def section(self): """Return the section of the package.""" return self._pkg.Section - @property + @DeprecatedProperty def priority(self): """Return the priority (of the candidate version).""" - ver = self._depcache.GetCandidateVer(self._pkg) - if ver: - return ver.PriorityStr - else: - return None + return self.candidate.priority - @property + @DeprecatedProperty def installedPriority(self): """Return the priority (of the installed version).""" - ver = self._depcache.GetCandidateVer(self._pkg) - if ver: - return ver.PriorityStr - else: - return None + return getattr(self.installed, 'priority', None) - @property + @DeprecatedProperty def summary(self): """Return the short description (one line summary).""" - if not self._lookupRecord(): - return "" - ver = self._depcache.GetCandidateVer(self._pkg) - desc_iter = ver.TranslatedDescription - self._records.Lookup(desc_iter.FileList.pop(0)) - return self._records.ShortDesc + return self.candidate.summary - @property - def description(self, format=True, useDots=False): + @DeprecatedProperty + def description(self): """Return the formatted long description. Return the formated long description according to the Debian policy @@ -342,73 +506,22 @@ class Package(object): See http://www.debian.org/doc/debian-policy/ch-controlfields.html for more information. """ - if not format: - return self.rawDescription - if not self._lookupRecord(): - return "" - # get the translated description - ver = self._depcache.GetCandidateVer(self._pkg) - desc_iter = ver.TranslatedDescription - self._records.Lookup(desc_iter.FileList.pop(0)) - desc = "" - try: - dsc = unicode(self._records.LongDesc, "utf-8") - except UnicodeDecodeError, err: - dsc = _("Invalid unicode in description for '%s' (%s). " - "Please report.") % (self.name, err) - lines = dsc.split("\n") - for i in range(len(lines)): - # Skip the first line, since its a duplication of the summary - if i == 0: - continue - raw_line = lines[i] - if raw_line.strip() == ".": - # The line is just line break - if not desc.endswith("\n"): - desc += "\n" - continue - elif raw_line.startswith(" "): - # The line should be displayed verbatim without word wrapping - if not desc.endswith("\n"): - line = "\n%s\n" % raw_line[2:] - else: - line = "%s\n" % raw_line[2:] - elif raw_line.startswith(" "): - # The line is part of a paragraph. - if desc.endswith("\n") or desc == "": - # Skip the leading white space - line = raw_line[1:] - else: - line = raw_line - else: - line = raw_line - # Use dots for lists - if useDots: - line = re.sub(r"^(\s*)(\*|0|o|-) ", ur"\1\u2022 ", line, 1) - # Add current line to the description - desc += line - return desc + return self.candidate.description - @property + @DeprecatedProperty def rawDescription(self): """return the long description (raw).""" - if not self._lookupRecord(): - return "" - return self._records.LongDesc + return self.candidate.raw_description - @property + @DeprecatedProperty def candidateRecord(self): """Return the Record of the candidate version of the package.""" - if not self._lookupRecord(True): - return None - return Record(self._records.Record) + return self.candidate.record - @property + @DeprecatedProperty def installedRecord(self): """Return the Record of the candidate version of the package.""" - if not self._lookupRecord(False): - return None - return Record(self._records.Record) + return getattr(self.installed, 'record', '') # depcache states @@ -464,34 +577,25 @@ class Package(object): # sizes - @property + @DeprecatedProperty def packageSize(self): """Return the size of the candidate deb package.""" - ver = self._depcache.GetCandidateVer(self._pkg) - return ver.Size + return self.candidate.size - @property + @DeprecatedProperty def installedPackageSize(self): """Return the size of the installed deb package.""" - ver = self._pkg.CurrentVer - return ver.Size + return getattr(self.installed, 'size', 0) - @property - def candidateInstalledSize(self, UseCandidate=True): + @DeprecatedProperty + def candidateInstalledSize(self): """Return the size of the candidate installed package.""" - ver = self._depcache.GetCandidateVer(self._pkg) - if ver: - return ver.Size - else: - return None + return self.candidate.installed_size - @property + @DeprecatedProperty def installedSize(self): """Return the size of the currently installed package.""" - ver = self._pkg.CurrentVer - if ver is None: - return 0 - return ver.InstalledSize + return getattr(self.installed, 'installed_size', 0) @property def installedFiles(self): @@ -651,16 +755,18 @@ class Package(object): "check your Internet connection.") return self._changelog - @property + @DeprecatedProperty def candidateOrigin(self): - """Return the Origin() of the candidate version.""" - ver = self._depcache.GetCandidateVer(self._pkg) - if not ver: - return None - origins = [] - for (verFileIter, index) in ver.FileList: - origins.append(Origin(self, verFileIter)) - return origins + """Return a list of Origin() objects for the candidate version.""" + return self.candidate.origins + + @property + def versions(self): + """Return a list of versions. + + :since: 0.7.9 + """ + return [Version(self, ver) for ver in self._pkg.VersionList] # depcache actions @@ -751,26 +857,26 @@ def _test(): pkg = Package(cache, depcache, records, sourcelist, None, pkgiter) print "Name: %s " % pkg.name print "ID: %s " % pkg.id - print "Priority (Candidate): %s " % pkg.priority - print "Priority (Installed): %s " % pkg.installedPriority - print "Installed: %s " % pkg.installedVersion - print "Candidate: %s " % pkg.candidateVersion - print "CandidateDownloadable: %s" % pkg.candidateDownloadable - print "CandidateOrigins: %s" % pkg.candidateOrigin - print "SourcePkg: %s " % pkg.sourcePackageName + print "Priority (Candidate): %s " % pkg.candidate.priority + print "Priority (Installed): %s " % pkg.installed.priority + print "Installed: %s " % pkg.installed.version + print "Candidate: %s " % pkg.candidate.version + print "CandidateDownloadable: %s" % pkg.candidate.downloadable + print "CandidateOrigins: %s" % pkg.candidate.origins + print "SourcePkg: %s " % pkg.candidate.source_name print "Section: %s " % pkg.section - print "Summary: %s" % pkg.summary - print "Description (formated) :\n%s" % pkg.description - print "Description (unformated):\n%s" % pkg.rawDescription - print "InstalledSize: %s " % pkg.installedSize - print "PackageSize: %s " % pkg.packageSize - print "Dependencies: %s" % pkg.installedDependencies - for dep in pkg.candidateDependencies: + print "Summary: %s" % pkg.candidate.summary + print "Description (formated) :\n%s" % pkg.candidate.description + print "Description (unformated):\n%s" % pkg.candidate.raw_description + print "InstalledSize: %s " % pkg.candidate.installed_size + print "PackageSize: %s " % pkg.candidate.size + print "Dependencies: %s" % pkg.installed.dependencies + for dep in pkg.candidate.dependencies: print ",".join("%s (%s) (%s) (%s)" % (o.name, o.version, o.relation, o.preDepend) for o in dep.or_dependencies) - print "arch: %s" % pkg.architecture - print "homepage: %s" % pkg.homepage - print "rec: ", pkg.candidateRecord + print "arch: %s" % pkg.candidate.architecture + print "homepage: %s" % pkg.candidate.homepage + print "rec: ", pkg.candidate.record # now test install/remove progress = apt.progress.OpTextProgress() diff --git a/debian/changelog b/debian/changelog index 81e25b17..1ed96cc3 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,10 @@ python-apt (0.7.9~exp3) experimental; urgency=low [ Julian Andres Klode ] * apt/gtk/widgets.py: - Handle older versions of python-gobject which do not ship glib + * apt/package.py: Introduce the Version class + - Deprecate Package.candidate*() and Package.installed*(), except for + installedFiles. + - Provide Version.get_source() (LP: #118788) [ Michael Vogt ] * aptsources/distro.py: diff --git a/doc/source/apt/package.rst b/doc/source/apt/package.rst index 1bd032ab..6781717c 100644 --- a/doc/source/apt/package.rst +++ b/doc/source/apt/package.rst @@ -10,6 +10,11 @@ The Package class .. autoclass:: Package :members: +The Version class +----------------- +.. autoclass:: Version + :members: + Dependency Information ---------------------- -- cgit v1.2.3 From 2f5a96fb610ef9cb10cb2042a86fea34d8a48904 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 17:02:04 +0100 Subject: * apt/: Adjust modules to use Package.{installed,candidate}.* --- apt/cache.py | 2 +- apt/debfile.py | 21 ++++++++++----------- apt/package.py | 12 ++++++------ 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/apt/cache.py b/apt/cache.py index 0065d14c..0c729787 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -152,7 +152,7 @@ class Cache(object): """Return the packages not downloadable packages in reqreinst state.""" reqreinst = set() for pkg in self: - if (not pkg.candidateDownloadable and + if (not pkg.candidate.downloadable and (pkg._pkg.InstState == apt_pkg.InstStateReInstReq or pkg._pkg.InstState == apt_pkg.InstStateHoldReInstReq)): reqreinst.add(pkg.name) diff --git a/apt/debfile.py b/apt/debfile.py index 820326b9..c550d766 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -108,9 +108,8 @@ class DebPackage(object): return True continue - inst = self._cache[depname] - instver = inst.installedVersion - if instver is not None and apt_pkg.CheckDep(instver, oper, ver): + inst = self._cache[depname].installed + if inst is not None and apt_pkg.CheckDep(inst.version, oper, ver): return True return False @@ -163,9 +162,9 @@ class DebPackage(object): pkg = self._cache[pkgname] if pkg.isInstalled: - pkgver = pkg.installedVersion + pkgver = pkg.installed.version elif pkg.markedInstall: - pkgver = pkg.candidateVersion + pkgver = pkg.candidate.version else: return False #print "pkg: %s" % pkgname @@ -258,9 +257,9 @@ class DebPackage(object): self._dbg(3, "replacesPkg() %s %s %s" % (pkgname, oper, ver)) pkg = self._cache[pkgname] if pkg.isInstalled: - pkgver = pkg.installedVersion + pkgver = pkg.installed.version elif pkg.markedInstall: - pkgver = pkg.candidateVersion + pkgver = pkg.candidate.version else: pkgver = None for or_group in self.replaces: @@ -297,10 +296,10 @@ class DebPackage(object): debver = self._sections["Version"] self._dbg(1, "debver: %s" % debver) if pkgname in self._cache: - if use_installed: - cachever = self._cache[pkgname].installedVersion + if use_installed and self._cache[pkgname].installed: + cachever = self._cache[pkgname].installed.version else: - cachever = self._cache[pkgname].candidateVersion + cachever = self._cache[pkgname].candidate.version if cachever is not None: cmp = apt_pkg.VersionCompare(cachever, debver) self._dbg(1, "CompareVersion(debver,instver): %s" % cmp) @@ -405,7 +404,7 @@ class DebPackage(object): # check authentication, one authenticated origin is enough # libapt will skip non-authenticated origins then authenticated = False - for origin in pkg.candidateOrigin: + for origin in pkg.candidate.origins: authenticated |= origin.trusted if not authenticated: unauthenticated.append(pkg.name) diff --git a/apt/package.py b/apt/package.py index a44eb2a6..c9275360 100644 --- a/apt/package.py +++ b/apt/package.py @@ -635,11 +635,11 @@ class Package(object): return self._changelog if uri is None: - if self.candidateOrigin[0].origin == "Debian": + if self.candidate.origins[0].origin == "Debian": uri = "http://packages.debian.org/changelogs/pool" \ "/%(src_section)s/%(prefix)s/%(src_pkg)s" \ "/%(src_pkg)s_%(src_ver)s/changelog" - elif self.candidateOrigin[0].origin == "Ubuntu": + elif self.candidate.origins[0].origin == "Ubuntu": uri = "http://changelogs.ubuntu.com/changelogs/pool" \ "/%(src_section)s/%(prefix)s/%(src_pkg)s" \ "/%(src_pkg)s_%(src_ver)s/changelog" @@ -647,7 +647,7 @@ class Package(object): return _("The list of changes is not available") # get the src package name - src_pkg = self.sourcePackageName + src_pkg = self.candidate.source_name # assume "main" section src_section = "main" @@ -655,8 +655,8 @@ class Package(object): section = self._depcache.GetCandidateVer(self._pkg).Section # get the source version, start with the binaries version - bin_ver = self.candidateVersion - src_ver = self.candidateVersion + bin_ver = self.candidate.version + src_ver = self.candidate.version #print "bin: %s" % binver try: # FIXME: This try-statement is too long ... @@ -726,7 +726,7 @@ class Package(object): if match: # strip epoch from installed version # and from changelog too - installed = self.installedVersion + installed = getattr(self.installed, 'version', None) if installed and ":" in installed: installed = installed.split(":", 1)[1] changelog_ver = match.group(1) -- cgit v1.2.3 From 5afbd53a5743fe37947d0ebd282111addd325615 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 18:13:48 +0100 Subject: * apt/progress/: New package, replaces apt.progress and apt.gtk - apt/progress/gtk2.py: Moved here from apt/gtk/widgets.py - apt/progress/__init__.py: Move here from apt/progress.py --- apt/gtk/__init__.py | 0 apt/gtk/widgets.py | 443 --------------------------------------- apt/progress.py | 356 ------------------------------- apt/progress/__init__.py | 356 +++++++++++++++++++++++++++++++ apt/progress/gtk2.py | 443 +++++++++++++++++++++++++++++++++++++++ debian/changelog | 3 + doc/examples/gui-inst.py | 4 +- doc/source/apt/gtk.widgets.rst | 29 --- doc/source/apt/progress.gtk2.rst | 29 +++ doc/source/examples/apt-gtk.py | 4 +- 10 files changed, 835 insertions(+), 832 deletions(-) delete mode 100644 apt/gtk/__init__.py delete mode 100644 apt/gtk/widgets.py delete mode 100644 apt/progress.py create mode 100644 apt/progress/__init__.py create mode 100644 apt/progress/gtk2.py delete mode 100644 doc/source/apt/gtk.widgets.rst create mode 100644 doc/source/apt/progress.gtk2.rst diff --git a/apt/gtk/__init__.py b/apt/gtk/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apt/gtk/widgets.py b/apt/gtk/widgets.py deleted file mode 100644 index 435265d4..00000000 --- a/apt/gtk/widgets.py +++ /dev/null @@ -1,443 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2004-2005 Canonical -# -# Authors: Michael Vogt -# Sebastian Heinlein -# Julian Andres Klode -# -# 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. -# -# his 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 -"""GObject-powered progress classes and a GTK+ status widget.""" - -from gettext import gettext as _ -import os -import time - -import pygtk -pygtk.require('2.0') -import gtk -try: - import glib -except ImportError: - import gobject as glib -import gobject -import pango -import vte - -import apt -import apt_pkg - - -def mksig(params=(), run=gobject.SIGNAL_RUN_FIRST, rettype=gobject.TYPE_NONE): - """Simplified Create a gobject signal. - - This allows us to write signals easier, because we just need to define the - type of the parameters (in most cases). - - ``params`` is a tuple which defines the types of the arguments. - """ - return (run, rettype, params) - - -class GOpProgress(gobject.GObject, apt.progress.OpProgress): - """Operation progress with GObject signals. - - Signals: - - * status-changed(str: operation, int: percent) - * status-started() - Not Implemented yet - * status-finished() - - """ - - __gsignals__ = {"status-changed": mksig((str, int)), - "status-started": mksig(), - "status-finished": mksig()} - - def __init__(self): - apt.progress.OpProgress.__init__(self) - gobject.GObject.__init__(self) - self._context = glib.main_context_default() - - def update(self, percent): - """Called to update the percentage done""" - self.emit("status-changed", self.op, percent) - while self._context.pending(): - self._context.iteration() - - def done(self): - """Called when all operation have finished.""" - self.emit("status-finished") - - -class GInstallProgress(gobject.GObject, apt.progress.InstallProgress): - """Installation progress with GObject signals. - - Signals: - - * status-changed(str: status, int: percent) - * status-started() - * status-finished() - * status-timeout() - * status-error() - * status-conffile() - - """ - # Seconds until a maintainer script will be regarded as hanging - INSTALL_TIMEOUT = 5 * 60 - - __gsignals__ = {"status-changed": mksig((str, int)), - "status-started": mksig(), - "status-timeout": mksig(), - "status-error": mksig(), - "status-conffile": mksig(), - "status-finished": mksig()} - - def __init__(self, term): - apt.progress.InstallProgress.__init__(self) - gobject.GObject.__init__(self) - self.finished = False - self.time_last_update = time.time() - self.term = term - reaper = vte.reaper_get() - reaper.connect("child-exited", self.childExited) - self.env = ["VTE_PTY_KEEP_FD=%s" % self.writefd, - "DEBIAN_FRONTEND=gnome", - "APT_LISTCHANGES_FRONTEND=gtk"] - self._context = glib.main_context_default() - - def childExited(self, term, pid, status): - """Called when a child process exits""" - self.apt_status = os.WEXITSTATUS(status) - self.finished = True - - def error(self, pkg, errormsg): - """Called when an error happens. - - Emits: status-error() - """ - self.emit("status-error") - - def conffile(self, current, new): - """Called during conffile. - - Emits: status-conffile() - """ - self.emit("status-conffile") - - def startUpdate(self): - """Called when the update starts. - - Emits: status-started() - """ - self.emit("status-started") - - def finishUpdate(self): - """Called when the update finished. - - Emits: status-finished() - """ - self.emit("status-finished") - - def statusChange(self, pkg, percent, status): - """Called when the status changed. - - Emits: status-changed(status, percent) - """ - self.time_last_update = time.time() - self.emit("status-changed", status, percent) - - def updateInterface(self): - """Called periodically to update the interface. - - Emits: status-timeout() [When a timeout happens] - """ - apt.progress.InstallProgress.updateInterface(self) - while self._context.pending(): - self._context.iteration() - if self.time_last_update + self.INSTALL_TIMEOUT < time.time(): - self.emit("status-timeout") - - def fork(self): - """Fork the process.""" - return self.term.forkpty(envv=self.env) - - def waitChild(self): - """Wait for the child process to exit.""" - while not self.finished: - self.updateInterface() - return self.apt_status - - -class GDpkgInstallProgress(apt.progress.DpkgInstallProgress, GInstallProgress): - """An InstallProgress for local installations. - - Signals: - - * status-changed(str: status, int: percent) - * status-started() - Not Implemented yet - * status-finished() - * status-timeout() - When the maintainer script hangs - * status-error() - When an error happens - * status-conffile() - On Conffile - """ - - def run(self, debfile): - """Install the given package.""" - apt.progress.DpkgInstallProgress.run(self, debfile) - - def updateInterface(self): - """Called periodically to update the interface. - - Emits: status-timeout() [When a timeout happens]""" - apt.progress.DpkgInstallProgress.updateInterface(self) - if self.time_last_update + self.INSTALL_TIMEOUT < time.time(): - self.emit("status-timeout") - - -class GFetchProgress(gobject.GObject, apt.progress.FetchProgress): - """A Fetch Progress with GObject signals. - - Signals: - - * status-changed(str: description, int: percent) - * status-started() - * status-finished() - """ - - __gsignals__ = {"status-changed": mksig((str, int)), - "status-started": mksig(), - "status-finished": mksig()} - - def __init__(self): - apt.progress.FetchProgress.__init__(self) - gobject.GObject.__init__(self) - self._continue = True - self._context = glib.main_context_default() - - def start(self): - self.emit("status-started") - - def stop(self): - self.emit("status-finished") - - def cancel(self): - self._continue = False - - def pulse(self): - apt.progress.FetchProgress.pulse(self) - currentItem = self.currentItems + 1 - if currentItem > self.totalItems: - currentItem = self.totalItems - if self.currentCPS > 0: - text = (_("Downloading file %(current)li of %(total)li with " - "%(speed)s/s") % \ - {"current": currentItem, - "total": self.totalItems, - "speed": apt_pkg.SizeToStr(self.currentCPS)}) - else: - text = (_("Downloading file %(current)li of %(total)li") % \ - {"current": currentItem, - "total": self.totalItems}) - self.emit("status-changed", text, self.percent) - while self._context.pending(): - self._context.iteration() - return self._continue - - -class GtkAptProgress(gtk.VBox): - """Graphical progress for installation/fetch/operations. - - This widget provides a progress bar, a terminal and a status bar for - showing the progress of package manipulation tasks. - """ - - def __init__(self): - gtk.VBox.__init__(self) - self.set_spacing(6) - # Setup some child widgets - self._expander = gtk.Expander(_("Details")) - self._terminal = vte.Terminal() - #self._terminal.set_font_from_string("monospace 10") - self._expander.add(self._terminal) - self._progressbar = gtk.ProgressBar() - # Setup the always italic status label - self._label = gtk.Label() - attr_list = pango.AttrList() - attr_list.insert(pango.AttrStyle(pango.STYLE_ITALIC, 0, -1)) - self._label.set_attributes(attr_list) - self._label.set_ellipsize(pango.ELLIPSIZE_END) - self._label.set_alignment(0, 0) - # add child widgets - self.pack_start(self._progressbar, False) - self.pack_start(self._label, False) - self.pack_start(self._expander, False) - # Setup the internal progress handlers - self._progress_open = GOpProgress() - self._progress_open.connect("status-changed", self._on_status_changed) - self._progress_open.connect("status-started", self._on_status_started) - self._progress_open.connect("status-finished", - self._on_status_finished) - self._progress_fetch = GFetchProgress() - self._progress_fetch.connect("status-changed", self._on_status_changed) - self._progress_fetch.connect("status-started", self._on_status_started) - self._progress_fetch.connect("status-finished", - self._on_status_finished) - self._progress_install = GInstallProgress(self._terminal) - self._progress_install.connect("status-changed", - self._on_status_changed) - self._progress_install.connect("status-started", - self._on_status_started) - self._progress_install.connect("status-finished", - self._on_status_finished) - self._progress_install.connect("status-timeout", - self._on_status_timeout) - self._progress_install.connect("status-error", - self._on_status_timeout) - self._progress_install.connect("status-conffile", - self._on_status_timeout) - self._progress_dpkg_install = GDpkgInstallProgress(self._terminal) - self._progress_dpkg_install.connect("status-changed", - self._on_status_changed) - self._progress_dpkg_install.connect("status-started", - self._on_status_started) - self._progress_dpkg_install.connect("status-finished", - self._on_status_finished) - self._progress_dpkg_install.connect("status-timeout", - self._on_status_timeout) - self._progress_dpkg_install.connect("status-error", - self._on_status_timeout) - self._progress_dpkg_install.connect("status-conffile", - self._on_status_timeout) - - def clear(self): - """Reset all status information.""" - self._label.set_label("") - self._progressbar.set_fraction(0) - self._expander.set_expanded(False) - - @property - def open(self): - """Return the cache opening progress handler.""" - return self._progress_open - - @property - def install(self): - """Return the install progress handler.""" - return self._progress_install - - @property - def dpkg_install(self): - """Return the install progress handler for dpkg.""" - return self._dpkg_progress_install - - @property - def fetch(self): - """Return the fetch progress handler.""" - return self._progress_fetch - - def _on_status_started(self, progress): - """Called when something starts.""" - self._on_status_changed(progress, _("Starting..."), 0) - while gtk.events_pending(): - gtk.main_iteration() - - def _on_status_finished(self, progress): - """Called when something finished.""" - self._on_status_changed(progress, _("Complete"), 100) - while gtk.events_pending(): - gtk.main_iteration() - - def _on_status_changed(self, progress, status, percent): - """Called when the status changed.""" - self._label.set_text(status) - if percent is None: - self._progressbar.pulse() - else: - self._progressbar.set_fraction(percent/100.0) - while gtk.events_pending(): - gtk.main_iteration() - - def _on_status_timeout(self, progress): - """Called when timeout happens.""" - self._expander.set_expanded(True) - while gtk.events_pending(): - gtk.main_iteration() - - def cancel_download(self): - """Cancel a currently running download.""" - self._progress_fetch.cancel() - - def show_terminal(self, expanded=False): - """Show the expander for the terminal. - - Show an expander with a terminal widget which provides a way - to interact with dpkg - """ - self._expander.show() - self._terminal.show() - self._expander.set_expanded(expanded) - while gtk.events_pending(): - gtk.main_iteration() - - def hide_terminal(self): - """Hide the expander with the terminal widget.""" - self._expander.hide() - while gtk.events_pending(): - gtk.main_iteration() - - def show(self): - """Show the Box""" - gtk.HBox.show(self) - self._label.show() - self._progressbar.show() - while gtk.events_pending(): - gtk.main_iteration() - - -def _test(): - """Test function""" - import sys - - from apt.debfile import DebPackage - - win = gtk.Window() - apt_progress = GtkAptProgress() - win.set_title("GtkAptProgress Demo") - win.add(apt_progress) - apt_progress.show() - win.show() - cache = apt.cache.Cache(apt_progress.open) - pkg = cache["xterm"] - if pkg.isInstalled: - pkg.markDelete() - else: - pkg.markInstall() - apt_progress.show_terminal(True) - try: - cache.commit(apt_progress.fetch, apt_progress.install) - except Exception, exc: - print >> sys.stderr, "Exception happened:", exc - if len(sys.argv) > 1: - deb = DebPackage(sys.argv[1], cache) - deb.install(apt_progress.dpkg_install) - gtk.main() - - -if __name__ == "__main__": - _test() - -# vim: ts=4 et sts=4 diff --git a/apt/progress.py b/apt/progress.py deleted file mode 100644 index 51eb2426..00000000 --- a/apt/progress.py +++ /dev/null @@ -1,356 +0,0 @@ -# Progress.py - progress reporting classes -# -# Copyright (c) 2005 Canonical -# -# Author: Michael Vogt -# -# 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 -"""progress reporting classes. - -This module provides classes for progress reporting. They can be used with -e.g., for reporting progress on the cache opening process, the cache update -progress, or the package install progress. -""" - -import errno -import fcntl -import os -import re -import select -import sys - -import apt_pkg - - -__all__ = ('CdromProgress', 'DpkgInstallProgress', 'DumbInstallProgress', - 'FetchProgress', 'InstallProgress', 'OpProgress', 'OpTextProgress', - 'TextFetchProgress') - - -class OpProgress(object): - """Abstract class to implement reporting on cache opening. - - Subclass this class to implement simple Operation progress reporting. - """ - - def __init__(self): - self.op = None - self.subOp = None - - def update(self, percent): - """Called periodically to update the user interface.""" - - def done(self): - """Called once an operation has been completed.""" - - -class OpTextProgress(OpProgress): - """A simple text based cache open reporting class.""" - - def __init__(self): - OpProgress.__init__(self) - - def update(self, percent): - """Called periodically to update the user interface.""" - sys.stdout.write("\r%s: %.2i " % (self.subOp, percent)) - sys.stdout.flush() - - def done(self): - """Called once an operation has been completed.""" - sys.stdout.write("\r%s: Done\n" % self.op) - - -class FetchProgress(object): - """Report the download/fetching progress. - - Subclass this class to implement fetch progress reporting - """ - - # download status constants - dlDone = 0 - dlQueued = 1 - dlFailed = 2 - dlHit = 3 - dlIgnored = 4 - dlStatusStr = {dlDone: "Done", - dlQueued: "Queued", - dlFailed: "Failed", - dlHit: "Hit", - dlIgnored: "Ignored"} - - def __init__(self): - self.eta = 0.0 - self.percent = 0.0 - # Make checking easier - self.currentBytes = 0 - self.currentItems = 0 - self.totalBytes = 0 - self.totalItems = 0 - self.currentCPS = 0 - - def start(self): - """Called when the fetching starts.""" - - def stop(self): - """Called when all files have been fetched.""" - - def updateStatus(self, uri, descr, shortDescr, status): - """Called when the status of an item changes. - - This happens eg. when the downloads fails or is completed. - """ - - def pulse(self): - """Called periodically to update the user interface. - - Return True to continue or False to cancel. - """ - self.percent = (((self.currentBytes + self.currentItems) * 100.0) / - float(self.totalBytes + self.totalItems)) - if self.currentCPS > 0: - self.eta = ((self.totalBytes - self.currentBytes) / - float(self.currentCPS)) - return True - - def mediaChange(self, medium, drive): - """react to media change events.""" - - -class TextFetchProgress(FetchProgress): - """ Ready to use progress object for terminal windows """ - - def __init__(self): - FetchProgress.__init__(self) - self.items = {} - - def updateStatus(self, uri, descr, shortDescr, status): - """Called when the status of an item changes. - - This happens eg. when the downloads fails or is completed. - """ - if status != self.dlQueued: - print "\r%s %s" % (self.dlStatusStr[status], descr) - self.items[uri] = status - - def pulse(self): - """Called periodically to update the user interface. - - Return True to continue or False to cancel. - """ - FetchProgress.pulse(self) - if self.currentCPS > 0: - s = "[%2.f%%] %sB/s %s" % (self.percent, - apt_pkg.SizeToStr(int(self.currentCPS)), - apt_pkg.TimeToStr(int(self.eta))) - else: - s = "%2.f%% [Working]" % (self.percent) - print "\r%s" % (s), - sys.stdout.flush() - return True - - def stop(self): - """Called when all files have been fetched.""" - print "\rDone downloading " - - def mediaChange(self, medium, drive): - """react to media change events.""" - print ("Media change: please insert the disc labeled " - "'%s' in the drive '%s' and press enter") % (medium, drive) - - return raw_input() not in ('c', 'C') - - -class DumbInstallProgress(object): - """Report the install progress. - - Subclass this class to implement install progress reporting. - """ - - def startUpdate(self): - """Start update.""" - - def run(self, pm): - """Start installation.""" - return pm.DoInstall() - - def finishUpdate(self): - """Called when update has finished.""" - - def updateInterface(self): - """Called periodically to update the user interface""" - - -class InstallProgress(DumbInstallProgress): - """An InstallProgress that is pretty useful. - - It supports the attributes 'percent' 'status' and callbacks for the dpkg - errors and conffiles and status changes. - """ - - def __init__(self): - DumbInstallProgress.__init__(self) - self.selectTimeout = 0.1 - (read, write) = os.pipe() - self.writefd = write - self.statusfd = os.fdopen(read, "r") - fcntl.fcntl(self.statusfd.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) - self.read = "" - self.percent = 0.0 - self.status = "" - - def error(self, pkg, errormsg): - """Called when a error is detected during the install.""" - - def conffile(self, current, new): - """Called when a conffile question from dpkg is detected.""" - - def statusChange(self, pkg, percent, status): - """Called when the status changed.""" - - def updateInterface(self): - """Called periodically to update the interface.""" - if self.statusfd is None: - return - try: - while not self.read.endswith("\n"): - self.read += os.read(self.statusfd.fileno(), 1) - except OSError, (errno_, errstr): - # resource temporarly unavailable is ignored - if errno_ != errno.EAGAIN and errno_ != errno.EWOULDBLOCK: - print errstr - if not self.read.endswith("\n"): - return - - s = self.read - #print s - try: - (status, pkg, percent, status_str) = s.split(":", 3) - except ValueError: - # silently ignore lines that can't be parsed - self.read = "" - return - #print "percent: %s %s" % (pkg, float(percent)/100.0) - if status == "pmerror": - self.error(pkg, status_str) - elif status == "pmconffile": - # we get a string like this: - # 'current-conffile' 'new-conffile' useredited distedited - match = re.match("\s*\'(.*)\'\s*\'(.*)\'.*", status_str) - if match: - self.conffile(match.group(1), match.group(2)) - elif status == "pmstatus": - if float(percent) != self.percent or status_str != self.status: - self.statusChange(pkg, float(percent), - status_str.strip()) - self.percent = float(percent) - self.status = status_str.strip() - self.read = "" - - def fork(self): - """Fork.""" - return os.fork() - - def waitChild(self): - """Wait for child progress to exit.""" - while True: - select.select([self.statusfd], [], [], self.selectTimeout) - self.updateInterface() - (pid, res) = os.waitpid(self.child_pid, os.WNOHANG) - if pid == self.child_pid: - break - return res - - def run(self, pm): - """Start installing.""" - pid = self.fork() - if pid == 0: - # child - res = pm.DoInstall(self.writefd) - os._exit(res) - self.child_pid = pid - res = self.waitChild() - return os.WEXITSTATUS(res) - - -class CdromProgress(object): - """Report the cdrom add progress. - - Subclass this class to implement cdrom add progress reporting. - """ - - def __init__(self): - pass - - def update(self, text, step): - """Called periodically to update the user interface.""" - - def askCdromName(self): - """Called to ask for the name of the cdrom.""" - - def changeCdrom(self): - """Called to ask for the cdrom to be changed.""" - - -class DpkgInstallProgress(InstallProgress): - """Progress handler for a local Debian package installation.""" - - def run(self, debfile): - """Start installing the given Debian package.""" - self.debfile = debfile - self.debname = os.path.basename(debfile).split("_")[0] - pid = self.fork() - if pid == 0: - # child - res = os.system("/usr/bin/dpkg --status-fd %s -i %s" % \ - (self.writefd, self.debfile)) - os._exit(os.WEXITSTATUS(res)) - self.child_pid = pid - res = self.waitChild() - return res - - def updateInterface(self): - """Process status messages from dpkg.""" - if self.statusfd is None: - return - while True: - try: - self.read += os.read(self.statusfd.fileno(), 1) - except OSError, (errno_, errstr): - # resource temporarly unavailable is ignored - if errno_ != 11: - print errstr - break - if not self.read.endswith("\n"): - continue - - statusl = self.read.split(":") - if len(statusl) < 3: - print "got garbage from dpkg: '%s'" % self.read - self.read = "" - break - status = statusl[2].strip() - #print status - if status == "error": - self.error(self.debname, status) - elif status == "conffile-prompt": - # we get a string like this: - # 'current-conffile' 'new-conffile' useredited distedited - match = re.match("\s*\'(.*)\'\s*\'(.*)\'.*", statusl[3]) - if match: - self.conffile(match.group(1), match.group(2)) - else: - self.status = status - self.read = "" diff --git a/apt/progress/__init__.py b/apt/progress/__init__.py new file mode 100644 index 00000000..51eb2426 --- /dev/null +++ b/apt/progress/__init__.py @@ -0,0 +1,356 @@ +# Progress.py - progress reporting classes +# +# Copyright (c) 2005 Canonical +# +# Author: Michael Vogt +# +# 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 +"""progress reporting classes. + +This module provides classes for progress reporting. They can be used with +e.g., for reporting progress on the cache opening process, the cache update +progress, or the package install progress. +""" + +import errno +import fcntl +import os +import re +import select +import sys + +import apt_pkg + + +__all__ = ('CdromProgress', 'DpkgInstallProgress', 'DumbInstallProgress', + 'FetchProgress', 'InstallProgress', 'OpProgress', 'OpTextProgress', + 'TextFetchProgress') + + +class OpProgress(object): + """Abstract class to implement reporting on cache opening. + + Subclass this class to implement simple Operation progress reporting. + """ + + def __init__(self): + self.op = None + self.subOp = None + + def update(self, percent): + """Called periodically to update the user interface.""" + + def done(self): + """Called once an operation has been completed.""" + + +class OpTextProgress(OpProgress): + """A simple text based cache open reporting class.""" + + def __init__(self): + OpProgress.__init__(self) + + def update(self, percent): + """Called periodically to update the user interface.""" + sys.stdout.write("\r%s: %.2i " % (self.subOp, percent)) + sys.stdout.flush() + + def done(self): + """Called once an operation has been completed.""" + sys.stdout.write("\r%s: Done\n" % self.op) + + +class FetchProgress(object): + """Report the download/fetching progress. + + Subclass this class to implement fetch progress reporting + """ + + # download status constants + dlDone = 0 + dlQueued = 1 + dlFailed = 2 + dlHit = 3 + dlIgnored = 4 + dlStatusStr = {dlDone: "Done", + dlQueued: "Queued", + dlFailed: "Failed", + dlHit: "Hit", + dlIgnored: "Ignored"} + + def __init__(self): + self.eta = 0.0 + self.percent = 0.0 + # Make checking easier + self.currentBytes = 0 + self.currentItems = 0 + self.totalBytes = 0 + self.totalItems = 0 + self.currentCPS = 0 + + def start(self): + """Called when the fetching starts.""" + + def stop(self): + """Called when all files have been fetched.""" + + def updateStatus(self, uri, descr, shortDescr, status): + """Called when the status of an item changes. + + This happens eg. when the downloads fails or is completed. + """ + + def pulse(self): + """Called periodically to update the user interface. + + Return True to continue or False to cancel. + """ + self.percent = (((self.currentBytes + self.currentItems) * 100.0) / + float(self.totalBytes + self.totalItems)) + if self.currentCPS > 0: + self.eta = ((self.totalBytes - self.currentBytes) / + float(self.currentCPS)) + return True + + def mediaChange(self, medium, drive): + """react to media change events.""" + + +class TextFetchProgress(FetchProgress): + """ Ready to use progress object for terminal windows """ + + def __init__(self): + FetchProgress.__init__(self) + self.items = {} + + def updateStatus(self, uri, descr, shortDescr, status): + """Called when the status of an item changes. + + This happens eg. when the downloads fails or is completed. + """ + if status != self.dlQueued: + print "\r%s %s" % (self.dlStatusStr[status], descr) + self.items[uri] = status + + def pulse(self): + """Called periodically to update the user interface. + + Return True to continue or False to cancel. + """ + FetchProgress.pulse(self) + if self.currentCPS > 0: + s = "[%2.f%%] %sB/s %s" % (self.percent, + apt_pkg.SizeToStr(int(self.currentCPS)), + apt_pkg.TimeToStr(int(self.eta))) + else: + s = "%2.f%% [Working]" % (self.percent) + print "\r%s" % (s), + sys.stdout.flush() + return True + + def stop(self): + """Called when all files have been fetched.""" + print "\rDone downloading " + + def mediaChange(self, medium, drive): + """react to media change events.""" + print ("Media change: please insert the disc labeled " + "'%s' in the drive '%s' and press enter") % (medium, drive) + + return raw_input() not in ('c', 'C') + + +class DumbInstallProgress(object): + """Report the install progress. + + Subclass this class to implement install progress reporting. + """ + + def startUpdate(self): + """Start update.""" + + def run(self, pm): + """Start installation.""" + return pm.DoInstall() + + def finishUpdate(self): + """Called when update has finished.""" + + def updateInterface(self): + """Called periodically to update the user interface""" + + +class InstallProgress(DumbInstallProgress): + """An InstallProgress that is pretty useful. + + It supports the attributes 'percent' 'status' and callbacks for the dpkg + errors and conffiles and status changes. + """ + + def __init__(self): + DumbInstallProgress.__init__(self) + self.selectTimeout = 0.1 + (read, write) = os.pipe() + self.writefd = write + self.statusfd = os.fdopen(read, "r") + fcntl.fcntl(self.statusfd.fileno(), fcntl.F_SETFL, os.O_NONBLOCK) + self.read = "" + self.percent = 0.0 + self.status = "" + + def error(self, pkg, errormsg): + """Called when a error is detected during the install.""" + + def conffile(self, current, new): + """Called when a conffile question from dpkg is detected.""" + + def statusChange(self, pkg, percent, status): + """Called when the status changed.""" + + def updateInterface(self): + """Called periodically to update the interface.""" + if self.statusfd is None: + return + try: + while not self.read.endswith("\n"): + self.read += os.read(self.statusfd.fileno(), 1) + except OSError, (errno_, errstr): + # resource temporarly unavailable is ignored + if errno_ != errno.EAGAIN and errno_ != errno.EWOULDBLOCK: + print errstr + if not self.read.endswith("\n"): + return + + s = self.read + #print s + try: + (status, pkg, percent, status_str) = s.split(":", 3) + except ValueError: + # silently ignore lines that can't be parsed + self.read = "" + return + #print "percent: %s %s" % (pkg, float(percent)/100.0) + if status == "pmerror": + self.error(pkg, status_str) + elif status == "pmconffile": + # we get a string like this: + # 'current-conffile' 'new-conffile' useredited distedited + match = re.match("\s*\'(.*)\'\s*\'(.*)\'.*", status_str) + if match: + self.conffile(match.group(1), match.group(2)) + elif status == "pmstatus": + if float(percent) != self.percent or status_str != self.status: + self.statusChange(pkg, float(percent), + status_str.strip()) + self.percent = float(percent) + self.status = status_str.strip() + self.read = "" + + def fork(self): + """Fork.""" + return os.fork() + + def waitChild(self): + """Wait for child progress to exit.""" + while True: + select.select([self.statusfd], [], [], self.selectTimeout) + self.updateInterface() + (pid, res) = os.waitpid(self.child_pid, os.WNOHANG) + if pid == self.child_pid: + break + return res + + def run(self, pm): + """Start installing.""" + pid = self.fork() + if pid == 0: + # child + res = pm.DoInstall(self.writefd) + os._exit(res) + self.child_pid = pid + res = self.waitChild() + return os.WEXITSTATUS(res) + + +class CdromProgress(object): + """Report the cdrom add progress. + + Subclass this class to implement cdrom add progress reporting. + """ + + def __init__(self): + pass + + def update(self, text, step): + """Called periodically to update the user interface.""" + + def askCdromName(self): + """Called to ask for the name of the cdrom.""" + + def changeCdrom(self): + """Called to ask for the cdrom to be changed.""" + + +class DpkgInstallProgress(InstallProgress): + """Progress handler for a local Debian package installation.""" + + def run(self, debfile): + """Start installing the given Debian package.""" + self.debfile = debfile + self.debname = os.path.basename(debfile).split("_")[0] + pid = self.fork() + if pid == 0: + # child + res = os.system("/usr/bin/dpkg --status-fd %s -i %s" % \ + (self.writefd, self.debfile)) + os._exit(os.WEXITSTATUS(res)) + self.child_pid = pid + res = self.waitChild() + return res + + def updateInterface(self): + """Process status messages from dpkg.""" + if self.statusfd is None: + return + while True: + try: + self.read += os.read(self.statusfd.fileno(), 1) + except OSError, (errno_, errstr): + # resource temporarly unavailable is ignored + if errno_ != 11: + print errstr + break + if not self.read.endswith("\n"): + continue + + statusl = self.read.split(":") + if len(statusl) < 3: + print "got garbage from dpkg: '%s'" % self.read + self.read = "" + break + status = statusl[2].strip() + #print status + if status == "error": + self.error(self.debname, status) + elif status == "conffile-prompt": + # we get a string like this: + # 'current-conffile' 'new-conffile' useredited distedited + match = re.match("\s*\'(.*)\'\s*\'(.*)\'.*", statusl[3]) + if match: + self.conffile(match.group(1), match.group(2)) + else: + self.status = status + self.read = "" diff --git a/apt/progress/gtk2.py b/apt/progress/gtk2.py new file mode 100644 index 00000000..435265d4 --- /dev/null +++ b/apt/progress/gtk2.py @@ -0,0 +1,443 @@ +#!/usr/bin/env python +# +# Copyright (c) 2004-2005 Canonical +# +# Authors: Michael Vogt +# Sebastian Heinlein +# Julian Andres Klode +# +# 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. +# +# his 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 +"""GObject-powered progress classes and a GTK+ status widget.""" + +from gettext import gettext as _ +import os +import time + +import pygtk +pygtk.require('2.0') +import gtk +try: + import glib +except ImportError: + import gobject as glib +import gobject +import pango +import vte + +import apt +import apt_pkg + + +def mksig(params=(), run=gobject.SIGNAL_RUN_FIRST, rettype=gobject.TYPE_NONE): + """Simplified Create a gobject signal. + + This allows us to write signals easier, because we just need to define the + type of the parameters (in most cases). + + ``params`` is a tuple which defines the types of the arguments. + """ + return (run, rettype, params) + + +class GOpProgress(gobject.GObject, apt.progress.OpProgress): + """Operation progress with GObject signals. + + Signals: + + * status-changed(str: operation, int: percent) + * status-started() - Not Implemented yet + * status-finished() + + """ + + __gsignals__ = {"status-changed": mksig((str, int)), + "status-started": mksig(), + "status-finished": mksig()} + + def __init__(self): + apt.progress.OpProgress.__init__(self) + gobject.GObject.__init__(self) + self._context = glib.main_context_default() + + def update(self, percent): + """Called to update the percentage done""" + self.emit("status-changed", self.op, percent) + while self._context.pending(): + self._context.iteration() + + def done(self): + """Called when all operation have finished.""" + self.emit("status-finished") + + +class GInstallProgress(gobject.GObject, apt.progress.InstallProgress): + """Installation progress with GObject signals. + + Signals: + + * status-changed(str: status, int: percent) + * status-started() + * status-finished() + * status-timeout() + * status-error() + * status-conffile() + + """ + # Seconds until a maintainer script will be regarded as hanging + INSTALL_TIMEOUT = 5 * 60 + + __gsignals__ = {"status-changed": mksig((str, int)), + "status-started": mksig(), + "status-timeout": mksig(), + "status-error": mksig(), + "status-conffile": mksig(), + "status-finished": mksig()} + + def __init__(self, term): + apt.progress.InstallProgress.__init__(self) + gobject.GObject.__init__(self) + self.finished = False + self.time_last_update = time.time() + self.term = term + reaper = vte.reaper_get() + reaper.connect("child-exited", self.childExited) + self.env = ["VTE_PTY_KEEP_FD=%s" % self.writefd, + "DEBIAN_FRONTEND=gnome", + "APT_LISTCHANGES_FRONTEND=gtk"] + self._context = glib.main_context_default() + + def childExited(self, term, pid, status): + """Called when a child process exits""" + self.apt_status = os.WEXITSTATUS(status) + self.finished = True + + def error(self, pkg, errormsg): + """Called when an error happens. + + Emits: status-error() + """ + self.emit("status-error") + + def conffile(self, current, new): + """Called during conffile. + + Emits: status-conffile() + """ + self.emit("status-conffile") + + def startUpdate(self): + """Called when the update starts. + + Emits: status-started() + """ + self.emit("status-started") + + def finishUpdate(self): + """Called when the update finished. + + Emits: status-finished() + """ + self.emit("status-finished") + + def statusChange(self, pkg, percent, status): + """Called when the status changed. + + Emits: status-changed(status, percent) + """ + self.time_last_update = time.time() + self.emit("status-changed", status, percent) + + def updateInterface(self): + """Called periodically to update the interface. + + Emits: status-timeout() [When a timeout happens] + """ + apt.progress.InstallProgress.updateInterface(self) + while self._context.pending(): + self._context.iteration() + if self.time_last_update + self.INSTALL_TIMEOUT < time.time(): + self.emit("status-timeout") + + def fork(self): + """Fork the process.""" + return self.term.forkpty(envv=self.env) + + def waitChild(self): + """Wait for the child process to exit.""" + while not self.finished: + self.updateInterface() + return self.apt_status + + +class GDpkgInstallProgress(apt.progress.DpkgInstallProgress, GInstallProgress): + """An InstallProgress for local installations. + + Signals: + + * status-changed(str: status, int: percent) + * status-started() - Not Implemented yet + * status-finished() + * status-timeout() - When the maintainer script hangs + * status-error() - When an error happens + * status-conffile() - On Conffile + """ + + def run(self, debfile): + """Install the given package.""" + apt.progress.DpkgInstallProgress.run(self, debfile) + + def updateInterface(self): + """Called periodically to update the interface. + + Emits: status-timeout() [When a timeout happens]""" + apt.progress.DpkgInstallProgress.updateInterface(self) + if self.time_last_update + self.INSTALL_TIMEOUT < time.time(): + self.emit("status-timeout") + + +class GFetchProgress(gobject.GObject, apt.progress.FetchProgress): + """A Fetch Progress with GObject signals. + + Signals: + + * status-changed(str: description, int: percent) + * status-started() + * status-finished() + """ + + __gsignals__ = {"status-changed": mksig((str, int)), + "status-started": mksig(), + "status-finished": mksig()} + + def __init__(self): + apt.progress.FetchProgress.__init__(self) + gobject.GObject.__init__(self) + self._continue = True + self._context = glib.main_context_default() + + def start(self): + self.emit("status-started") + + def stop(self): + self.emit("status-finished") + + def cancel(self): + self._continue = False + + def pulse(self): + apt.progress.FetchProgress.pulse(self) + currentItem = self.currentItems + 1 + if currentItem > self.totalItems: + currentItem = self.totalItems + if self.currentCPS > 0: + text = (_("Downloading file %(current)li of %(total)li with " + "%(speed)s/s") % \ + {"current": currentItem, + "total": self.totalItems, + "speed": apt_pkg.SizeToStr(self.currentCPS)}) + else: + text = (_("Downloading file %(current)li of %(total)li") % \ + {"current": currentItem, + "total": self.totalItems}) + self.emit("status-changed", text, self.percent) + while self._context.pending(): + self._context.iteration() + return self._continue + + +class GtkAptProgress(gtk.VBox): + """Graphical progress for installation/fetch/operations. + + This widget provides a progress bar, a terminal and a status bar for + showing the progress of package manipulation tasks. + """ + + def __init__(self): + gtk.VBox.__init__(self) + self.set_spacing(6) + # Setup some child widgets + self._expander = gtk.Expander(_("Details")) + self._terminal = vte.Terminal() + #self._terminal.set_font_from_string("monospace 10") + self._expander.add(self._terminal) + self._progressbar = gtk.ProgressBar() + # Setup the always italic status label + self._label = gtk.Label() + attr_list = pango.AttrList() + attr_list.insert(pango.AttrStyle(pango.STYLE_ITALIC, 0, -1)) + self._label.set_attributes(attr_list) + self._label.set_ellipsize(pango.ELLIPSIZE_END) + self._label.set_alignment(0, 0) + # add child widgets + self.pack_start(self._progressbar, False) + self.pack_start(self._label, False) + self.pack_start(self._expander, False) + # Setup the internal progress handlers + self._progress_open = GOpProgress() + self._progress_open.connect("status-changed", self._on_status_changed) + self._progress_open.connect("status-started", self._on_status_started) + self._progress_open.connect("status-finished", + self._on_status_finished) + self._progress_fetch = GFetchProgress() + self._progress_fetch.connect("status-changed", self._on_status_changed) + self._progress_fetch.connect("status-started", self._on_status_started) + self._progress_fetch.connect("status-finished", + self._on_status_finished) + self._progress_install = GInstallProgress(self._terminal) + self._progress_install.connect("status-changed", + self._on_status_changed) + self._progress_install.connect("status-started", + self._on_status_started) + self._progress_install.connect("status-finished", + self._on_status_finished) + self._progress_install.connect("status-timeout", + self._on_status_timeout) + self._progress_install.connect("status-error", + self._on_status_timeout) + self._progress_install.connect("status-conffile", + self._on_status_timeout) + self._progress_dpkg_install = GDpkgInstallProgress(self._terminal) + self._progress_dpkg_install.connect("status-changed", + self._on_status_changed) + self._progress_dpkg_install.connect("status-started", + self._on_status_started) + self._progress_dpkg_install.connect("status-finished", + self._on_status_finished) + self._progress_dpkg_install.connect("status-timeout", + self._on_status_timeout) + self._progress_dpkg_install.connect("status-error", + self._on_status_timeout) + self._progress_dpkg_install.connect("status-conffile", + self._on_status_timeout) + + def clear(self): + """Reset all status information.""" + self._label.set_label("") + self._progressbar.set_fraction(0) + self._expander.set_expanded(False) + + @property + def open(self): + """Return the cache opening progress handler.""" + return self._progress_open + + @property + def install(self): + """Return the install progress handler.""" + return self._progress_install + + @property + def dpkg_install(self): + """Return the install progress handler for dpkg.""" + return self._dpkg_progress_install + + @property + def fetch(self): + """Return the fetch progress handler.""" + return self._progress_fetch + + def _on_status_started(self, progress): + """Called when something starts.""" + self._on_status_changed(progress, _("Starting..."), 0) + while gtk.events_pending(): + gtk.main_iteration() + + def _on_status_finished(self, progress): + """Called when something finished.""" + self._on_status_changed(progress, _("Complete"), 100) + while gtk.events_pending(): + gtk.main_iteration() + + def _on_status_changed(self, progress, status, percent): + """Called when the status changed.""" + self._label.set_text(status) + if percent is None: + self._progressbar.pulse() + else: + self._progressbar.set_fraction(percent/100.0) + while gtk.events_pending(): + gtk.main_iteration() + + def _on_status_timeout(self, progress): + """Called when timeout happens.""" + self._expander.set_expanded(True) + while gtk.events_pending(): + gtk.main_iteration() + + def cancel_download(self): + """Cancel a currently running download.""" + self._progress_fetch.cancel() + + def show_terminal(self, expanded=False): + """Show the expander for the terminal. + + Show an expander with a terminal widget which provides a way + to interact with dpkg + """ + self._expander.show() + self._terminal.show() + self._expander.set_expanded(expanded) + while gtk.events_pending(): + gtk.main_iteration() + + def hide_terminal(self): + """Hide the expander with the terminal widget.""" + self._expander.hide() + while gtk.events_pending(): + gtk.main_iteration() + + def show(self): + """Show the Box""" + gtk.HBox.show(self) + self._label.show() + self._progressbar.show() + while gtk.events_pending(): + gtk.main_iteration() + + +def _test(): + """Test function""" + import sys + + from apt.debfile import DebPackage + + win = gtk.Window() + apt_progress = GtkAptProgress() + win.set_title("GtkAptProgress Demo") + win.add(apt_progress) + apt_progress.show() + win.show() + cache = apt.cache.Cache(apt_progress.open) + pkg = cache["xterm"] + if pkg.isInstalled: + pkg.markDelete() + else: + pkg.markInstall() + apt_progress.show_terminal(True) + try: + cache.commit(apt_progress.fetch, apt_progress.install) + except Exception, exc: + print >> sys.stderr, "Exception happened:", exc + if len(sys.argv) > 1: + deb = DebPackage(sys.argv[1], cache) + deb.install(apt_progress.dpkg_install) + gtk.main() + + +if __name__ == "__main__": + _test() + +# vim: ts=4 et sts=4 diff --git a/debian/changelog b/debian/changelog index 1ed96cc3..ab188657 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,9 @@ python-apt (0.7.9~exp3) experimental; urgency=low - Deprecate Package.candidate*() and Package.installed*(), except for installedFiles. - Provide Version.get_source() (LP: #118788) + * apt/progress/: New package, replaces apt.progress and apt.gtk + - apt/progress/gtk2.py: Moved here from apt/gtk/widgets.py + - apt/progress/__init__.py: Move here from apt/progress.py [ Michael Vogt ] * aptsources/distro.py: diff --git a/doc/examples/gui-inst.py b/doc/examples/gui-inst.py index 8138d922..68f06fc0 100755 --- a/doc/examples/gui-inst.py +++ b/doc/examples/gui-inst.py @@ -5,13 +5,13 @@ import pygtk pygtk.require('2.0') import gtk -import apt.gtk.widgets +import apt.progress.gtk2 if __name__ == "__main__": win = gtk.Window() - progress = apt.gtk.widgets.GtkAptProgress() + progress = apt.progress.gtk2.GtkAptProgress() win.set_title("GtkAptProgress Demo") win.add(progress) progress.show() diff --git a/doc/source/apt/gtk.widgets.rst b/doc/source/apt/gtk.widgets.rst deleted file mode 100644 index 9fa84ead..00000000 --- a/doc/source/apt/gtk.widgets.rst +++ /dev/null @@ -1,29 +0,0 @@ -:mod:`apt.gtk.widgets` --- GTK widgets -====================================== -.. automodule:: apt.gtk.widgets - - -GObject progress classes -------------------------- - -.. autoclass:: GDpkgInstallProgress - :members: - -.. autoclass:: GFetchProgress - :members: - -.. autoclass:: GInstallProgress - :members: - -.. autoclass:: GOpProgress - :members: - -GTK+ Class ----------- -.. autoclass:: GtkAptProgress - :members: - - -Example -------- -.. literalinclude:: ../examples/apt-gtk.py diff --git a/doc/source/apt/progress.gtk2.rst b/doc/source/apt/progress.gtk2.rst new file mode 100644 index 00000000..a83ab111 --- /dev/null +++ b/doc/source/apt/progress.gtk2.rst @@ -0,0 +1,29 @@ +:mod:`apt.progress.gtk2` --- GTK widgets +======================================== +.. automodule:: apt.progress.gtk2 + + +GObject progress classes +------------------------- + +.. autoclass:: GDpkgInstallProgress + :members: + +.. autoclass:: GFetchProgress + :members: + +.. autoclass:: GInstallProgress + :members: + +.. autoclass:: GOpProgress + :members: + +GTK+ Class +---------- +.. autoclass:: GtkAptProgress + :members: + + +Example +------- +.. literalinclude:: ../examples/apt-gtk.py diff --git a/doc/source/examples/apt-gtk.py b/doc/source/examples/apt-gtk.py index c3bb09d5..835ea4ee 100644 --- a/doc/source/examples/apt-gtk.py +++ b/doc/source/examples/apt-gtk.py @@ -4,14 +4,14 @@ import pygtk pygtk.require("2.0") import gtk -import apt.gtk.widgets +import apt.progress.gtk2 def main(): """Main function.""" win = gtk.Window() win.connect("destroy", gtk.main_quit) - progress = apt.gtk.widgets.GtkAptProgress() + progress = apt.progress.gtk2.GtkAptProgress() win.set_title("GtkAptProgress Demo") win.add(progress) progress.show() -- cgit v1.2.3 From c3f9f8637176e2411b4e84e632e595cfd5512e90 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 18:20:14 +0100 Subject: * apt/cache.py, apt/package.py: Fix some bugs. --- TODO | 5 ----- apt/cache.py | 3 +-- apt/package.py | 5 ++++- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/TODO b/TODO index c3faedf4..a08a28af 100644 --- a/TODO +++ b/TODO @@ -1,8 +1,3 @@ -* apt.Package: - - change all candidateInstalledSize() to installSize(useCandidate=True) - same for candidateOrigin() (see downloadable for a example). - - might be better to have "Package.candidate.{downloadable,size,etc} - * aptsources: - make the distro detection in sources.list more clever by using the origin informaton to avoid adding full uris to (unofficial/internal) diff --git a/apt/cache.py b/apt/cache.py index 0c729787..1b5531ac 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -20,7 +20,6 @@ # USA import os -import sys import apt_pkg from apt import Package @@ -446,7 +445,7 @@ if __name__ == "__main__": print len(f) print "Testing filtered cache (no argument)" - f = FilteredCache(progress=OpTextProgress()) + f = FilteredCache(progress=apt.progress.OpTextProgress()) f.cache.connect("cache_pre_change", cache_pre_changed) f.cache.connect("cache_post_change", cache_post_changed) f.cache.upgrade() diff --git a/apt/package.py b/apt/package.py index c9275360..03b1e90c 100644 --- a/apt/package.py +++ b/apt/package.py @@ -79,6 +79,7 @@ class Dependency(object): def __repr__(self): return repr(self.or_dependencies) + class DeprecatedProperty(property): """A property which gives DeprecationWarning on access. @@ -97,6 +98,7 @@ class DeprecatedProperty(property): self.fget.func_name), DeprecationWarning, 2) return property.__get__(self, obj, type) + class Origin(object): """The origin of a version. @@ -167,6 +169,7 @@ class Record(object): """deprecated form of 'key in x'.""" return self._rec.has_key(key) + class Version(object): """Representation of a package version. @@ -264,7 +267,7 @@ class Version(object): dsc = unicode(self.package._records.LongDesc, "utf-8") except UnicodeDecodeError, err: return _("Invalid unicode in description for '%s' (%s). " - "Please report.") % (self.name, err) + "Please report.") % (self.package.name, err) lines = iter(dsc.split("\n")) # Skip the first line, since its a duplication of the summary -- cgit v1.2.3 From 645c80f504f98332fb8eceb955c13a54e38e5956 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 18:23:12 +0100 Subject: * doc/source/*: Improve the documentation - Document more attributes and functions of apt_pkg (they are all listed) --- debian/changelog | 2 + doc/source/apt/package.rst | 9 +- doc/source/apt_pkg/index.rst | 199 +++++++++++++++++++++++++++++++++++-------- doc/source/conf.py | 2 +- 4 files changed, 175 insertions(+), 37 deletions(-) diff --git a/debian/changelog b/debian/changelog index ab188657..45785487 100644 --- a/debian/changelog +++ b/debian/changelog @@ -10,6 +10,8 @@ python-apt (0.7.9~exp3) experimental; urgency=low * apt/progress/: New package, replaces apt.progress and apt.gtk - apt/progress/gtk2.py: Moved here from apt/gtk/widgets.py - apt/progress/__init__.py: Move here from apt/progress.py + * doc/source/*: Improve the documentation + - Document more attributes and functions of apt_pkg (they are all listed) [ Michael Vogt ] * aptsources/distro.py: diff --git a/doc/source/apt/package.rst b/doc/source/apt/package.rst index 6781717c..bb74915e 100644 --- a/doc/source/apt/package.rst +++ b/doc/source/apt/package.rst @@ -10,6 +10,11 @@ The Package class .. autoclass:: Package :members: + .. note:: + + Several methods have been deprecated in version 0.7.9 of python-apt, + please see the :class:`Version` class for the new alternatives. + The Version class ----------------- .. autoclass:: Version @@ -93,14 +98,14 @@ Examples cache = apt.Cache() pkg = cache['python-apt'] # Access the Package object for python-apt - print 'python-apt is trusted:', pkg.candidateOrigin.trusted + print 'python-apt is trusted:', pkg.candidate.origins[0].trusted # Mark python-apt for install pkg.markInstall() print 'python-apt is marked for install:', pkg.markedInstall - print 'python-apt is', pkg.summary #Python interface to libapt-pkg + print 'python-apt is (summary):', pkg.candidate.summary # Now, really install it cache.commit() diff --git a/doc/source/apt_pkg/index.rst b/doc/source/apt_pkg/index.rst index 1c5866a9..e944eb15 100644 --- a/doc/source/apt_pkg/index.rst +++ b/doc/source/apt_pkg/index.rst @@ -34,7 +34,7 @@ Object initialization ---------------------- .. function:: GetCache([progress]) - Return a :class:`pkgCache` object. The optional parameter ``progress`` + Return a :class:`pkgCache` object. The optional parameter *progress* specifies an instance of :class:`apt.progress.OpProgress()` which will display the open progress. @@ -44,25 +44,54 @@ Object initialization .. method:: Cdrom.Ident(progress) - Identify the cdrom. The parameter ``progress`` refers to an + Identify the cdrom. The parameter *progress* refers to an :class:`apt.progress.CdromProgress()` object. .. method:: Cdrom.Add(progress) - Add the cdrom to the sources.list file. The parameter ``progress`` + Add the cdrom to the sources.list file. The parameter *progress* refers to an :class:`apt.progress.CdromProgress()` object. - .. function:: GetDepCache(cache) - Return a :class:`pkgDepCache` object. The parameter ``cache`` specifies an + Return a :class:`pkgDepCache` object. The parameter *cache* specifies an instance of :class:`pkgCache` (see :func:`GetCache()`). .. function:: GetPkgSourceList() - Return a :class:`pkgSourceList` object. + Return a :class:`PkgSourceList` object. + +.. function:: GetPackageManager(depcache) + + Return a new :class:`PkgManager` object. The parameter *depcache* specifies + a :class:`pkgDepCache` object as returned by :func:`GetDepCache`. + +.. function:: GetPkgActionGroup(depcache) + + Return a new :class:`ActionGroup` object. The parameter *depcache* + specifies a :class:`pkgDepCache` object as returned by :func:`GetDepCache`. + +.. function:: GetPkgProblemResolver(depcache) + + Return a new :class:`ProblemResolver` object. The parameter *depcache* + specifies a :class:`pkgDepCache` object as returned by :func:`GetDepCache`. + +.. function:: GetPkgRecords(cache) + + Return a new :class:`PkgRecords` object. + + The parameter *cache* refers to an :class:`pkgCache` object, as returned + by :func:`GetCache`. + +.. function:: GetPkgSrcRecords() + + Return a new :class:`PkgSrcRecords` object. + +.. function:: newConfiguration() + + Return a new :class:`Configuration` object. The Acquire interface @@ -70,7 +99,7 @@ The Acquire interface .. function:: GetAcquire([progress]) Return an :class:`Acquire` object. This is a class which allows you - to fetch files, or archive contents. The parameter ``progress`` refers to + to fetch files, or archive contents. The parameter *progress* refers to an :class:`apt.progress.FetchProgress()` object. Acquire items have multiple methods: @@ -99,26 +128,29 @@ The Acquire interface .. function:: GetPkgAcqFile(aquire, uri[, md5, size, descr, shortDescr, destDir, destFile]) - The parameter ``acquire`` refers to an :class:`Acquire()` object as returned + Create a new :class:`PkgAcqFile()` object and register it with *acquire*, + so it will be fetched. + + The parameter *acquire* refers to an :class:`Acquire()` object as returned by :func:`GetAcquire`. The file will be added to the Acquire queue automatically. - The parameter ``uri`` refers to the location of the file, any protocol + The parameter *uri* refers to the location of the file, any protocol of apt is supported. - The parameter ``md5`` refers to the md5sum of the file. This can be used + The parameter *md5* refers to the md5sum of the file. This can be used for checking the file. - The parameter ``size`` can be used to specify the size of the package, + The parameter *size* can be used to specify the size of the package, which can then be used to calculate the progress and validate the download. - The parameter ``descr`` is a descripition of the download. It may be - used to describe the item in the progress class. ``shortDescr`` is the + The parameter *descr* is a descripition of the download. It may be + used to describe the item in the progress class. *shortDescr* is the short form of it. - You can use ``destDir`` to manipulate the directory where the file will - be saved in. Together with ``destFile`` you can specify the complete target - path. + You can use *destDir* to manipulate the directory where the file will + be saved in. Instead of *destDir*, you can also specify the full path to + the file using the parameter *destFile*. You can not combine both. @@ -130,19 +162,19 @@ of the ones provides in Python's :mod:`hashlib` module. .. function:: md5sum(object) - Return the md5sum of the object. ``object`` may either be a string, in + Return the md5sum of the object. *object* may either be a string, in which case the md5sum of the string is returned, or a :class:`file()` object, in which case the md5sum of its contents is returned. .. function:: sha1sum(object) - Return the sha1sum of the object. ``object`` may either be a string, in + Return the sha1sum of the object. *object* may either be a string, in which case the sha1sum of the string is returned, or a :class:`file()` object, in which case the sha1sum of its contents is returned. .. function:: sha256sum(object) - Return the sha256sum of the object. ``object`` may either be a string, in + Return the sha256sum of the object. *object* may either be a string, in which case the sha256sum of the string is returned, or a :class:`file()` object, in which case the sha256sum of its contents is returned. @@ -151,19 +183,15 @@ Other functions .. note:: - This documentation is created automatically and should be rewritten. + This documentation is (in parts) created automatically, and still needs to + be improved. .. autofunction:: Base64Encode .. autofunction:: CheckDep .. autofunction:: CheckDomainList .. autofunction:: DeQuoteString .. autofunction:: GetLock -.. autofunction:: GetPackageManager -.. autofunction:: GetPkgActionGroup -.. autofunction:: GetPkgProblemResolver -.. autofunction:: GetPkgRecords -.. autofunction:: GetPkgSrcRecords -.. autofunction:: newConfiguration + .. autofunction:: ParseCommandLine .. autofunction:: ParseDepends .. autofunction:: ParseSection @@ -175,14 +203,105 @@ Other functions .. autofunction:: ReadConfigFile .. autofunction:: ReadConfigFileISC .. autofunction:: RewriteSection -.. autofunction:: SizeToStr -.. autofunction:: StringToBool -.. autofunction:: StrToTime -.. autofunction:: TimeRFC1123 -.. autofunction:: TimeToStr -.. autofunction:: UpstreamVersion -.. autofunction:: URItoFileName -.. autofunction:: VersionCompare + +.. function:: SizeToStr(size) + + Return a string presenting the human-readable version of the integer + *size*. When calculating the units (k,M,G,etc.) the size is divided by the + factor 1000. + + Example:: + + >>> apt_pkg.SizeToStr(10000) + '10.0k' + +.. function:: StringToBool(input) + + Parse the string *input* and return one of **-1**, **0**, **1**. + + .. table:: Return values + + ===== ============================================= + Value Meaning + ===== ============================================= + -1 The string *input* is not recognized. + 0 The string *input* evaluates to **False**. + +1 The string *input* evaluates to **True**. + ===== ============================================= + + Example:: + + >>> apt_pkg.StringToBool("yes") + 1 + >>> apt_pkg.StringToBool("no") + 0 + >>> apt_pkg.StringToBool("not-recognized") + -1 + +.. function:: StrToTime(rfc_time) + + Convert the :rfc:`1123` conforming string *rfc_time* to the unix time, and + return the integer. This is the opposite of :func:`TimeRFC1123`. + + Example:: + + >> apt_pkg.StrToTime('Thu, 01 Jan 1970 00:00:00 GMT') + 0 + +.. function:: TimeRFC1123(seconds) + + Format the unix time specified by the integer *seconds*, according to the + requirements of :rfc:`1123`. + + Example:: + + >>> apt_pkg.TimeRFC1123(0) + 'Thu, 01 Jan 1970 00:00:00 GMT' + + +.. function:: TimeToStr(seconds) + + Format a given duration in a human-readable manner. The parameter *seconds* + refers to a number of seconds, given as an integer. The return value is a + string with a unit like 's' for seconds. + + Example:: + + >>> apt_pkg.TimeToStr(3601) + '1h0min1s' + + + +.. function:: UpstreamVersion(version) + + Return the string *version*, eliminating everything following the last + '-'. Thus, this should be equivalent to ``version.rsplit('-', 1)[0]``. + +.. function:: URItoFileName(uri) + + Take a string *uri* as parameter and return a filename which can be used to + store the file, based on the URI. + + Example:: + + >>> apt_pkg.URItoFileName('http://debian.org/index.html') + 'debian.org_index.html' + + +.. function:: VersionCompare(a, b) + + Compare two versions, *a* and *b*, and return an integer value which has + the same characteristic as the built-in :func:`cmp` function. + + .. table:: Return values + + ===== ============================================= + Value Meaning + ===== ============================================= + > 0 The version *a* is greater than version *b*. + = 0 Both versions are equal. + < 0 The version *a* is less than version *b*. + ===== ============================================= Data @@ -256,6 +375,18 @@ Select states Build information ^^^^^^^^^^^^^^^^^ .. data:: Date + + The date on which this extension has been compiled. + .. data:: LibVersion + + The version of the apt_pkg library. This is **not** the version of apt, + nor the version of python-apt. + .. data:: Time + + The time this extension has been built. + .. data:: Version + + The version of apt (not of python-apt). diff --git a/doc/source/conf.py b/doc/source/conf.py index 8f71e3e3..3b0ebed7 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -59,7 +59,7 @@ copyright = u'2009, Julian Andres Klode ' # The short X.Y version. version = '0.7' # The full version, including alpha/beta/rc tags. -release = '0.7.9~exp2' +release = '0.7.9~exp3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. -- cgit v1.2.3 From cece83b131202c9557fa332332b8cf85c2170eb8 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 19:09:47 +0100 Subject: * setup.py: Remove apt.gtk, add apt.progress --- apt/cache.py | 6 ++++-- doc/source/apt_pkg/index.rst | 1 + setup.py | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apt/cache.py b/apt/cache.py index 9f00b8a5..11e44c9e 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -52,9 +52,11 @@ class Cache(object): apt_pkg.Config.Set("Dir::Cache::pkgcache", "") if rootdir: if os.path.exists(rootdir+"/etc/apt/apt.conf"): - apt_pkg.ReadConfigFile(apt_pkg.Config, rootdir+"/etc/apt/apt.conf") + apt_pkg.ReadConfigFile(apt_pkg.Config, + rootdir + "/etc/apt/apt.conf") if os.path.isdir(rootdir+"/etc/apt/apt.conf.d"): - apt_pkg.ReadConfigDir(apt_pkg.Config, rootdir+"/etc/apt/apt.conf.d") + apt_pkg.ReadConfigDir(apt_pkg.Config, + rootdir + "/etc/apt/apt.conf.d") apt_pkg.Config.Set("Dir", rootdir) apt_pkg.Config.Set("Dir::State::status", rootdir + "/var/lib/dpkg/status") diff --git a/doc/source/apt_pkg/index.rst b/doc/source/apt_pkg/index.rst index e944eb15..6e7b772e 100644 --- a/doc/source/apt_pkg/index.rst +++ b/doc/source/apt_pkg/index.rst @@ -201,6 +201,7 @@ Other functions .. autofunction:: PkgSystemUnLock .. autofunction:: QuoteString .. autofunction:: ReadConfigFile +.. autofunction:: ReadConfigDir() .. autofunction:: ReadConfigFileISC .. autofunction:: RewriteSection diff --git a/setup.py b/setup.py index 6a22734d..fc046381 100755 --- a/setup.py +++ b/setup.py @@ -51,7 +51,7 @@ setup(name="python-apt", author="APT Development Team", author_email="deity@lists.debian.org", ext_modules=[apt_pkg, apt_inst], - packages=['apt', 'apt.gtk', 'aptsources'], + packages=['apt', 'apt.progress', 'aptsources'], data_files = [('share/python-apt/templates', glob.glob('build/data/templates/*.info')), ('share/python-apt/templates', -- cgit v1.2.3 From a00d0963e09d91c38b5db538de79bdd869a9d112 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 19:17:34 +0100 Subject: * aptsources/sourceslist.py: Add missing ')' --- aptsources/sourceslist.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aptsources/sourceslist.py b/aptsources/sourceslist.py index f4d88822..950bbd62 100644 --- a/aptsources/sourceslist.py +++ b/aptsources/sourceslist.py @@ -351,7 +351,7 @@ class SourcesList(object): files = {} # write an empty default config file if there aren't any sources if len(self.list) == 0: - path = apt_pkg.Config.FindFile("Dir::Etc::sourcelist" + path = apt_pkg.Config.FindFile("Dir::Etc::sourcelist") header = ( "## See sources.list(5) for more information, especialy\n" "# Remember that you can only use http, ftp or file URIs\n" -- cgit v1.2.3 From 29b9304e0b3024c62772df6eeebf848bb52c3c37 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 19:18:05 +0100 Subject: po/POTFILES.in: Add apt/package.py,apt/debfile.py,apt/progress/gtk2.py --- po/POTFILES.in | 4 ++- po/python-apt.pot | 92 +++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 85 insertions(+), 11 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 0cf708e1..767fa3ca 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -2,4 +2,6 @@ [type: gettext/rfc822deb] data/templates/Ubuntu.info.in [type: gettext/rfc822deb] data/templates/Debian.info.in aptsources/distro.py -apt/gtk/widgets.py \ No newline at end of file +apt/progress/gtk2.py +apt/package.py +apt/debfile.py diff --git a/po/python-apt.pot b/po/python-apt.pot index 217c772c..0de7caab 100644 --- a/po/python-apt.pot +++ b/po/python-apt.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-03-03 21:17+0100\n" +"POT-Creation-Date: 2009-03-08 19:15+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -314,7 +314,7 @@ 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,34 +322,106 @@ 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:246 #, python-format msgid "Downloading file %(current)li of %(total)li with %(speed)s/s" msgstr "" -#: ../apt/gtk/widgets.py:249 +#: ../apt/progress/gtk2.py:252 #, python-format msgid "Downloading file %(current)li of %(total)li" msgstr "" #. Setup some child widgets -#: ../apt/gtk/widgets.py:269 +#: ../apt/progress/gtk2.py:272 msgid "Details" msgstr "" -#: ../apt/gtk/widgets.py:351 +#: ../apt/progress/gtk2.py:354 msgid "Starting..." msgstr "" -#: ../apt/gtk/widgets.py:357 +#: ../apt/progress/gtk2.py:360 msgid "Complete" msgstr "" + +#: ../apt/package.py:266 +#, python-format +msgid "Invalid unicode in description for '%s' (%s). Please report." +msgstr "" + +#: ../apt/package.py:644 ../apt/package.py:748 +msgid "The list of changes is not available" +msgstr "" + +#: ../apt/package.py:752 +#, python-format +msgid "" +"The list of changes is not available yet.\n" +"\n" +"Please use http://launchpad.net/ubuntu/+source/%s/%s/+changelog\n" +"until the changes become available or try again later." +msgstr "" + +#: ../apt/package.py:758 +msgid "" +"Failed to download the list of changes. \n" +"Please check your Internet connection." +msgstr "" + +#: ../apt/debfile.py:59 +#, python-format +msgid "This is not a valid DEB archive, missing '%s' member" +msgstr "" + +#: ../apt/debfile.py:84 +#, python-format +msgid "List of files for '%s'could not be read" +msgstr "" + +#: ../apt/debfile.py:152 +#, python-format +msgid "Dependency is not satisfiable: %s\n" +msgstr "" + +#: ../apt/debfile.py:176 +#, python-format +msgid "Conflicts with the installed package '%s'" +msgstr "" + +#: ../apt/debfile.py:322 +#, python-format +msgid "Wrong architecture '%s'" +msgstr "" + +#. the deb is older than the installed +#: ../apt/debfile.py:328 +msgid "A later version is already installed" +msgstr "" + +#: ../apt/debfile.py:348 +msgid "Failed to satisfy all dependencies (broken cache)" +msgstr "" + +#: ../apt/debfile.py:379 +#, python-format +msgid "Cannot install '%s'" +msgstr "" + +#: ../apt/debfile.py:487 +#, python-format +msgid "Install Build-Dependencies for source package '%s' that builds %s\n" +msgstr "" + +#: ../apt/debfile.py:497 +msgid "An essential package would be removed" +msgstr "" -- cgit v1.2.3 From 231983e447d19630372a51412859c0942b2d3ac5 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 19:31:15 +0100 Subject: debian/changelog: Add 'Provide Package.versions (Closes: #513236)' --- debian/changelog | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/changelog b/debian/changelog index a7241740..11b1cfe7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -7,6 +7,7 @@ python-apt (0.7.9~exp3) experimental; urgency=low - Deprecate Package.candidate*() and Package.installed*(), except for installedFiles. - Provide Version.get_source() (LP: #118788) + - Provide Package.versions (Closes: #513236) * apt/progress/: New package, replaces apt.progress and apt.gtk - apt/progress/gtk2.py: Moved here from apt/gtk/widgets.py - apt/progress/__init__.py: Move here from apt/progress.py -- cgit v1.2.3 From d012f1c89a5f773d9b9ae7128e24d708bb4117cb Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 20:15:52 +0100 Subject: apt/cache.py: If no progress is given for cache open, use OpProgress. Also fix doc/examples/records.py to use Package.candidate.* --- apt/cache.py | 10 +++++----- doc/examples/records.py | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apt/cache.py b/apt/cache.py index 11e44c9e..a9430d6b 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -72,6 +72,8 @@ class Cache(object): """ Open the package cache, after that it can be used like a dictionary """ + if progress is None: + progress = apt.progress.OpProgress() self._runCallbacks("cache_pre_open") self._cache = apt_pkg.GetCache(progress) self._depcache = apt_pkg.GetDepCache(self._cache) @@ -80,9 +82,7 @@ class Cache(object): self._list.ReadMainList() self._dict = {} - # build the packages dict - if progress is not None: - progress.Op = "Building data structures" + progress.Op = "Building data structures" i=last=0 size=len(self._cache.Packages) for pkg in self._cache.Packages: @@ -94,8 +94,8 @@ class Cache(object): self._dict[pkg.Name] = Package(self, pkg) i += 1 - if progress is not None: - progress.done() + + progress.done() self._runCallbacks("cache_post_open") def __getitem__(self, key): diff --git a/doc/examples/records.py b/doc/examples/records.py index a0fc8dc4..681eac0c 100755 --- a/doc/examples/records.py +++ b/doc/examples/records.py @@ -5,9 +5,9 @@ import apt cache = apt.Cache() for pkg in cache: - if not pkg.candidateRecord: + if not pkg.candidate.record: continue - if "Task" in pkg.candidateRecord: + if "Task" in pkg.candidate.record: print "Pkg %s is part of '%s'" % ( - pkg.name, pkg.candidateRecord["Task"].split()) + pkg.name, pkg.candidate.record["Task"].split()) #print pkg.candidateRecord -- cgit v1.2.3 From e3133a7e09eae842be16eb64d7888c5751d72e75 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 8 Mar 2009 20:25:59 +0100 Subject: * doc/examples/*.py: Fix some examples, cleanup --- doc/examples/acquire.py | 2 -- doc/examples/action.py | 1 - doc/examples/build-deps.py | 2 +- doc/examples/cdrom.py | 6 ++---- doc/examples/configisc.py | 1 - doc/examples/depcache.py | 3 --- doc/examples/inst.py | 3 --- doc/examples/progress.py | 6 +++--- 8 files changed, 6 insertions(+), 18 deletions(-) diff --git a/doc/examples/acquire.py b/doc/examples/acquire.py index a23c41c6..41a38588 100644 --- a/doc/examples/acquire.py +++ b/doc/examples/acquire.py @@ -2,8 +2,6 @@ import apt import apt_pkg import os -import sys -import tempfile def get_file(fetcher, uri, destFile): diff --git a/doc/examples/action.py b/doc/examples/action.py index 9b9d7dd3..8ee86eb7 100644 --- a/doc/examples/action.py +++ b/doc/examples/action.py @@ -3,7 +3,6 @@ import apt_pkg import sys -import copy from apt.progress import OpTextProgress from progress import TextFetchProgress diff --git a/doc/examples/build-deps.py b/doc/examples/build-deps.py index aeb5667c..b5ac88a2 100755 --- a/doc/examples/build-deps.py +++ b/doc/examples/build-deps.py @@ -32,7 +32,7 @@ if len(sys.argv) < 2: print "need a package name as argument" sys.exit(1) try: - base = cache[sys.argv[1]] + pkg = base = cache[sys.argv[1]] except KeyError: print "No package %s found" % sys.argv[1] sys.exit(1) diff --git a/doc/examples/cdrom.py b/doc/examples/cdrom.py index 743220a6..408bd720 100644 --- a/doc/examples/cdrom.py +++ b/doc/examples/cdrom.py @@ -3,10 +3,8 @@ import apt_pkg import sys -import os -import copy -from progress import CdromProgress +from progress import TextCdromProgress # init @@ -15,7 +13,7 @@ apt_pkg.init() cdrom = apt_pkg.GetCdrom() print cdrom -progress = CdromProgress() +progress = TextCdromProgress() (res, ident) = cdrom.Ident(progress) print "ident result is: %s (%s) " % (res, ident) diff --git a/doc/examples/configisc.py b/doc/examples/configisc.py index de8ec6be..8da1ad0a 100755 --- a/doc/examples/configisc.py +++ b/doc/examples/configisc.py @@ -10,7 +10,6 @@ import apt_pkg import sys -import posixpath ConfigFile = apt_pkg.ParseCommandLine(apt_pkg.Config, [], sys.argv) diff --git a/doc/examples/depcache.py b/doc/examples/depcache.py index 790cc9d6..de038fe8 100644 --- a/doc/examples/depcache.py +++ b/doc/examples/depcache.py @@ -1,10 +1,7 @@ #!/usr/bin/python # example how to deal with the depcache -import apt import apt_pkg -import sys -import copy from progress import TextProgress diff --git a/doc/examples/inst.py b/doc/examples/inst.py index a3a50356..5a7fc993 100644 --- a/doc/examples/inst.py +++ b/doc/examples/inst.py @@ -3,9 +3,6 @@ import apt import sys -import os -import copy -import time from apt.progress import InstallProgress diff --git a/doc/examples/progress.py b/doc/examples/progress.py index 304bd117..2231001f 100644 --- a/doc/examples/progress.py +++ b/doc/examples/progress.py @@ -40,7 +40,7 @@ class TextFetchProgress(apt.FetchProgress): def pulse(self): print "Pulse: CPS: %s/s; Bytes: %s/%s; Item: %s/%s" % ( - apt.SizeToStr(self.currentCPS), SizeToStr(self.currentBytes), + apt.SizeToStr(self.currentCPS), apt.SizeToStr(self.currentBytes), apt.SizeToStr(self.totalBytes), self.currentItems, self.totalItems) return True @@ -81,12 +81,12 @@ class TextCdromProgress(apt.CdromProgress): def update(self, text, step): # check if we actually have some text to display if text != "": - print "Update: %s %s" % (string.strip(text), step) + print "Update: %s %s" % (text.strip(), step) def askCdromName(self): print "Please enter cd-name: ", cd_name = sys.stdin.readline() - return (True, string.strip(cd_name)) + return (True, cd_name.strip()) def changeCdrom(self): print "Please insert cdrom and press " -- cgit v1.2.3 From c0fcb974984603081a072f0e4a17e1fe01287a2d Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 19 Mar 2009 13:42:02 +0100 Subject: set to unreleased --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 33d8c67f..c8fe7cf4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -python-apt (0.7.9~exp3) experimental; urgency=low +python-apt (0.7.9~exp3) UNRELEASED; urgency=low [ Julian Andres Klode ] * apt/gtk/widgets.py: -- cgit v1.2.3 From b08e026fea9ed453d2cbaaa402fe1bd17c6242dd Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 19 Mar 2009 14:08:58 +0100 Subject: * aptsources/sourceslist.py: - fix bug in invalid lines detection (LP: #324614) --- aptsources/sourceslist.py | 2 +- debian/changelog | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/aptsources/sourceslist.py b/aptsources/sourceslist.py index f4d88822..29ee6430 100644 --- a/aptsources/sourceslist.py +++ b/aptsources/sourceslist.py @@ -144,7 +144,7 @@ class SourceEntry: return if line[0] == "#": self.disabled = True - pieces = line[1:].strip() + pieces = line[1:].strip().split() # if it looks not like a disabled deb line return if not pieces[0] in ("rpm", "rpm-src", "deb", "deb-src"): self.invalid = True diff --git a/debian/changelog b/debian/changelog index 9df26b05..3bbae45f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -19,6 +19,8 @@ python-apt (0.7.9~exp3) experimental; urgency=low closes: #497049 * apt/package.py: - avoid uneeded interal references in the Package objects + * aptsources/sourceslist.py: + - fix bug in invalid lines detection (LP: #324614) -- -- cgit v1.2.3 From 08dae2ec56cba3f08903ae285aec6e5f583f40fc Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 19 Mar 2009 21:36:25 +0100 Subject: releasing version 0.7.9 --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index c8fe7cf4..620595ea 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -python-apt (0.7.9~exp3) UNRELEASED; urgency=low +python-apt (0.7.9) unstable; urgency=low [ Julian Andres Klode ] * apt/gtk/widgets.py: @@ -81,7 +81,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 Sun, 11 Jan 2009 20:01:59 +0100 + -- Michael Vogt Fri, 16 Jan 2009 11:28:17 +0100 python-apt (0.7.9~exp1) experimental; urgency=low -- cgit v1.2.3 From d6634fdddf567ab227b4b0c1e0cd56d1b217d5a9 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Thu, 19 Mar 2009 21:38:49 +0100 Subject: this is a debian upload :) --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 620595ea..f996ef5b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -35,7 +35,7 @@ python-apt (0.7.9) unstable; urgency=low * apt/package.py: - avoid uneeded interal references in the Package objects - -- Michael Vogt Thu, 19 Mar 2009 13:39:21 +0100 + -- Michael Vogt Thu, 19 Mar 2009 13:39:21 +0100 python-apt (0.7.9~exp2) experimental; urgency=low -- cgit v1.2.3 From eef1614c216c646ccb35c73a518ac62a78457bd4 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Fri, 20 Mar 2009 23:07:39 +0100 Subject: close default timeout bug (thanks to juliank) --- debian/changelog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index f996ef5b..901f3986 100644 --- a/debian/changelog +++ b/debian/changelog @@ -22,7 +22,8 @@ python-apt (0.7.9) unstable; urgency=low - add Recommends to iso-codes (for iso_3166.xml) * apt/package.py: - make sure to set the defaulttimeout back to the - original value (in getChangelog(), LP: #314212) + original value (in getChangelog(), LP: #314212) + Closes: #513315 * apt/cache.py: - when setting a alternative rootdir, read the config from it as well -- cgit v1.2.3 From 10858f98f759a2407ac596582687581a2ed33d34 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 29 Mar 2009 16:35:39 +0200 Subject: Build-Depend on python-debian, use it to get version number from changelog --- debian/changelog | 6 ++++++ debian/control | 11 ++++++++++- doc/source/conf.py | 7 +++++-- setup.py | 22 +++++++++++++++++----- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/debian/changelog b/debian/changelog index f996ef5b..3f7b420d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +python-apt (0.7.10~exp1) experimental; urgency=low + + * Build-Depend on python-debian, use it to get version number from changelog + + -- Julian Andres Klode Sun, 29 Mar 2009 14:09:18 +0200 + python-apt (0.7.9) unstable; urgency=low [ Julian Andres Klode ] diff --git a/debian/control b/debian/control index 41e3af4a..932a2b4f 100644 --- a/debian/control +++ b/debian/control @@ -5,7 +5,16 @@ Maintainer: APT Development Team Uploaders: Matt Zimmerman , Michael Vogt Standards-Version: 3.7.2.2 XS-Python-Version: all -Build-Depends: debhelper (>= 5.0.37.1), libapt-pkg-dev (>= 0.7.10), apt-utils, python-all-dev, python-distutils-extra (>= 1.9.0), cdbs, python-central (>= 0.5), python-all-dbg, python-sphinx (>= 0.5) +Build-Depends: apt-utils, + cdbs, + debhelper (>= 5.0.37.1), + libapt-pkg-dev (>= 0.7.10), + python-all-dbg, + python-all-dev, + python-central (>= 0.5), + python-debian, + python-distutils-extra (>= 1.9.0), + python-sphinx (>= 0.5) Vcs-Bzr: http://bzr.debian.org/apt/python-apt/debian-sid Vcs-Browser: http://bzr.debian.org/loggerhead/apt/python-apt/debian-sid/changes diff --git a/doc/source/conf.py b/doc/source/conf.py index 3b0ebed7..17fe6a23 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -56,10 +56,13 @@ copyright = u'2009, Julian Andres Klode ' # |version| and |release|, also used in various other places throughout the # built documents. # +from debian_bundle.changelog import Changelog + +changes = Changelog(open('../../debian/changelog')) # The short X.Y version. -version = '0.7' +version = '.'.join(changes.full_version.split('.')[:2]) # The full version, including alpha/beta/rc tags. -release = '0.7.9~exp3' +release = changes.full_version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/setup.py b/setup.py index fc046381..1c266ce7 100755 --- a/setup.py +++ b/setup.py @@ -1,14 +1,26 @@ #! /usr/bin/env python # $Id: setup.py,v 1.2 2002/01/08 07:13:21 jgg Exp $ - -from distutils.core import setup, Extension -from distutils.sysconfig import parse_makefile -from DistUtilsExtra.command import build_extra, build_i18n import glob import os import shutil import sys +from distutils.core import setup, Extension +from distutils.sysconfig import parse_makefile +from DistUtilsExtra.command import build_extra, build_i18n + + +class FakeDebianSupportModule(object): + """Work around the python-apt dependency of debian_support.""" + + class Version(object): + """Empty class.""" + +sys.modules['debian_bundle.debian_support'] = FakeDebianSupportModule + +from debian_bundle.changelog import Changelog + + # The apt_pkg module files = map(lambda source: "python/"+source, @@ -46,7 +58,7 @@ if len(sys.argv) > 1 and sys.argv[1] == "clean" and '-a' in sys.argv: print "Not removing", dirname, "because it does not exist" setup(name="python-apt", - version="0.7.9", + version=Changelog(open('debian/changelog')).full_version, description="Python bindings for APT", author="APT Development Team", author_email="deity@lists.debian.org", -- cgit v1.2.3 From bea068087a98e03bbdaae2ac46287ed0d69e509a Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 15:25:03 +0200 Subject: Depend on libjs-jquery, and remove internal copy --- debian/changelog | 3 ++- debian/control | 3 ++- debian/rules | 6 +++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3f7b420d..3244d439 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,9 @@ python-apt (0.7.10~exp1) experimental; urgency=low * Build-Depend on python-debian, use it to get version number from changelog + * Depend on libjs-jquery, and remove internal copy - -- Julian Andres Klode Sun, 29 Mar 2009 14:09:18 +0200 + -- Julian Andres Klode Wed, 01 Apr 2009 15:24:29 +0200 python-apt (0.7.9) unstable; urgency=low diff --git a/debian/control b/debian/control index 932a2b4f..6e0acd94 100644 --- a/debian/control +++ b/debian/control @@ -20,7 +20,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 +Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, lsb-release, + libjs-jquery Recommends: iso-codes Priority: optional Provides: ${python:Provides} diff --git a/debian/rules b/debian/rules index 90b48cda..a2802ea7 100755 --- a/debian/rules +++ b/debian/rules @@ -22,9 +22,6 @@ build/python-apt-dbg:: python$$i-dbg ./setup.py build; \ done -build/python-apt:: - pydoc -w - install/python-apt-dbg:: for i in $(cdbs_python_build_versions); do \ python$$i-dbg ./setup.py install --root $(CURDIR)/debian/python-apt-dbg; \ @@ -33,6 +30,9 @@ install/python-apt-dbg:: ! -type d ! -name '*_d.so' | xargs rm -f find debian/python-apt-dbg -depth -empty -exec rmdir {} \; +binary-predeb/python-apt:: + ln -sf ../../../../javascript/jquery/jquery.js debian/python-apt/usr/share/doc/python-apt/html/_static/jquery.js + binary-predeb/python-apt-dbg:: rm -rf debian/python-apt-dbg/usr/share/doc/python-apt-dbg ln -s python-apt debian/python-apt-dbg/usr/share/doc/python-apt-dbg -- cgit v1.2.3 From 3fbbced1f6d22d6ce3a7188032b0d19251159fbd Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 15:34:44 +0200 Subject: * apt/package.py: Introduce Version.{uri,uris,fetch_binary()} --- apt/package.py | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++----- debian/changelog | 2 + 2 files changed, 109 insertions(+), 9 deletions(-) diff --git a/apt/package.py b/apt/package.py index 37cd33fb..595cf8ec 100644 --- a/apt/package.py +++ b/apt/package.py @@ -41,6 +41,17 @@ def _(string): return gettext.dgettext("python-apt", string) +def _file_is_same(path, size, md5): + """Return True if the file is the same.""" + if (os.path.exists(path) and os.path.getsize(path) == size and + apt_pkg.md5sum(open(path)) == md5): + return True + + +class FetchError(Exception): + """Raised when a file could not be fetched.""" + + class BaseDependency(object): """A single dependency. @@ -338,10 +349,87 @@ class Version(object): origins.append(Origin(self.package, verFileIter)) return origins - def fetch_source(self): - """Get the source code of a package""" + @property + def filename(self): + """Return the path to the file inside the archive.""" + return self._records.FileName + + @property + def md5(self): + """Return the md5sum of the binary.""" + return self._records.MD5Hash + + @property + def sha1(self): + """Return the sha1sum of the binary.""" + return self._records.SHA1Hash + + @property + def sha256(self): + """Return the sha1sum of the binary.""" + return self._records.SHA256Hash + + def _uris(self): + """Return an iterator over all available urls.""" + for (packagefile, index) in self._cand.FileList: + indexfile = self.package._pcache._list.FindIndex(packagefile) + if indexfile: + yield indexfile.ArchiveURI(self._records.FileName) + + @property + def uris(self): + """Return a list of all available uris for the binary.""" + return list(self._uris()) + + @property + def uri(self): + """Return a single URI for the binary.""" + return self._uris().next() + + def fetch_binary(self, destdir='', progress=None): + """Fetch the binary version of the package. + + The parameter 'destdir' specifies the directory where the package will + be fetched to. + + The parameter 'progress' may refer to an apt.progress.FetchProgress() + object. If not specified or None, apt.progress.TextFetchProgress() is + used. + """ + base = os.path.basename(self._records.FileName) + destfile = os.path.join(destdir, base) + if _file_is_same(destfile, self.size, self._records.MD5Hash): + print 'Ignoring already existing file:', destfile + return + acq = apt_pkg.GetAcquire(progress or apt.progress.TextFetchProgress()) + apt_pkg.GetPkgAcqFile(acq, self.uri, self._records.MD5Hash, self.size, + base, destFile=destfile) + acq.Run() + for item in acq.Items: + if item.Status != item.StatDone: + raise FetchError("The item %r could not be fetched: %s" % + (item.DestFile, item.ErrorText)) + return os.path.abspath(destfile) + + def fetch_source(self, destdir="", progress=None, unpack=True): + """Get the source code of a package. + + The parameter 'destdir' specifies the directory where the source will + be fetched to. + + The parameter 'progress' may refer to an apt.progress.FetchProgress() + object. If not specified or None, apt.progress.TextFetchProgress() is + used. + + The parameter 'unpack' describes whether the source should be unpacked + (True) or not (False). By default, it is unpacked. + + If 'unpack' is True, the path to the extracted directory is returned. + Otherwise, the path to the .dsc file is returned. + """ src = apt_pkg.GetPkgSrcRecords() - acq = apt_pkg.GetAcquire(apt.progress.TextFetchProgress()) + acq = apt_pkg.GetAcquire(progress or apt.progress.TextFetchProgress()) + dsc = None src.Lookup(self.package.name) try: @@ -351,23 +439,33 @@ class Version(object): raise ValueError("No source for %r" % self) for md5, size, path, type in src.Files: base = os.path.basename(path) + destfile = os.path.join(destdir, base) if type == 'dsc': - dsc = base + dsc = destfile if os.path.exists(base) and os.path.getsize(base) == size: fobj = open(base) try: if apt_pkg.md5sum(fobj) == md5: - print 'Ignoring already existing file', base + print 'Ignoring already existing file:', destfile continue finally: fobj.close() apt_pkg.GetPkgAcqFile(acq, src.Index.ArchiveURI(path), md5, size, - base) + base, destFile=destfile) acq.Run() - outdir = src.Package + '-' + apt_pkg.UpstreamVersion(src.Version) - subprocess.check_call(["dpkg-source", "-x", dsc, outdir]) - return os.path.abspath(outdir) + for item in acq.Items: + if item.Status != item.StatDone: + raise FetchError("The item %r could not be fetched: %s" % + (item.DestFile, item.ErrorText)) + + if unpack: + outdir = src.Package + '-' + apt_pkg.UpstreamVersion(src.Version) + outdir = os.path.join(destdir, outdir) + subprocess.check_call(["dpkg-source", "-x", dsc, outdir]) + return os.path.abspath(outdir) + else: + return os.path.abspath(dsc) class Package(object): diff --git a/debian/changelog b/debian/changelog index 3244d439..0015319c 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,8 @@ python-apt (0.7.10~exp1) experimental; urgency=low * Build-Depend on python-debian, use it to get version number from changelog * Depend on libjs-jquery, and remove internal copy + * apt/package.py: + - Introduce Version.{uri,uris,fetch_binary()} -- Julian Andres Klode Wed, 01 Apr 2009 15:24:29 +0200 -- cgit v1.2.3 From 376f7b202b67393c68e7aa7a219a5d6b02b914d1 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 15:42:01 +0200 Subject: Remove mdz from Uploaders (Closes: #521477), add myself. --- debian/changelog | 3 ++- debian/control | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 3dc359c7..36ffc2b4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ python-apt (0.7.10~exp1) experimental; urgency=low * Depend on libjs-jquery, and remove internal copy * apt/package.py: - Introduce Version.{uri,uris,fetch_binary()} + * Remove mdz from Uploaders (Closes: #521477), add myself. -- Julian Andres Klode Wed, 01 Apr 2009 15:24:29 +0200 @@ -31,7 +32,7 @@ python-apt (0.7.9) unstable; urgency=low - add Recommends to iso-codes (for iso_3166.xml) * apt/package.py: - make sure to set the defaulttimeout back to the - original value (in getChangelog(), LP: #314212) + original value (in getChangelog(), LP: #314212) Closes: #513315 * apt/cache.py: - when setting a alternative rootdir, read the diff --git a/debian/control b/debian/control index 6e0acd94..d0fbfdfa 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: python-apt Section: python Priority: optional Maintainer: APT Development Team -Uploaders: Matt Zimmerman , Michael Vogt +Uploaders: Michael Vogt , Julian Andres Klode Standards-Version: 3.7.2.2 XS-Python-Version: all Build-Depends: apt-utils, -- cgit v1.2.3 From e945bab415a4b61b9ee00ad11d02c0b583f073b5 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 15:43:15 +0200 Subject: debian/control: Add ${misc:Depends} to python-apt-dbg dependencies. --- debian/control | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/control b/debian/control index d0fbfdfa..47557615 100644 --- a/debian/control +++ b/debian/control @@ -43,7 +43,8 @@ Description: Python interface to libapt-pkg Package: python-apt-dbg Priority: extra Architecture: any -Depends: python-dbg, python-apt (= ${Source-Version}), ${shlibs:Depends} +Depends: python-dbg, python-apt (= ${Source-Version}), ${shlibs:Depends}, + ${misc:Depends} Description: Python interface to libapt-pkg (debug extension) The apt_pkg Python interface will provide full access to the internal libapt-pkg structures allowing Python programs to easily perform a -- cgit v1.2.3 From aa0e9335d3861a934eef359894f7d0d1b6164bec Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 15:44:33 +0200 Subject: debian/control: Remove useless Priority: optional in python-apt, move python-apt-dbg to debug section. --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 47557615..5ce48bd1 100644 --- a/debian/control +++ b/debian/control @@ -23,7 +23,6 @@ Architecture: any Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, lsb-release, libjs-jquery Recommends: iso-codes -Priority: optional Provides: ${python:Provides} Suggests: python-apt-dbg, python-gtk2, python-vte XB-Python-Version: ${python:Versions} @@ -43,6 +42,7 @@ Description: Python interface to libapt-pkg Package: python-apt-dbg Priority: extra Architecture: any +Section: debug Depends: python-dbg, python-apt (= ${Source-Version}), ${shlibs:Depends}, ${misc:Depends} Description: Python interface to libapt-pkg (debug extension) -- cgit v1.2.3 From 14bf76bdb50dc8ee450776ca1525e7c25a4a608e Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 16:24:59 +0200 Subject: * debian/control: Standards-Version, ${binary:Version}. - Update Standards-Version to 3.8.1 - Use ${binary:Version} instead of ${Source-Version} --- debian/changelog | 5 ++++- debian/control | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/debian/changelog b/debian/changelog index 36ffc2b4..f51944f9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,7 +4,10 @@ python-apt (0.7.10~exp1) experimental; urgency=low * Depend on libjs-jquery, and remove internal copy * apt/package.py: - Introduce Version.{uri,uris,fetch_binary()} - * Remove mdz from Uploaders (Closes: #521477), add myself. + * debian/control: + - Remove mdz from Uploaders (Closes: #521477), add myself. + - Update Standards-Version to 3.8.1 + - Use ${binary:Version} instead of ${Source-Version} -- Julian Andres Klode Wed, 01 Apr 2009 15:24:29 +0200 diff --git a/debian/control b/debian/control index 5ce48bd1..9afd50e0 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Section: python Priority: optional Maintainer: APT Development Team Uploaders: Michael Vogt , Julian Andres Klode -Standards-Version: 3.7.2.2 +Standards-Version: 3.8.1 XS-Python-Version: all Build-Depends: apt-utils, cdbs, @@ -43,7 +43,7 @@ Package: python-apt-dbg Priority: extra Architecture: any Section: debug -Depends: python-dbg, python-apt (= ${Source-Version}), ${shlibs:Depends}, +Depends: python-dbg, python-apt (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} Description: Python interface to libapt-pkg (debug extension) The apt_pkg Python interface will provide full access to the internal -- cgit v1.2.3 From 312b5ca7acbe74bc73acc2b710628ea2a8ad83cc Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 16:27:15 +0200 Subject: * Copyright updates: debian/copyright, etc. - debian/copyright: Switch to machine-interpretable copyright - apt/*.py: Fix the copyright years and comments. --- apt/__init__.py | 18 +++++++++++++++ apt/cache.py | 2 +- apt/cdrom.py | 2 +- apt/debfile.py | 31 ++++++++++++------------- apt/package.py | 2 +- apt/progress/__init__.py | 4 ++-- apt/progress/gtk2.py | 2 +- aptsources/distinfo.py | 10 ++++---- aptsources/distro.py | 4 ++-- aptsources/sourceslist.py | 12 +++++----- debian/changelog | 1 + debian/copyright | 58 ++++++++++++++++++++++++++++++++++++++++++----- 12 files changed, 103 insertions(+), 43 deletions(-) diff --git a/apt/__init__.py b/apt/__init__.py index e3cfacbe..ae2abbf2 100644 --- a/apt/__init__.py +++ b/apt/__init__.py @@ -1,3 +1,21 @@ +# Copyright (c) 2005-2009 Canonical +# +# Author: Michael Vogt +# +# 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 the core of apt_pkg import apt_pkg import sys diff --git a/apt/cache.py b/apt/cache.py index a9430d6b..cc425ccb 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -1,6 +1,6 @@ # cache.py - apt cache abstraction # -# Copyright (c) 2005 Canonical +# Copyright (c) 2005-2009 Canonical # # Author: Michael Vogt # diff --git a/apt/cdrom.py b/apt/cdrom.py index 61250fc4..b52762ad 100644 --- a/apt/cdrom.py +++ b/apt/cdrom.py @@ -1,6 +1,6 @@ # cdrom.py - CDROM handling # -# Copyright (c) 2005 Canonical +# Copyright (c) 2005-2009 Canonical # Copyright (c) 2009 Julian Andres Klode # # Author: Michael Vogt diff --git a/apt/debfile.py b/apt/debfile.py index c550d766..0406a250 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -1,24 +1,21 @@ -# Copyright (c) 2005-2007 Canonical +# Copyright (c) 2005-2009 Canonical # -# AUTHOR: -# Michael Vogt +# Author: Michael Vogt # -# This file is part of GDebi +# 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. # -# GDebi 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. -# -# GDebi 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 GDebi; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# 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 """Classes for working with locally available Debian packages.""" from gettext import gettext as _ import os diff --git a/apt/package.py b/apt/package.py index 595cf8ec..9afe1674 100644 --- a/apt/package.py +++ b/apt/package.py @@ -1,6 +1,6 @@ # package.py - apt package abstraction # -# Copyright (c) 2005 Canonical +# Copyright (c) 2005-2009 Canonical # # Author: Michael Vogt # diff --git a/apt/progress/__init__.py b/apt/progress/__init__.py index 51eb2426..769942ce 100644 --- a/apt/progress/__init__.py +++ b/apt/progress/__init__.py @@ -1,6 +1,6 @@ -# Progress.py - progress reporting classes +# progress.py - progress reporting classes # -# Copyright (c) 2005 Canonical +# Copyright (c) 2005-2009 Canonical # # Author: Michael Vogt # diff --git a/apt/progress/gtk2.py b/apt/progress/gtk2.py index 435265d4..f872e34f 100644 --- a/apt/progress/gtk2.py +++ b/apt/progress/gtk2.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2004-2005 Canonical +# Copyright (c) 2004-2009 Canonical # # Authors: Michael Vogt # Sebastian Heinlein diff --git a/aptsources/distinfo.py b/aptsources/distinfo.py index 59fa7e02..ce44e48b 100644 --- a/aptsources/distinfo.py +++ b/aptsources/distinfo.py @@ -1,12 +1,10 @@ -#!/usr/bin/env python -# # distinfo.py - provide meta information for distro repositories # -# Copyright (c) 2005 Gustavo Noronha Silva -# 2006-2007 Sebastian Heinlein +# Copyright (c) 2005 Gustavo Noronha Silva +# Copyright (c) 2006-2007 Sebastian Heinlein # -# Author: Gustavo Noronha Silva -# Sebastian Heinlein +# Authors: Gustavo Noronha Silva +# Sebastian Heinlein # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as diff --git a/aptsources/distro.py b/aptsources/distro.py index d81c6e4a..bbb8ba50 100644 --- a/aptsources/distro.py +++ b/aptsources/distro.py @@ -1,7 +1,7 @@ # distro.py - Provide a distro abstraction of the sources.list # -# Copyright (c) 2004-2007 Canonical Ltd. -# 2006-2007 Sebastian Heinlein +# Copyright (c) 2004-2009 Canonical Ltd. +# Copyright (c) 2006-2007 Sebastian Heinlein # # Authors: Sebastian Heinlein # Michael Vogt diff --git a/aptsources/sourceslist.py b/aptsources/sourceslist.py index b1f00446..1dfd870f 100644 --- a/aptsources/sourceslist.py +++ b/aptsources/sourceslist.py @@ -1,12 +1,12 @@ # aptsource.py - Provide an abstraction of the sources.list # -# Copyright (c) 2004-2007 Canonical Ltd. -# 2004 Michiel Sikkes -# 2006-2007 Sebastian Heinlein +# Copyright (c) 2004-2009 Canonical Ltd. +# Copyright (c) 2004 Michiel Sikkes +# Copyright (c) 2006-2007 Sebastian Heinlein # -# Author: Michiel Sikkes -# Michael Vogt -# Sebastian Heinlein +# Authors: Michiel Sikkes +# Michael Vogt +# Sebastian Heinlein # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as diff --git a/debian/changelog b/debian/changelog index f51944f9..91ce7304 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,7 @@ python-apt (0.7.10~exp1) experimental; urgency=low - Remove mdz from Uploaders (Closes: #521477), add myself. - Update Standards-Version to 3.8.1 - Use ${binary:Version} instead of ${Source-Version} + * debian/copyright: Switch to machine-interpretable copyright -- Julian Andres Klode Wed, 01 Apr 2009 15:24:29 +0200 diff --git a/debian/copyright b/debian/copyright index f8463185..8599328a 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,7 +1,53 @@ -APT is free software; you can redistribute them and/or modify them 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. +Format-Specification: http://wiki.debian.org/Proposals/CopyrightFormat?action=recall&rev=443 -On Debian systems, a copy of the GNU General Public License can be -found in /usr/share/common-licenses/GPL. +Files: * +Copyright: © 2004-2009 Canonical Ltd. +License: GPL-2+ + +Files: aptsources/*.py +Copyright: © 2004-2009 Canonical Ltd. +Copyright: © 2005 Gustavo Noronha Silva +Copyright: © 2006-2007 Sebastian Heinlein +License: GPL-2+ + +Files: doc/source/* +Copyright: © 2009 Julian Andres Klode +License: GPL-2+ + +Files: utils/get_*.py +Copyright: © 2006 Free Software Foundation Europe +License: GPL-2+ + +Files: po/* +Copyright: © 2006 Canonical Ltd, and Rosetta Contributors 2006 +License: GPL-2+ + +Files: po/de.po +Copyright: © 2005 Michiel Sikkes +License: GPL-2+ + +Files: po/en_CA.po +Copyright: © 2005 Adam Weinberger and the GNOME Foundation +License: GPL-2+ + +Files: po/fi.po +Copyright: © 2005-2006 Timo Jyrinki +License: GPL-2+ + +Files: po/fr.po +Copyright: © 2007 Hugues NAULET +License: GPL-2+ + +Files: po/hu.po, po/lt.po, po/pt.po, po/ro.po, po/rw.po, po/sv.po, po/uk.po, + po/zh_HK.po +Copyright: © 2005-2006 Free Software Foundation +License: GPL-2+ + +License: GPL-2+ + APT is free software; you can redistribute them and/or modify them 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. + . + On Debian systems, a copy of the GNU General Public License can be + found in /usr/share/common-licenses/GPL-2. -- cgit v1.2.3 From 192a186f6613f02e0fcef12da11412ec6001ed8c Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 17:11:16 +0200 Subject: * Fix documentation building - doc/source/conf.py: Only include directories for current python version. - debian/control: Build-Depend on python-gtk2, python-vte. - setup.py: If pygtk can not be imported, do not build the documentation. --- debian/changelog | 4 ++++ debian/control | 4 +++- doc/source/conf.py | 6 +++++- setup.py | 5 +++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 91ce7304..4bc94036 100644 --- a/debian/changelog +++ b/debian/changelog @@ -9,6 +9,10 @@ python-apt (0.7.10~exp1) experimental; urgency=low - Update Standards-Version to 3.8.1 - Use ${binary:Version} instead of ${Source-Version} * debian/copyright: Switch to machine-interpretable copyright + * Fix documentation building + - doc/source/conf.py: Only include directories for current python version. + - debian/control: Build-Depend on python-gtk2, python-vte. + - setup.py: If pygtk can not be imported, do not build the documentation. -- Julian Andres Klode Wed, 01 Apr 2009 15:24:29 +0200 diff --git a/debian/control b/debian/control index 9afd50e0..c06611e2 100644 --- a/debian/control +++ b/debian/control @@ -14,7 +14,9 @@ Build-Depends: apt-utils, python-central (>= 0.5), python-debian, python-distutils-extra (>= 1.9.0), - python-sphinx (>= 0.5) + python-gtk2, + python-sphinx (>= 0.5), + python-vte Vcs-Bzr: http://bzr.debian.org/apt/python-apt/debian-sid Vcs-Browser: http://bzr.debian.org/loggerhead/apt/python-apt/debian-sid/changes diff --git a/doc/source/conf.py b/doc/source/conf.py index 17fe6a23..40154a6f 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -23,9 +23,13 @@ import sys # absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) sys.path.insert(0, os.path.abspath('../..')) + +# Find the path to the built apt_pkg and apt_inst extensions if os.path.exists("../../build"): + version = '.'.join(str(x) for x in sys.version_info[:2]) for dirname in os.listdir('../../build'): - sys.path.insert(0, os.path.abspath('../../build/' + dirname)) + if version in dirname: + sys.path.insert(0, os.path.abspath('../../build/' + dirname)) # General configuration # --------------------- diff --git a/setup.py b/setup.py index 1c266ce7..3d378050 100755 --- a/setup.py +++ b/setup.py @@ -75,6 +75,11 @@ setup(name="python-apt", if len(sys.argv) > 1 and sys.argv[1] == "build": import sphinx + try: + import pygtk + except ImportError: + print >> sys.stderr, 'E: python-gtk2 is required to build documentation.' + sys.exit(0) sphinx.main(["sphinx", "-b", "html", "-d", "build/doc/doctrees", os.path.abspath("doc/source"), "build/doc/html"]) sphinx.main(["sphinx", "-b", "text", "-d", "build/doc/doctrees", -- cgit v1.2.3 From e3bdb73667560fcf662b8f1b5252b6e268d95e59 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 17:24:55 +0200 Subject: Set distribution to unstable, and close #521532 in the changelog --- debian/changelog | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index 4bc94036..4ef0b1f7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,7 +1,7 @@ -python-apt (0.7.10~exp1) experimental; urgency=low +python-apt (0.7.10) unstable; urgency=low * Build-Depend on python-debian, use it to get version number from changelog - * Depend on libjs-jquery, and remove internal copy + * Depend on libjs-jquery, and remove internal copy (Closes: #521532) * apt/package.py: - Introduce Version.{uri,uris,fetch_binary()} * debian/control: -- cgit v1.2.3 From 0447f65d8f2497d2b0ee3b27c772873dfc9c1248 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 17:36:38 +0200 Subject: Breaks: debdelta (<< 0.28) to avoid more problems due to the internal API changes from 0.7.9. --- debian/changelog | 2 ++ debian/control | 1 + 2 files changed, 3 insertions(+) diff --git a/debian/changelog b/debian/changelog index 4ef0b1f7..a4db252f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -13,6 +13,8 @@ python-apt (0.7.10) unstable; urgency=low - doc/source/conf.py: Only include directories for current python version. - debian/control: Build-Depend on python-gtk2, python-vte. - setup.py: If pygtk can not be imported, do not build the documentation. + * Breaks: debdelta (<< 0.28) to avoid more problems due to the internal + API changes from 0.7.9. -- Julian Andres Klode Wed, 01 Apr 2009 15:24:29 +0200 diff --git a/debian/control b/debian/control index c06611e2..e50518ae 100644 --- a/debian/control +++ b/debian/control @@ -25,6 +25,7 @@ Architecture: any Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, lsb-release, libjs-jquery Recommends: iso-codes +Breaks: debdelta (<< 0.28) Provides: ${python:Provides} Suggests: python-apt-dbg, python-gtk2, python-vte XB-Python-Version: ${python:Versions} -- cgit v1.2.3 From b05b23dc822c0cc93446cb67d18b73105248928c Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 17:37:30 +0200 Subject: Fix spelling error: python -> Python --- debian/changelog | 1 + debian/control | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index a4db252f..f254200d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,7 @@ python-apt (0.7.10) unstable; urgency=low - Remove mdz from Uploaders (Closes: #521477), add myself. - Update Standards-Version to 3.8.1 - Use ${binary:Version} instead of ${Source-Version} + - Fix spelling error: python -> Python * debian/copyright: Switch to machine-interpretable copyright * Fix documentation building - doc/source/conf.py: Only include directories for current python version. diff --git a/debian/control b/debian/control index e50518ae..8943ae20 100644 --- a/debian/control +++ b/debian/control @@ -53,4 +53,4 @@ Description: Python interface to libapt-pkg (debug extension) libapt-pkg structures allowing Python programs to easily perform a variety of functions. . - This package contains the extension built for the python debug interpreter. + This package contains the extension built for the Python debug interpreter. -- cgit v1.2.3 From b2d0d968e0aa3e3211b1a697c02117b7c09fb384 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 1 Apr 2009 17:40:12 +0200 Subject: Fix Breaks 0.28 => 0.28~, so it works for backports as well. --- debian/changelog | 2 +- debian/control | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/debian/changelog b/debian/changelog index f254200d..04d6a5d5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -14,7 +14,7 @@ python-apt (0.7.10) unstable; urgency=low - doc/source/conf.py: Only include directories for current python version. - debian/control: Build-Depend on python-gtk2, python-vte. - setup.py: If pygtk can not be imported, do not build the documentation. - * Breaks: debdelta (<< 0.28) to avoid more problems due to the internal + * Breaks: debdelta (<< 0.28~) to avoid more problems due to the internal API changes from 0.7.9. -- Julian Andres Klode Wed, 01 Apr 2009 15:24:29 +0200 diff --git a/debian/control b/debian/control index 8943ae20..4c7b542f 100644 --- a/debian/control +++ b/debian/control @@ -25,7 +25,7 @@ Architecture: any Depends: ${python:Depends}, ${shlibs:Depends}, ${misc:Depends}, lsb-release, libjs-jquery Recommends: iso-codes -Breaks: debdelta (<< 0.28) +Breaks: debdelta (<< 0.28~) Provides: ${python:Provides} Suggests: python-apt-dbg, python-gtk2, python-vte XB-Python-Version: ${python:Versions} -- cgit v1.2.3 From f4ad2eba9cb8a84903691d6f31b5b90e07fb5ae3 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 10 Apr 2009 17:51:01 +0200 Subject: Fix FTBFS with python-debian (>= 0.1.13) on Python 2.4 by not using it to get a version number in setup.py (Closes: #523473) --- debian/changelog | 7 +++++++ setup.py | 16 ++-------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/debian/changelog b/debian/changelog index 04d6a5d5..7f4a0203 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +python-apt (0.7.10.1) unstable; urgency=low + + * Fix FTBFS with python-debian (>= 0.1.13) on Python 2.4 by not using it to + get a version number in setup.py (Closes: #523473) + + -- Julian Andres Klode Fri, 10 Apr 2009 15:27:28 +0200 + python-apt (0.7.10) unstable; urgency=low * Build-Depend on python-debian, use it to get version number from changelog diff --git a/setup.py b/setup.py index 3d378050..2fd29953 100755 --- a/setup.py +++ b/setup.py @@ -10,18 +10,6 @@ from distutils.sysconfig import parse_makefile from DistUtilsExtra.command import build_extra, build_i18n -class FakeDebianSupportModule(object): - """Work around the python-apt dependency of debian_support.""" - - class Version(object): - """Empty class.""" - -sys.modules['debian_bundle.debian_support'] = FakeDebianSupportModule - -from debian_bundle.changelog import Changelog - - - # The apt_pkg module files = map(lambda source: "python/"+source, parse_makefile("python/makefile")["APT_PKG_SRC"].split()) @@ -58,7 +46,6 @@ if len(sys.argv) > 1 and sys.argv[1] == "clean" and '-a' in sys.argv: print "Not removing", dirname, "because it does not exist" setup(name="python-apt", - version=Changelog(open('debian/changelog')).full_version, description="Python bindings for APT", author="APT Development Team", author_email="deity@lists.debian.org", @@ -78,7 +65,8 @@ if len(sys.argv) > 1 and sys.argv[1] == "build": try: import pygtk except ImportError: - print >> sys.stderr, 'E: python-gtk2 is required to build documentation.' + print >> sys.stderr, ('W: Not building documentation because python-' + 'gtk2 is not available at the moment.') sys.exit(0) sphinx.main(["sphinx", "-b", "html", "-d", "build/doc/doctrees", os.path.abspath("doc/source"), "build/doc/html"]) -- cgit v1.2.3 From 5e5eb8e3d1942fe3a184c72811ee149b301a37b0 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 10 Apr 2009 17:53:08 +0200 Subject: * apt/package.py(Package.candidateRecord): Fix missing 'd' in 'record' --- apt/package.py | 2 +- debian/changelog | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apt/package.py b/apt/package.py index 9afe1674..008aebae 100644 --- a/apt/package.py +++ b/apt/package.py @@ -610,7 +610,7 @@ class Package(object): @DeprecatedProperty def candidateRecord(self): """Return the Record of the candidate version of the package.""" - return self.candidate.recor + return self.candidate.record @DeprecatedProperty def installedRecord(self): diff --git a/debian/changelog b/debian/changelog index 7f4a0203..a899b479 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,8 +2,10 @@ python-apt (0.7.10.1) unstable; urgency=low * Fix FTBFS with python-debian (>= 0.1.13) on Python 2.4 by not using it to get a version number in setup.py (Closes: #523473) + * apt/package.py: + - (Package.candidateRecord): Fix missing 'd' in 'record' - -- Julian Andres Klode Fri, 10 Apr 2009 15:27:28 +0200 + -- Julian Andres Klode Fri, 10 Apr 2009 17:51:07 +0200 python-apt (0.7.10) unstable; urgency=low -- cgit v1.2.3 From d7e542cd8973684d110c0512a49981e672df23e1 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 10 Apr 2009 17:56:15 +0200 Subject: * apt/package.py(DeprecatedProperty.__get__): Only warn when used on objects. This makes it easier to use e.g. pydoc,sphinx,pychecker, which use inspect the classes and therefore also have to access the properties. --- apt/package.py | 9 +++++---- debian/changelog | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/apt/package.py b/apt/package.py index 008aebae..00f563e4 100644 --- a/apt/package.py +++ b/apt/package.py @@ -99,10 +99,11 @@ class DeprecatedProperty(property): self.__doc__ = ':Deprecated: ' + (doc or fget.__doc__ or '') def __get__(self, obj, type=None): - warnings.warn("Accessed deprecated property %s.%s, please see the " - "Version class for alternatives." % - ((obj.__class__.__name__ or type.__name__), - self.fget.func_name), DeprecationWarning, 2) + if obj is not None: + warnings.warn("Accessed deprecated property %s.%s, please see the " + "Version class for alternatives." % + ((obj.__class__.__name__ or type.__name__), + self.fget.func_name), DeprecationWarning, 2) return property.__get__(self, obj, type) diff --git a/debian/changelog b/debian/changelog index a899b479..eb2a6a30 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,8 @@ python-apt (0.7.10.1) unstable; urgency=low get a version number in setup.py (Closes: #523473) * apt/package.py: - (Package.candidateRecord): Fix missing 'd' in 'record' + - (DeprecatedProperty.__get__): Only warn when used on objects, this + makes it easier to use e.g. pydoc,sphinx,pychecker. -- Julian Andres Klode Fri, 10 Apr 2009 17:51:07 +0200 -- cgit v1.2.3 From 8e4f00f1b6349b55eebce3c9cccbcab7ab438a85 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 12 Apr 2009 19:07:25 +0200 Subject: apt/package.py: Handle cases where no candidate is available and one of the deprecated properties (e.g. candidateVersion) is requested. (Closes: #523801) --- apt/package.py | 28 +++++++++++++++------------- debian/changelog | 8 ++++++++ po/python-apt.pot | 30 +++++++++++++++--------------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/apt/package.py b/apt/package.py index 00f563e4..0e13957f 100644 --- a/apt/package.py +++ b/apt/package.py @@ -529,12 +529,12 @@ class Package(object): @DeprecatedProperty def candidateVersion(self): """Return the candidate version as string.""" - return self.candidate.version + return getattr(self.candidate, "version", None) @DeprecatedProperty def candidateDependencies(self): """Return a list of candidate dependencies.""" - return self.candidate.dependencies + return getattr(self.candidate, "dependencies", None) @DeprecatedProperty def installedDependencies(self): @@ -544,12 +544,12 @@ class Package(object): @DeprecatedProperty def architecture(self): """Return the Architecture of the package""" - return self.candidate.architecture + return getattr(self.candidate, "architecture", None) @DeprecatedProperty def candidateDownloadable(self): """Return True if the candidate is downloadable.""" - return self.candidate.downloadable + return getattr(self.candidate, "downloadable", None) @DeprecatedProperty def installedDownloadable(self): @@ -570,7 +570,7 @@ class Package(object): @DeprecatedProperty def homepage(self): """Return the homepage field as string.""" - return self.candidate.homepage + return getattr(self.candidate, "homepage", None) @property def section(self): @@ -580,7 +580,7 @@ class Package(object): @DeprecatedProperty def priority(self): """Return the priority (of the candidate version).""" - return self.candidate.priority + return getattr(self.candidate, "priority", None) @DeprecatedProperty def installedPriority(self): @@ -590,7 +590,7 @@ class Package(object): @DeprecatedProperty def summary(self): """Return the short description (one line summary).""" - return self.candidate.summary + return getattr(self.candidate, "summary", None) @DeprecatedProperty def description(self): @@ -601,17 +601,17 @@ class Package(object): See http://www.debian.org/doc/debian-policy/ch-controlfields.html for more information. """ - return self.candidate.description + return getattr(self.candidate, "description", None) @DeprecatedProperty def rawDescription(self): """return the long description (raw).""" - return self.candidate.raw_description + return getattr(self.candidate, "raw_description", None) @DeprecatedProperty def candidateRecord(self): """Return the Record of the candidate version of the package.""" - return self.candidate.record + return getattr(self.candidate, "record", None) @DeprecatedProperty def installedRecord(self): @@ -676,7 +676,7 @@ class Package(object): @DeprecatedProperty def packageSize(self): """Return the size of the candidate deb package.""" - return self.candidate.size + return getattr(self.candidate, "size", None) @DeprecatedProperty def installedPackageSize(self): @@ -686,7 +686,7 @@ class Package(object): @DeprecatedProperty def candidateInstalledSize(self): """Return the size of the candidate installed package.""" - return self.candidate.installed_size + return getattr(self.candidate, "installed_size", None) @DeprecatedProperty def installedSize(self): @@ -731,6 +731,8 @@ class Package(object): return self._changelog if uri is None: + if not self.candidate: + pass if self.candidate.origins[0].origin == "Debian": uri = "http://packages.debian.org/changelogs/pool" \ "/%(src_section)s/%(prefix)s/%(src_pkg)s" \ @@ -863,7 +865,7 @@ class Package(object): @DeprecatedProperty def candidateOrigin(self): """Return a list of Origin() objects for the candidate version.""" - return self.candidate.origins + return getattr(self.candidate, "origins", None) @property def versions(self): diff --git a/debian/changelog b/debian/changelog index eb2a6a30..20d2167a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +python-apt (0.7.10.2) unstable; urgency=low + + * apt/package.py: Handle cases where no candidate is available and + one of the deprecated properties (e.g. candidateVersion) is + requested. (Closes: #523801) + + -- Julian Andres Klode Sun, 12 Apr 2009 19:00:07 +0200 + python-apt (0.7.10.1) unstable; urgency=low * Fix FTBFS with python-debian (>= 0.1.13) on Python 2.4 by not using it to diff --git a/po/python-apt.pot b/po/python-apt.pot index 0de7caab..9c23c579 100644 --- a/po/python-apt.pot +++ b/po/python-apt.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-03-08 19:15+0100\n" +"POT-Creation-Date: 2009-04-12 19:07+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -354,16 +354,16 @@ msgstr "" msgid "Complete" msgstr "" -#: ../apt/package.py:266 +#: ../apt/package.py:278 #, python-format msgid "Invalid unicode in description for '%s' (%s). Please report." msgstr "" -#: ../apt/package.py:644 ../apt/package.py:748 +#: ../apt/package.py:745 ../apt/package.py:849 msgid "The list of changes is not available" msgstr "" -#: ../apt/package.py:752 +#: ../apt/package.py:853 #, python-format msgid "" "The list of changes is not available yet.\n" @@ -372,56 +372,56 @@ msgid "" "until the changes become available or try again later." msgstr "" -#: ../apt/package.py:758 +#: ../apt/package.py:859 msgid "" "Failed to download the list of changes. \n" "Please check your Internet connection." msgstr "" -#: ../apt/debfile.py:59 +#: ../apt/debfile.py:56 #, python-format msgid "This is not a valid DEB archive, missing '%s' member" msgstr "" -#: ../apt/debfile.py:84 +#: ../apt/debfile.py:81 #, python-format msgid "List of files for '%s'could not be read" msgstr "" -#: ../apt/debfile.py:152 +#: ../apt/debfile.py:149 #, python-format msgid "Dependency is not satisfiable: %s\n" msgstr "" -#: ../apt/debfile.py:176 +#: ../apt/debfile.py:173 #, python-format msgid "Conflicts with the installed package '%s'" msgstr "" -#: ../apt/debfile.py:322 +#: ../apt/debfile.py:319 #, python-format msgid "Wrong architecture '%s'" msgstr "" #. the deb is older than the installed -#: ../apt/debfile.py:328 +#: ../apt/debfile.py:325 msgid "A later version is already installed" msgstr "" -#: ../apt/debfile.py:348 +#: ../apt/debfile.py:345 msgid "Failed to satisfy all dependencies (broken cache)" msgstr "" -#: ../apt/debfile.py:379 +#: ../apt/debfile.py:376 #, python-format msgid "Cannot install '%s'" msgstr "" -#: ../apt/debfile.py:487 +#: ../apt/debfile.py:484 #, python-format msgid "Install Build-Dependencies for source package '%s' that builds %s\n" msgstr "" -#: ../apt/debfile.py:497 +#: ../apt/debfile.py:494 msgid "An essential package would be removed" msgstr "" -- cgit v1.2.3 From 3bbb577e8a47ed05041c2532531e0e263f821c2c Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 12 Apr 2009 19:10:48 +0200 Subject: setup.py, debian/rules: Support version in setup.py again by getting the value from the variable DEBVER (defined in debian/rules), falling back to None. --- debian/changelog | 3 +++ debian/rules | 1 + setup.py | 1 + 3 files changed, 5 insertions(+) diff --git a/debian/changelog b/debian/changelog index 20d2167a..d9258436 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,9 @@ python-apt (0.7.10.2) unstable; urgency=low * apt/package.py: Handle cases where no candidate is available and one of the deprecated properties (e.g. candidateVersion) is requested. (Closes: #523801) + * setup.py, debian/rules: Support version in setup.py again by getting + the value from the variable DEBVER (defined in debian/rules), falling + back to None. -- Julian Andres Klode Sun, 12 Apr 2009 19:00:07 +0200 diff --git a/debian/rules b/debian/rules index a2802ea7..6d709ecd 100755 --- a/debian/rules +++ b/debian/rules @@ -15,6 +15,7 @@ PKG=python-apt DEBVER=$(shell dpkg-parsechangelog |sed -n -e '/^Version:/s/^Version: //p') DEB_COMPRESS_EXCLUDE:=.html .js _static/* _sources/* _sources/*/* .inv DEB_BUILD_PROG:=debuild --preserve-envvar PATH --preserve-envvar CCACHE_DIR -us -uc $(DEB_BUILD_PROG_OPTS) +export DEBVER build/python-apt-dbg:: set -e; \ diff --git a/setup.py b/setup.py index 2fd29953..2afd0708 100755 --- a/setup.py +++ b/setup.py @@ -47,6 +47,7 @@ if len(sys.argv) > 1 and sys.argv[1] == "clean" and '-a' in sys.argv: setup(name="python-apt", description="Python bindings for APT", + version=os.environ.get('DEBVER'), author="APT Development Team", author_email="deity@lists.debian.org", ext_modules=[apt_pkg, apt_inst], -- cgit v1.2.3 From 23d29169c30b2f05a0c2943832a7cf7288ff5802 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 12 Apr 2009 19:55:55 +0200 Subject: apt/package.py: Handle cases where no candidate is available, by returning None in the candidate property. (Closes: #523801) --- apt/package.py | 4 +++- debian/changelog | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/apt/package.py b/apt/package.py index 0e13957f..ec88a456 100644 --- a/apt/package.py +++ b/apt/package.py @@ -491,7 +491,9 @@ class Package(object): """Return the candidate version of the package. :since: 0.7.9""" - return Version(self, self._pcache._depcache.GetCandidateVer(self._pkg)) + cand = self._pcache._depcache.GetCandidateVer(self._pkg) + if cand is not None: + return Version(self, cand) @property def installed(self): diff --git a/debian/changelog b/debian/changelog index d9258436..83b00150 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +python-apt (0.7.10.3) unstable; urgency=low + + * apt/package.py: Handle cases where no candidate is available, by returning + None in the candidate property. (Closes: #523801) + + -- Julian Andres Klode Sun, 12 Apr 2009 19:50:26 +0200 + python-apt (0.7.10.2) unstable; urgency=low * apt/package.py: Handle cases where no candidate is available and -- cgit v1.2.3