diff options
| author | Michael Vogt <egon@bottom> | 2006-07-26 16:59:37 +0200 |
|---|---|---|
| committer | Michael Vogt <egon@bottom> | 2006-07-26 16:59:37 +0200 |
| commit | 70c850f4910cfcb6a825c67f577d8bc554612044 (patch) | |
| tree | 5321c9aa207b8743c7cca63e2b7b05609fbcddf7 | |
| parent | f701fc174a88d8f2b418a032571ff40ed6fd56e6 (diff) | |
| parent | 6fc084d34105f336fdf090e2dd45e402e25cfc57 (diff) | |
| download | python-apt-70c850f4910cfcb6a825c67f577d8bc554612044.tar.gz | |
* merged from the auto-mark branch
39 files changed, 1521 insertions, 246 deletions
@@ -0,0 +1,4 @@ +* 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} diff --git a/apt/cache.py b/apt/cache.py index 973291c0..690510e3 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -21,8 +21,9 @@ import apt_pkg from apt import Package -from apt.progress import OpTextProgress -from UserDict import UserDict +import apt.progress +import os +import sys class Cache(object): """ Dictionary-like package cache @@ -30,10 +31,14 @@ class Cache(object): dictionary """ - def __init__(self, progress=None): + def __init__(self, progress=None, rootdir=None): self._callbacks = {} self.open(progress) + if rootdir: + apt_pkg.Config.Set("Dir", rootdir) + apt_pkg.Config.Set("Dir::State::status", rootdir + "/var/lib/dpkg/status") + def _runCallbacks(self, name): """ internal helper to run a callback """ if self._callbacks.has_key(name): @@ -48,6 +53,8 @@ class Cache(object): self._cache = apt_pkg.GetCache(progress) self._depcache = apt_pkg.GetDepCache(self._cache) self._records = apt_pkg.GetPkgRecords(self._cache) + self._list = apt_pkg.GetPkgSourceList() + self._list.ReadMainList() self._dict = {} # build the packages dict @@ -62,7 +69,8 @@ class Cache(object): # drop stuff with no versions (cruft) if len(pkg.VersionList) > 0: self._dict[pkg.Name] = Package(self._cache, self._depcache, - self._records, self, pkg) + self._records, self._list, + self, pkg) i += 1 if progress != None: @@ -79,11 +87,7 @@ class Cache(object): raise StopIteration def has_key(self, key): - try: - self._dict[key] - except KeyError: - return False - return True + return self._dict.has_key(key) def __len__(self): return len(self._dict) @@ -109,15 +113,102 @@ class Cache(object): self._depcache.Upgrade(distUpgrade) self.cachePostChange() - def update(self, fetchProgress=None, opProgress=None): - if(opProgress != None): - self._cache.Update(fetchProgress, opProgress); - else: - self._cache.Update(fetchProgress); + def _runFetcher(self, fetcher): + # do the actual fetching + res = fetcher.Run() + + # now check the result (this is the code from apt-get.cc) + failed = False + transient = False + errMsg = "" + for item in fetcher.Items: + if item.Status == item.StatDone: + continue + if item.StatIdle: + transient = True + continue + errMsg += "Failed to fetch %s %s\n" % (item.DescURI,item.ErrorText) + failed = True + + # we raise a exception if the download failed + if failed: + raise IOError, errMsg + return res + + def _fetchArchives(self, fetcher, pm): + """ fetch the needed archives """ + + # get lock + lockfile = apt_pkg.Config.FindDir("Dir::Cache::Archives") + "lock" + lock = apt_pkg.GetLock(lockfile) + if lock < 0: + raise IOError, "Failed to lock %s" % lockfile + + try: + # this may as well throw a SystemError exception + if not pm.GetArchives(fetcher, self._list, self._records): + return False + # now run the fetcher, throw exception if something fails to be + # fetched + return self._runFetcher(fetcher) + finally: + os.close(lock) + + def update(self, fetchProgress=None): + lockfile = apt_pkg.Config.FindDir("Dir::State::Lists") + "lock" + lock = apt_pkg.GetLock(lockfile) + if lock < 0: + raise IOError, "Failed to lock %s" % lockfile - def commit(self, fprogress, iprogress): + try: + if fetchProgress == None: + fetchProgress = apt.progress.FetchProgress() + fetcher = apt_pkg.GetAcquire(fetchProgress) + # this can throw a exception + self._list.GetIndexes(fetcher) + # now run the fetcher, throw exception if something fails to be + # fetched + if self._runFetcher(fetcher) == fetcher.ResultContinue: + return True + return False + finally: + os.close(lock) + + def installArchives(self, pm, installProgress): + installProgress.startUpdate() + res = installProgress.run(pm) + installProgress.finishUpdate() + return res + + def commit(self, fetchProgress=None, installProgress=None): """ Apply the marked changes to the cache """ - self._depcache.Commit(fprogress, iprogress) + # FIXME: + # use the new acquire/pkgmanager interface here, + # raise exceptions when a download or install fails + # and send proper error strings to the application. + # Current a failed download will just display "error" + # which is less than optimal! + + if fetchProgress == None: + fetchProgress = apt.progress.FetchProgress() + if installProgress == None: + installProgress = apt.progress.InstallProgress() + + pm = apt_pkg.GetPackageManager(self._depcache) + fetcher = apt_pkg.GetAcquire(fetchProgress) + while True: + # fetch archives first + res = self._fetchArchives(fetcher, pm) + + # then install + res = self.installArchives(pm, installProgress) + if res == pm.ResultCompleted: + break + if res == pm.ResultFailed: + raise SystemError, "installArchives() failed" + # reload the fetcher for media swaping + fetcher.Shutdown() + return (res == pm.ResultCompleted) # cache changes def cachePostChange(self): @@ -131,7 +222,7 @@ class Cache(object): def connect(self, name, callback): """ connect to a signal, currently only used for - cache_{post,pre}_changed """ + cache_{post,pre}_{changed,open} """ if not self._callbacks.has_key(name): self._callbacks[name] = [] self._callbacks[name].append(callback) @@ -177,11 +268,7 @@ class FilteredCache(object): return self._filtered.keys() def has_key(self, key): - try: - self._filtered[key] - except KeyError: - return False - return True + return self._filtered.has_key(key) def _reapplyFilter(self): " internal helper to refilter " @@ -228,7 +315,7 @@ def cache_post_changed(): if __name__ == "__main__": print "Cache self test" apt_pkg.init() - c = Cache(OpTextProgress()) + c = Cache(apt.progress.OpTextProgress()) c.connect("cache_pre_change", cache_pre_changed) c.connect("cache_post_change", cache_post_changed) print c.has_key("aptitude") @@ -246,6 +333,17 @@ if __name__ == "__main__": #print p.name x = p.name + + # see if fetching works + for d in ["/tmp/pytest", "/tmp/pytest/partial"]: + if not os.path.exists(d): + os.mkdir(d) + apt_pkg.Config.Set("Dir::Cache::Archives","/tmp/pytest") + pm = apt_pkg.GetPackageManager(c._depcache) + fetcher = apt_pkg.GetAcquire(apt.progress.TextFetchProgress()) + c._fetchArchives(fetcher, pm) + #sys.exit(1) + print "Testing filtered cache (argument is old cache)" f = FilteredCache(c) f.cache.connect("cache_pre_change", cache_pre_changed) diff --git a/apt/package.py b/apt/package.py index 9749da52..0d1145ea 100644 --- a/apt/package.py +++ b/apt/package.py @@ -19,18 +19,22 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA -import apt_pkg, string +import apt_pkg +import sys import random +import string + class Package(object): """ This class represents a package in the cache """ - def __init__(self, cache, depcache, records, pcache, pkgiter): + def __init__(self, cache, depcache, records, sourcelist, 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 pass @@ -45,14 +49,14 @@ class Package(object): # check if we found a version if ver == None: - print "No version for: %s (Candiate: %s)" % (self._pkg.Name, UseCandidate) + #print "No version for: %s (Candidate: %s)" % (self._pkg.Name, UseCandidate) return False if ver.FileList == None: print "No FileList for: %s " % self._pkg.Name() return False - file, index = ver.FileList.pop(0) - self._records.Lookup((file,index)) + f, index = ver.FileList.pop(0) + self._records.Lookup((f,index)) return True @@ -90,9 +94,29 @@ class Package(object): return None candidateVersion = property(candidateVersion) + def _downloadable(self, useCandidate=True): + """ helper, return if the version is downloadable """ + if useCandidate: + ver = self._depcache.GetCandidateVer(self._pkg) + else: + ver = self._pkg.CurrentVer + if ver == None: + return False + return ver.Downloadable + def candidateDownloadable(self): + " returns if the canidate is downloadable " + return self._downloadable(useCandidate=True) + candidateDownloadable = property(candidateDownloadable) + + def installedDownloadable(self): + " returns if the installed version is downloadable " + return self._downloadable(useCandidate=False) + installedDownloadable = property(installedDownloadable) + def sourcePackageName(self): """ Return the source package name as string """ - self._lookupRecord() + if not self._lookupRecord(): + return None src = self._records.SourcePkg if src != "": return src @@ -125,13 +149,15 @@ class Package(object): def summary(self): """ Return the short description (one line summary) """ - self._lookupRecord() + if not self._lookupRecord(): + return "" return self._records.ShortDesc summary = property(summary) def description(self, format=True): """ Return the formated long description """ - self._lookupRecord() + if not self._lookupRecord(): + return "" desc = "" for line in string.split(self._records.LongDesc, "\n"): tmp = string.strip(line) @@ -144,7 +170,8 @@ class Package(object): def rawDescription(self): """ return the long description (raw)""" - self._lookupRecord() + if not self._lookupRecord(): + return "" return self._records.LongDesc rawDescription = property(rawDescription) @@ -215,12 +242,33 @@ class Package(object): installedSize = property(installedSize) # canidate origin + class Origin: + def __init__(self, pkg, VerFileIter): + self.component = VerFileIter.Component + self.archive = VerFileIter.Archive + self.origin = VerFileIter.Origin + self.label = VerFileIter.Label + self.site = VerFileIter.Site + # check the trust + indexfile = pkg._list.FindIndex(VerFileIter) + if indexfile and indexfile.IsTrusted: + self.trusted = True + else: + self.trusted = False + def __repr__(self): + return "component: '%s' archive: '%s' origin: '%s' label: '%s' " \ + "site '%s' isTrusted: '%s'"% (self.component, self.archive, + self.origin, self.label, + self.site, self.trusted) + def candidateOrigin(self): ver = self._depcache.GetCandidateVer(self._pkg) - (VerFileIter,index) = ver.FileList.pop() - print len(VerFileIter) - print VerFileIter - return VerFileIter.Component + if not ver: + return None + origins = [] + for (verFileIter,index) in ver.FileList: + origins.append(self.Origin(self, verFileIter)) + return origins candidateOrigin = property(candidateOrigin) # depcache actions @@ -242,10 +290,12 @@ class Package(object): Fix.InstallProtect() Fix.Resolve() self._pcache.cachePostChange() - def markInstall(self, autoFix=True): - """ mark a package for install. Run the resolver if autoFix is set """ + def markInstall(self, autoFix=True, autoInst=True): + """ mark a package for install. Run the resolver if autoFix is set, + automatically install required dependencies if autoInst is set + """ self._pcache.cachePreChange() - self._depcache.MarkInstall(self._pkg) + self._depcache.MarkInstall(self._pkg, autoInst) # try to fix broken stuff if autoFix and self._depcache.BrokenCount > 0: fixer = apt_pkg.GetPkgProblemResolver(self._depcache) @@ -256,9 +306,10 @@ class Package(object): def markUpgrade(self): """ mark a package for upgrade """ if self.isUpgradable: - self.MarkInstall() - # FIXME: we may want to throw a exception here - sys.stderr.write("MarkUpgrade() called on a non-upgrable pkg") + self.markInstall() + else: + # FIXME: we may want to throw a exception here + sys.stderr.write("MarkUpgrade() called on a non-upgrable pkg: '%s'\n" %self._pkg.Name) def commit(self, fprogress, iprogress): """ commit the changes, need a FetchProgress and InstallProgress @@ -274,16 +325,18 @@ if __name__ == "__main__": cache = apt_pkg.GetCache() depcache = apt_pkg.GetDepCache(cache) records = apt_pkg.GetPkgRecords(cache) + sourcelist = apt_pkg.GetPkgSourceList() - iter = cache["apt-utils"] - pkg = Package(cache, depcache, records, None, iter) + pkgiter = cache["apt-utils"] + 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 "CandiateOrigin: %s" % pkg.candidateOrigin + print "CandidateDownloadable: %s" % pkg.candidateDownloadable + print "CandidateOrigins: %s" % pkg.candidateOrigin print "SourcePkg: %s " % pkg.sourcePackageName print "Section: %s " % pkg.section print "Summary: %s" % pkg.summary diff --git a/apt/progress.py b/apt/progress.py index 86cd6594..4119067c 100644 --- a/apt/progress.py +++ b/apt/progress.py @@ -19,9 +19,9 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA -import sys +import sys, apt_pkg, os, fcntl, string, re -class OpProgress: +class OpProgress(object): """ Abstract class to implement reporting on cache opening Subclass this class to implement simple Operation progress reporting """ @@ -62,6 +62,8 @@ class FetchProgress(object): dlIgnored : "Ignored"} def __init__(self): + self.eta = 0.0 + self.percent = 0.0 pass def start(self): @@ -104,7 +106,7 @@ class TextFetchProgress(FetchProgress): sys.stdout.flush() return True def stop(self): - print "\rDone " + print "\rDone downloading " def mediaChange(self, medium, drive): """ react to media change events """ res = True; @@ -115,7 +117,7 @@ class TextFetchProgress(FetchProgress): res = false; return res -class InstallProgress: +class DumbInstallProgress(object): """ Report the install progress Subclass this class to implement install progress reporting """ @@ -123,11 +125,85 @@ class InstallProgress: pass def startUpdate(self): pass + def run(self, pm): + return pm.DoInstall() def finishUpdate(self): pass def updateInterface(self): pass +class InstallProgress(DumbInstallProgress): + """ A 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) + (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 " + pass + def conffile(self,current,new): + " called when a conffile question from dpkg is detected " + pass + def statusChange(self, pkg, percent, status): + " called when the status changed " + pass + def updateInterface(self): + if self.statusfd != None: + 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 != 11: + print errstr + if self.read.endswith("\n"): + s = self.read + #print s + (status, pkg, percent, status_str) = string.split(s, ":") + #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.compile("\s*\'(.*)\'\s*\'(.*)\'.*").match(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 = string.strip(status_str) + self.read = "" + + def fork(self): + return os.fork() + def waitChild(self): + while True: + (pid, res) = os.waitpid(self.child_pid,os.WNOHANG) + if pid == self.child_pid: + break + self.updateInterface() + return os.WEXITSTATUS(res) + def run(self, pm): + pid = self.fork() + if pid == 0: + # child + res = pm.DoInstall(self.writefd) + sys.exit(res) + self.child_pid = pid + res = self.waitChild() + return res + class CdromProgress: """ Report the cdrom add progress Subclass this class to implement cdrom add progress reporting diff --git a/debian/changelog b/debian/changelog index a31244bb..d9b428bd 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,96 @@ +python-apt (0.6.19) unstable; urgency=low + + [ Michael Vogt ] + * doc/examples/print_uris.py: + - added a example to show how the indexfile.ArchiveURI() can be used + with binary packages + + [ Otavio Salvador ] + * apt/cache.py: + - fix commit doc string to also cite the open related callbacks + - allow change of rootdir for APT database loading + + -- + +python-apt (0.6.18) unstable; urgency=low + + * Non-maintainer upload. + * Update for the new Python policy. Closes: #373512 + + -- Raphael Hertzog <hertzog@debian.org> Sat, 17 Jun 2006 15:09:28 +0200 + +python-apt (0.6.17) unstable; urgency=low + + * apt/progress.py: + - initialize FetchProgress.eta with the correct type + - strip the staus str before passing it to InstallProgress.statusChanged() + - added InstallProgress.statusChange(pkg, percent, status) + - make DumbInstallProgress a new-style class + (thanks to kamion for the suggestions) + - fix various pychecker warnings + * apt/cache.py: + - return useful values on Cache.update() + - Release locks on failure (thanks to Colin Watson) + - fix various pychecker warnings + * apt/package.py: + - fix various pychecker warnings + - check if looupRecords succeeded + - fix bug in the return statement of _downloadable() + * apt/cache.py: + * python/srcrecords.cc: + - add "Restart" method + - don't run auto "Restart" before performing a Lookup + - fix the initalization (no need to pass a PkgCacheType to the records) + - added "Index" attribute + * python/indexfile.cc: + - added ArchiveURI() method + + -- Michael Vogt <mvo@debian.org> Mon, 8 May 2006 22:34:58 +0200 + +python-apt (0.6.16.2) unstable; urgency=low + + * Non-maintainer upload. + * debian/control: + + Replaces: python-apt (<< 0.6.11), instead of Conflicts which is not + correct here. (closes: #308586). + + -- Pierre Habouzit <madcoder@debian.org> Fri, 14 Apr 2006 19:30:51 +0200 + +python-apt (0.6.16.1) unstable; urgency=low + + * memleak fixed when pkgCache objects are deallocated + * typos fixed (thanks to Gustavo Franco) + * pkgRecords.Record added to get raw record data + * python/cache.cc: "key" in pkgCache::VerIterator.DependsList[key] is + no longer locale specific but always english + + -- Michael Vogt <mvo@debian.org> Wed, 22 Feb 2006 10:41:13 +0100 + +python-apt (0.6.16) unstable; urgency=low + + * added GetPkgAcqFile to queue individual file downloads with the + system (dosn't make use of the improved pkgAcqFile yet) + * added SourceList.GetIndexes() + * rewrote apt.cache.update() to use the improved aquire interface + * apt/ API change: apt.Package.candidateOrigin returns a list of origins + now instead of a single one + * apt_pkg.Cdrom.Add() returns a boolean now, CdromProgress has totalSteps + * added support for pkgIndexFile and added SourcesList.FindIndex() + * added "trusted" to the Origin class + + -- Michael Vogt <michael.vogt@ubuntu.com> Thu, 5 Jan 2006 00:56:36 +0100 + +python-apt (0.6.15) unstable; urgency=low + + * rewrote cache.Commit() and make it raise proper Exception if stuff + goes wrong + * fix a invalid return from cache.commit(), fail if a download failed + * apt.Package.candidateOrigin returns a class now + * added pkgAcquire, pkgPackageManager and a example (acquire.py) + * tightend build-dependencies for new apt and the c++ transition + + -- Michael Vogt <mvo@debian.org> Mon, 28 Nov 2005 23:48:37 +0100 + python-apt (0.6.14) unstable; urgency=low * doc/examples/build-deps.py: @@ -9,9 +102,9 @@ python-apt (0.6.14) unstable; urgency=low - always run "Restart" before performing a Lookup * export locking via: GetLock(),PkgSystem{Lock,UnLock} * apt/cache.py: - - add __iter__ + - added __iter__ to make "for pkg in apt.Cache:" stuff possible - -- Michael Vogt <michael.vogt@ubuntu.com> Tue, 20 Sep 2005 13:24:31 +0200 + -- Michael Vogt <mvo@debian.org> Wed, 9 Nov 2005 04:52:08 +0100 python-apt (0.6.13) unstable; urgency=low diff --git a/debian/compat b/debian/compat new file mode 100644 index 00000000..7813681f --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5
\ No newline at end of file diff --git a/debian/control b/debian/control index bfa67c67..f313dff5 100644 --- a/debian/control +++ b/debian/control @@ -3,43 +3,18 @@ Section: python Priority: optional Maintainer: APT Development Team <deity@lists.debian.org> Uploaders: Matt Zimmerman <mdz@debian.org>, Michael Vogt <mvo@debian.org> -Standards-Version: 3.6.1.1 -Build-Depends: debhelper (>= 4.2.28), libapt-pkg-dev (>= 0.6.40), apt-utils, python-dev, python2.4-dev, python2.3-dev +Standards-Version: 3.6.2.0 +XS-Python-Version: all +Build-Depends: debhelper (>= 5.0.37.1), libapt-pkg-dev (>= 0.6.40), apt-utils, python-all-dev, python-central Package: python-apt -Architecture: all -Depends: ${python:Depends} -Priority: optional -Description: Python interface to libapt-pkg - The apt-pkg Python interface will provide full access to the internal - libapt-pkg structures allowing Python programs to easily perform a - variety of functions, such as: - . - - Access to the APT configuration system - - Access to the APT package information database - - Parsing of Debian package control files, and other files with a - similar structure - -Package: python2.3-apt Architecture: any -Depends: python2.3, ${shlibs:Depends} -Conflicts: python-apt (<< 0.6.11) -Priority: optional -Description: Python interface to libapt-pkg - The apt-pkg Python interface will provide full access to the internal - libapt-pkg structures allowing Python programs to easily perform a - variety of functions, such as: - . - - Access to the APT configuration system - - Access to the APT package information database - - Parsing of Debian package control files, and other files with a - similar structure - -Package: python2.4-apt -Architecture: any -Depends: python2.4, ${shlibs:Depends} -Conflicts: python-apt (<< 0.6.11) +Depends: ${python:Depends} Priority: optional +Replaces: python2.3-apt (<< 0.6.18), python2.4-apt (<< 0.6.18) +Conflicts: python2.3-apt (<< 0.6.18), python2.4-apt (<< 0.6.18) +Provides: ${python:Provides} +XB-Python-Version: ${python:Versions} Description: Python interface to libapt-pkg The apt-pkg Python interface will provide full access to the internal libapt-pkg structures allowing Python programs to easily perform a diff --git a/debian/rules b/debian/rules index 0ab6fa27..ffd39a6f 100755 --- a/debian/rules +++ b/debian/rules @@ -6,16 +6,13 @@ # This has to be exported to make some magic below work. export DH_OPTIONS -# This is the debhelper compatibility version to use. -export DH_COMPAT=3 - DEBVER=$(shell dpkg-parsechangelog |sed -n -e '/^Version:/s/^Version: //p') DEB_BUILD_PROG:=debuild --preserve-envvar PATH --preserve-envvar CCACHE_DIR -us -uc $(DEB_BUILD_PROG_OPTS) # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 -PYTHON=python2.3 python2.4 +PYTHON=$(shell pyversions -r debian/control) build: build-stamp build-stamp: @@ -41,18 +38,6 @@ clean: # Build architecture-independent files here. binary-indep: DH_OPTIONS=-i binary-indep: build - dh_testdir - dh_testroot - dh_installdocs - dh_installexamples doc/examples/*.py - dh_installchangelogs - dh_compress - dh_fixperms - dh_installdeb - dh_python - dh_gencontrol - dh_md5sums - dh_builddeb # Build architecture-dependent files here. binary-arch: DH_OPTIONS=-a @@ -60,11 +45,11 @@ binary-arch: build dh_testdir dh_testroot dh_clean -k - + for PY in $(PYTHON); do \ - /usr/bin/$$PY setup.py install --prefix=`pwd`/debian/$${PY}-apt/usr; \ + /usr/bin/$$PY setup.py install --prefix=`pwd`/debian/python-apt/usr; \ done - + dh_installdocs dh_installchangelogs dh_strip @@ -72,6 +57,7 @@ binary-arch: build dh_fixperms dh_installdeb dh_shlibdeps + dh_pycentral dh_python dh_gencontrol dh_md5sums @@ -83,7 +69,7 @@ source diff: arch-build: rm -rf debian/arch-build mkdir -p debian/arch-build/python-apt-$(DEBVER) - baz inventory -s | xargs cp -a --parents --target=debian/arch-build/python-apt-$(DEBVER) + tar -c --exclude=arch-build --no-recursion -f - `bzr inventory` | (cd debian/arch-build/python-apt-$(DEBVER);tar xf -) (cd debian/arch-build/python-apt-$(DEBVER); $(DEB_BUILD_PROG)) binary: binary-indep binary-arch diff --git a/doc/examples/acquire.py b/doc/examples/acquire.py new file mode 100644 index 00000000..a0790c98 --- /dev/null +++ b/doc/examples/acquire.py @@ -0,0 +1,92 @@ +import apt +import apt_pkg +import os +import sys +import tempfile + +def get_file(fetcher, uri, destFile): + cwd = os.getcwd() + # create a temp dir + dir = tempfile.mkdtemp() + os.chdir(dir) + # get the file + af = apt_pkg.GetPkgAcqFile(fetcher, + uri=uri, + descr="sample descr") + res = fetcher.Run() + if res != fetcher.ResultContinue: + os.rmdir(dir) + os.chdir(cwd) + return False + filename = os.path.basename(uri) + os.rename(dir+"/"+filename,destFile) + # cleanup + os.rmdir(dir) + os.chdir(cwd) + return True + +apt_pkg.init() + +#apt_pkg.Config.Set("Debug::pkgDPkgPM","1"); +#apt_pkg.Config.Set("Debug::pkgPackageManager","1"); +#apt_pkg.Config.Set("Debug::pkgDPkgProgressReporting","1"); + +cache = apt_pkg.GetCache() +depcache = apt_pkg.GetDepCache(cache) + +recs = apt_pkg.GetPkgRecords(cache) +list = apt_pkg.GetPkgSourceList() +list.ReadMainList() + +# show the amount fetch needed for a dist-upgrade +depcache.Upgrade(True) +progress = apt.progress.TextFetchProgress() +fetcher = apt_pkg.GetAcquire(progress) +pm = apt_pkg.GetPackageManager(depcache) +pm.GetArchives(fetcher,list,recs) +print "%s (%s)" % (apt_pkg.SizeToStr(fetcher.FetchNeeded), fetcher.FetchNeeded) + +for pkg in cache.Packages: + depcache.MarkKeep(pkg) + +try: + os.mkdir("/tmp/pyapt-test") + os.mkdir("/tmp/pyapt-test/partial") +except OSError: + pass +apt_pkg.Config.Set("Dir::Cache::archives","/tmp/pyapt-test") + +pkg = cache["3ddesktop"] +depcache.MarkInstall(pkg) + +progress = apt.progress.TextFetchProgress() +fetcher = apt_pkg.GetAcquire(progress) +#fetcher = apt_pkg.GetAcquire() +pm = apt_pkg.GetPackageManager(depcache) + +print pm +print fetcher + +get_file(fetcher, "ftp://ftp.debian.org/debian/dists/README", "/tmp/lala") +sys.exit(1) + +pm.GetArchives(fetcher,list,recs) + +for item in fetcher.Items: + print item + if item.Status == item.StatError: + print "Some error ocured: '%s'" % item.ErrorText + if item.Complete == False: + print "No error, still nothing downloaded (%s)" % item.ErrorText + print + + +res = fetcher.Run() +print "fetcher.Run() returned: %s" % res + +print "now runing pm.DoInstall()" +res = pm.DoInstall(1) +print "pm.DoInstall() returned: %s"% res + + + diff --git a/doc/examples/action.py b/doc/examples/action.py index a794317a..adf26539 100644 --- a/doc/examples/action.py +++ b/doc/examples/action.py @@ -30,9 +30,6 @@ sys.exit(0) - - - iter = cache["base-config"] print "example package iter: %s" % iter diff --git a/doc/examples/all_deps.py b/doc/examples/all_deps.py new file mode 100644 index 00000000..f4f1741c --- /dev/null +++ b/doc/examples/all_deps.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python
+
+import sys
+import apt
+
+
+def dependencies(cache, pkg, deps, key="Depends"):
+ #print "pkg: %s (%s)" % (pkg.name, deps)
+ candver = cache._depcache.GetCandidateVer(pkg._pkg)
+ if candver == None:
+ return deps
+ dependslist = candver.DependsList
+ if dependslist.has_key(key):
+ for depVerList in dependslist[key]:
+ for dep in depVerList:
+ if cache.has_key(dep.TargetPkg.Name):
+ if pkg.name != dep.TargetPkg.Name and not dep.TargetPkg.Name in deps:
+ deps.add(dep.TargetPkg.Name)
+ dependencies(cache, cache[dep.TargetPkg.Name], deps, key)
+ return deps
+
+
+pkgname = sys.argv[1]
+c = apt.Cache()
+pkg = c[pkgname]
+
+deps = set()
+
+deps = dependencies(c,pkg, deps, "Depends")
+print " ".join(deps)
+
+preDeps = set()
+preDeps = dependencies(c,pkg, preDeps, "PreDepends")
+print " ".join(preDeps)
diff --git a/doc/examples/build-deps.py b/doc/examples/build-deps.py index b580f5de..65e35f3d 100755 --- a/doc/examples/build-deps.py +++ b/doc/examples/build-deps.py @@ -24,7 +24,7 @@ cache = apt_pkg.GetCache() depcache = apt_pkg.GetDepCache(cache) depcache.Init() records = apt_pkg.GetPkgRecords(cache) -srcrecords = apt_pkg.GetPkgSrcRecords(cache) +srcrecords = apt_pkg.GetPkgSrcRecords() # base package that we use for build-depends calculation if len(sys.argv) < 2: diff --git a/doc/examples/deb_inspect.py b/doc/examples/deb_inspect.py index 4173c196..0befd2bb 100755 --- a/doc/examples/deb_inspect.py +++ b/doc/examples/deb_inspect.py @@ -4,6 +4,7 @@ import apt_pkg import apt_inst import sys +import os.path def Callback(What,Name,Link,Mode,UID,GID,Size,MTime,Major,Minor): """ callback for debExtract """ @@ -35,5 +36,12 @@ if __name__ == "__main__": print apt_pkg.ParseDepends(depends) - - + print "extracting archive" + dir = "/tmp/deb" + os.mkdir(dir) + apt_inst.debExtractArchive(open(file),dir) + def visit(arg, dirname, names): + print "%s/" % dirname + for file in names: + print "\t%s" % file + os.path.walk(dir, visit, None) diff --git a/doc/examples/dependant-pkgs.py b/doc/examples/dependant-pkgs.py new file mode 100755 index 00000000..f36936a8 --- /dev/null +++ b/doc/examples/dependant-pkgs.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +import apt +import sys + +pkgs = set() +cache = apt.Cache() +for pkg in cache: + candver = cache._depcache.GetCandidateVer(pkg._pkg) + if candver == None: + continue + dependslist = candver.DependsList + for dep in dependslist.keys(): + # get the list of each dependency object + for depVerList in dependslist[dep]: + for z in depVerList: + # get all TargetVersions of + # the dependency object + for tpkg in z.AllTargets(): + if sys.argv[1] == tpkg.ParentPkg.Name: + pkgs.add(pkg.name) + +main = set() +universe = set() +for pkg in pkgs: + if "universe" in cache[pkg].section: + universe.add(cache[pkg].sourcePackageName) + else: + main.add(cache[pkg].sourcePackageName) + +print "main:" +print "\n".join(main) +print + +print "universe:" +print "\n".join(universe) diff --git a/doc/examples/gui-inst.py b/doc/examples/gui-inst.py index 38417e10..deb325fe 100755 --- a/doc/examples/gui-inst.py +++ b/doc/examples/gui-inst.py @@ -2,6 +2,7 @@ # example how to install in a custom terminal widget # see also gnome bug: #169201 +import apt import apt_pkg import sys, os, fcntl import copy @@ -13,6 +14,7 @@ pygtk.require('2.0') import gtk import vte import time +import posix from apt.progress import OpProgress, FetchProgress, InstallProgress @@ -36,10 +38,12 @@ class GuiFetchProgress(gtk.Window, FetchProgress): def stop(self): self.hide() def pulse(self): - self.label.set_text("Speed: %s/s" % apt_pkg.SizeToStr(self.currentCPS)) + FetchProgress.pulse(self) + self.label.set_text("Speed: %s/s" % apt_pkg.SizeToStr(self.currentCPS)) #self.progressbar.set_fraction(self.currentBytes/self.totalBytes) while gtk.events_pending(): gtk.main_iteration() + return True class TermInstallProgress(InstallProgress, gtk.Window): def __init__(self): @@ -50,11 +54,16 @@ class TermInstallProgress(InstallProgress, gtk.Window): self.add(box) self.term = vte.Terminal() self.term.show() + # check for the child + self.reaper = vte.reaper_get() + self.reaper.connect("child-exited",self.child_exited) + self.finished = False + box.pack_start(self.term) self.progressbar = gtk.ProgressBar() self.progressbar.show() box.pack_start(self.progressbar) - + (read, write) = os.pipe() self.writefd=write self.status = os.fdopen(read, "r") @@ -62,7 +71,12 @@ class TermInstallProgress(InstallProgress, gtk.Window): print "read-fd: %s" % self.status.fileno() print "write-fd: %s" % self.writefd self.read = "" - + + def child_exited(self,term, pid, status): + print "child_exited: %s %s %s %s" % (self,term,pid,status) + self.apt_status = posix.WEXITSTATUS(status) + self.finished = True + def startUpdate(self): print "start" self.show() @@ -84,29 +98,26 @@ class TermInstallProgress(InstallProgress, gtk.Window): self.read = "" while gtk.events_pending(): gtk.main_iteration() + def finishUpdate(self): sys.stdin.readline() - def fork(self): + def run(self, pm): print "fork" env = ["VTE_PTY_KEEP_FD=%s"%self.writefd] print env pid = self.term.forkpty(envv=env) + if pid == 0: + res = pm.DoInstall(self.writefd) + print res + sys.exit(res) print "After fork: %s " % pid - return pid - - -# init -apt_pkg.init() - -progress = OpProgress() -cache = apt_pkg.GetCache(progress) -print "Available packages: %s " % cache.PackageCount + while not self.finished: + self.updateInterface() + return self.apt_status +cache = apt.Cache() +print "Available packages: %s " % cache._cache.PackageCount -# get depcache -depcache = apt_pkg.GetDepCache(cache) -depcache.ReadPinFile() -depcache.Init(progress) # update the cache fprogress = GuiFetchProgress() @@ -125,15 +136,15 @@ while gtk.events_pending(): gtk.main_iteration() -iter = cache["3dchess"] -print "\n%s"%iter +pkg = cache["3dchess"] +print "\n%s"%pkg.name # install or remove, the importend thing is to keep us busy :) -if iter.CurrentVer == None: - depcache.MarkInstall(iter) +if pkg.isInstalled: + pkg.markDelete() else: - depcache.MarkDelete(iter) -depcache.Commit(fprogress, iprogress) + pkg.markInstall() +cache.commit(fprogress, iprogress) print "Exiting" sys.exit(0) diff --git a/doc/examples/indexfile.py b/doc/examples/indexfile.py new file mode 100644 index 00000000..d383fd61 --- /dev/null +++ b/doc/examples/indexfile.py @@ -0,0 +1,21 @@ + +import apt_pkg + +apt_pkg.init() + +sources = apt_pkg.GetPkgSourceList() +sources.ReadMainList() + +cache = apt_pkg.GetCache() +depcache = apt_pkg.GetDepCache(cache) +pkg = cache["libimlib2"] +cand = depcache.GetCandidateVer(pkg) +for (f,i) in cand.FileList: + index = sources.FindIndex(f) + print index + if index: + print index.Size + print index.IsTrusted + print index.Exists + print index.HasPackages + print index.ArchiveURI("some/path") diff --git a/doc/examples/inst.py b/doc/examples/inst.py index fe5ec8e3..0e91c28f 100644 --- a/doc/examples/inst.py +++ b/doc/examples/inst.py @@ -2,60 +2,48 @@ # example how to deal with the depcache import apt -import apt_pkg import sys, os import copy +import time -from progress import TextFetchProgress, TextInstallProgress -from apt.progress import OpTextProgress +from apt.progress import InstallProgress class TextInstallProgress(InstallProgress): def __init__(self): - InstallProgress.__init__(self) - self.status = None - def StartUpdate(self): - print "StartUpdate: %s" % self.statusfd - self.status = os.fdopen(self.statusfd, "r") - print self.status - def UpdateInterface(self): - if self.status != None: - s = self.status.readline() - if s: - print s - def FinishUpdate(self): - self.status.close() - -# init -apt_pkg.init() - -progress = OpTextProgress() -cache = apt_pkg.GetCache(progress) -print "Available packages: %s " % cache.PackageCount - -# get depcache -depcache = apt_pkg.GetDepCache(cache) -depcache.ReadPinFile() -depcache.Init(progress) - -# do something -fprogress = TextFetchProgress() + apt.progress.InstallProgress.__init__(self) + self.last = 0.0 + def updateInterface(self): + InstallProgress.updateInterface(self) + if self.last >= self.percent: + return + sys.stdout.write("\r[%s] %s\n" %(self.percent, self.status)) + sys.stdout.flush() + self.last = self.percent + def conffile(self,current,new): + print "conffile prompt: %s %s" % (current,new) + def error(self, errorstr): + print "got dpkg error: '%s'" % errorstr + +cache = apt.Cache(apt.progress.OpTextProgress()) + +fprogress = apt.progress.TextFetchProgress() iprogress = TextInstallProgress() -# can be used to set a custom fork method (like vte.Terminal.forkpty) -#iprogress.fork = os.fork - -iter = cache["base-config"] -print "\n%s"%iter +pkg = cache["test-package"] +pkg.markUpgrade() +cache.commit(fprogress,iprogress) +sys.exit(1) # install or remove, the importend thing is to keep us busy :) -if iter.CurrentVer == None: - depcache.MarkInstall(iter) +if pkg.isInstalled: + print "Going to delete %s" % pkg.name + pkg.markDelete() else: - depcache.MarkDelete(iter) -res = depcache.Commit(fprogress, iprogress) + print "Going to install %s" % pkg.name + pkg.markInstall() +res = cache.commit(fprogress, iprogress) print res -print "Exiting" sys.exit(0) diff --git a/doc/examples/print_uris.py b/doc/examples/print_uris.py new file mode 100755 index 00000000..c8a64223 --- /dev/null +++ b/doc/examples/print_uris.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# +# a example that prints the URIs of all upgradable packages +# + +import apt +import apt_pkg + + +cache = apt.Cache() +upgradable = filter(lambda p: p.isUpgradable, cache) + + +for pkg in upgradable: + pkg._lookupRecord(True) + path = apt_pkg.ParseSection(pkg._records.Record)["Filename"] + cand = pkg._depcache.GetCandidateVer(pkg._pkg) + for (packagefile,i) in cand.FileList: + indexfile = cache._list.FindIndex(packagefile) + if indexfile: + uri = indexfile.ArchiveURI(path) + print uri diff --git a/doc/examples/progress.py b/doc/examples/progress.py index d820fcb2..2723c382 100644 --- a/doc/examples/progress.py +++ b/doc/examples/progress.py @@ -44,12 +44,16 @@ class TextFetchProgress(apt.FetchProgress): class TextInstallProgress(apt.InstallProgress): def __init__(self): + apt.InstallProgress.__init__(self) pass def startUpdate(self): print "StartUpdate" def finishUpdate(self): print "FinishUpdate" + def statusChange(self, pkg, percent, status): + print "[%s] %s: %s" % (percent, pkg, status) def updateInterface(self): + apt.InstallProgress.updateInterface(self) # usefull to e.g. redraw a GUI time.sleep(0.1) @@ -70,3 +74,16 @@ class TextCdromProgress(apt.CdromProgress): print "Please insert cdrom and press <ENTER>" answer = sys.stdin.readline() return True + + +if __name__ == "__main__": + c = apt.Cache() + pkg = c["3dchess"] + if pkg.isInstalled: + pkg.markDelete() + else: + pkg.markInstall() + + res = c.commit(TextFetchProgress(), TextInstallProgress()) + + print res diff --git a/doc/examples/sources.py b/doc/examples/sources.py index 79514621..c12c6f15 100644 --- a/doc/examples/sources.py +++ b/doc/examples/sources.py @@ -4,6 +4,12 @@ import apt_pkg apt_pkg.init() +#cache = apt_pkg.GetCache() +#sources = apt_pkg.GetPkgSrcRecords(cache) + sources = apt_pkg.GetPkgSrcRecords() +sources.Restart() while sources.Lookup('hello'): print sources.Package, sources.Version, sources.Maintainer, sources.Section, `sources.Binaries` + print sources.Files + print sources.Index.ArchiveURI("") diff --git a/python/acquire.cc b/python/acquire.cc new file mode 100644 index 00000000..65f8f2d7 --- /dev/null +++ b/python/acquire.cc @@ -0,0 +1,274 @@ +// Description /*{{{*/ +// $Id: acquire.cc,v 1.1 2003/06/03 03:03:23 mvo Exp $ +/* ###################################################################### + + Acquire - Wrapper for the acquire code + + ##################################################################### */ + +#include "generic.h" +#include "apt_pkgmodule.h" +#include "progress.h" + +#include <apt-pkg/acquire-item.h> + +// pkgAcquire::Item +static PyObject *AcquireItemAttr(PyObject *Self,char *Name) +{ + pkgAcquire::ItemIterator &I = GetCpp<pkgAcquire::ItemIterator>(Self); + + if (strcmp("ID",Name) == 0) + return Py_BuildValue("i",(*I)->ID); + else if (strcmp("Status",Name) == 0) + return Py_BuildValue("i",(*I)->Status); + else if (strcmp("Complete",Name) == 0) + return Py_BuildValue("i",(*I)->Complete); + else if (strcmp("Local",Name) == 0) + return Py_BuildValue("i",(*I)->Local); + else if (strcmp("IsTrusted",Name) == 0) + return Py_BuildValue("i",(*I)->IsTrusted()); + else if (strcmp("FileSize",Name) == 0) + return Py_BuildValue("i",(*I)->FileSize); + else if (strcmp("ErrorText",Name) == 0) + return Safe_FromString((*I)->ErrorText.c_str()); + else if (strcmp("DestFile",Name) == 0) + return Safe_FromString((*I)->DestFile.c_str()); + else if (strcmp("DescURI",Name) == 0) + return Safe_FromString((*I)->DescURI().c_str()); + // constants + else if (strcmp("StatIdle",Name) == 0) + return Py_BuildValue("i", pkgAcquire::Item::StatIdle); + else if (strcmp("StatFetching",Name) == 0) + return Py_BuildValue("i", pkgAcquire::Item::StatFetching); + else if (strcmp("StatDone",Name) == 0) + return Py_BuildValue("i", pkgAcquire::Item::StatDone); + else if (strcmp("StatError",Name) == 0) + return Py_BuildValue("i", pkgAcquire::Item::StatError); + else if (strcmp("StatAuthError",Name) == 0) + return Py_BuildValue("i", pkgAcquire::Item::StatAuthError); + + + PyErr_SetString(PyExc_AttributeError,Name); + return 0; +} + + +static PyObject *AcquireItemRepr(PyObject *Self) +{ + pkgAcquire::ItemIterator &I = GetCpp<pkgAcquire::ItemIterator>(Self); + + char S[300]; + snprintf(S,sizeof(S),"<pkgAcquire::ItemIterator object: " + "Status: %i Complete: %i Local: %i IsTrusted: %i " + "FileSize: %i DestFile:'%s' " + "DescURI: '%s' ID:%i ErrorText: '%s'>", + (*I)->Status, (*I)->Complete, (*I)->Local, (*I)->IsTrusted(), + (*I)->FileSize, (*I)->DestFile.c_str(), (*I)->DescURI().c_str(), + (*I)->ID,(*I)->ErrorText.c_str()); + return PyString_FromString(S); +} + + +PyTypeObject AcquireItemType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgAcquire::ItemIterator", // tp_name + sizeof(CppOwnedPyObject<pkgAcquire::ItemIterator>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<pkgAcquire::ItemIterator>, // tp_dealloc + 0, // tp_print + AcquireItemAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + AcquireItemRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + + +static PyObject *PkgAcquireRun(PyObject *Self,PyObject *Args) +{ + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(Self); + + int pulseInterval = 500000; + if (PyArg_ParseTuple(Args, "|i", &pulseInterval) == 0) + return 0; + + pkgAcquire::RunResult run = fetcher->Run(pulseInterval); + + return HandleErrors(Py_BuildValue("i",run)); +} + +static PyObject *PkgAcquireShutdown(PyObject *Self,PyObject *Args) +{ + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(Self); + + if (PyArg_ParseTuple(Args, "") == 0) + return 0; + + fetcher->Shutdown(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyMethodDef PkgAcquireMethods[] = +{ + {"Run",PkgAcquireRun,METH_VARARGS,"Run the fetcher"}, + {"Shutdown",PkgAcquireShutdown, METH_VARARGS,"Shutdown the fetcher"}, + {} +}; + + +static PyObject *AcquireAttr(PyObject *Self,char *Name) +{ + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(Self); + + if(strcmp("TotalNeeded",Name) == 0) + return Py_BuildValue("d", fetcher->TotalNeeded()); + if(strcmp("FetchNeeded",Name) == 0) + return Py_BuildValue("d", fetcher->FetchNeeded()); + if(strcmp("PartialPresent",Name) == 0) + return Py_BuildValue("d", fetcher->PartialPresent()); + if(strcmp("Items",Name) == 0) + { + PyObject *List = PyList_New(0); + for (pkgAcquire::ItemIterator I = fetcher->ItemsBegin(); + I != fetcher->ItemsEnd(); I++) + { + PyObject *Obj; + Obj = CppOwnedPyObject_NEW<pkgAcquire::ItemIterator>(Self,&AcquireItemType,I); + PyList_Append(List,Obj); + Py_DECREF(Obj); + + } + return List; + } + // some constants + if(strcmp("ResultContinue",Name) == 0) + return Py_BuildValue("i", pkgAcquire::Continue); + if(strcmp("ResultFailed",Name) == 0) + return Py_BuildValue("i", pkgAcquire::Failed); + if(strcmp("ResultCancelled",Name) == 0) + return Py_BuildValue("i", pkgAcquire::Cancelled); + + return Py_FindMethod(PkgAcquireMethods,Self,Name); +} + + + + +PyTypeObject PkgAcquireType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "Acquire", // tp_name + sizeof(CppPyObject<pkgAcquire*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgAcquire*>, // tp_dealloc + 0, // tp_print + AcquireAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + +PyObject *GetAcquire(PyObject *Self,PyObject *Args) +{ + pkgAcquire *fetcher; + + PyObject *pyFetchProgressInst = NULL; + if (PyArg_ParseTuple(Args,"|O",&pyFetchProgressInst) == 0) + return 0; + + if (pyFetchProgressInst != NULL) { + // FIXME: memleak? + PyFetchProgress *progress = new PyFetchProgress(); + progress->setCallbackInst(pyFetchProgressInst); + fetcher = new pkgAcquire(progress); + } else { + fetcher = new pkgAcquire(); + } + + CppPyObject<pkgAcquire*> *FetcherObj = + CppPyObject_NEW<pkgAcquire*>(&PkgAcquireType, fetcher); + + return FetcherObj; +} + + + + + +// pkgAcquireFile + +static PyObject *AcquireFileAttr(PyObject *Self,char *Name) +{ + pkgAcqFile *acqFile = GetCpp<pkgAcqFile*>(Self); + + PyErr_SetString(PyExc_AttributeError,Name); + return 0; +} + + + + +PyTypeObject PkgAcquireFileType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgAcquireFile", // tp_name + sizeof(CppPyObject<pkgAcqFile*>),// tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgAcqFile*>, // tp_dealloc + 0, // tp_print + AcquireFileAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + +PyObject *GetPkgAcqFile(PyObject *Self, PyObject *Args, PyObject * kwds) +{ + PyObject *pyfetcher; + char *uri, *md5, *descr, *shortDescr, *destDir, *destFile; + int size = 0; + uri = md5 = descr = shortDescr = destDir = destFile = ""; + + char * kwlist[] = {"owner","uri", "md5", "size", "descr", "shortDescr", + NULL}; + + if (PyArg_ParseTupleAndKeywords(Args, kwds, "O!s|siss", kwlist, + &PkgAcquireType, &pyfetcher, &uri, &md5, + &size, &descr, &shortDescr) == 0) + return 0; + + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(pyfetcher); + pkgAcqFile *af = new pkgAcqFile(fetcher, // owner + uri, // uri + md5, // md5 + size, // size + descr, // descr + shortDescr); // short-desc + CppPyObject<pkgAcqFile*> *AcqFileObj = CppPyObject_NEW<pkgAcqFile*>(&PkgAcquireFileType); + AcqFileObj->Object = af; + + return AcqFileObj; +} + + + /*}}}*/ diff --git a/python/apt_instmodule.cc b/python/apt_instmodule.cc index 96bd029b..d672a40a 100644 --- a/python/apt_instmodule.cc +++ b/python/apt_instmodule.cc @@ -66,6 +66,43 @@ static PyObject *debExtractControl(PyObject *Self,PyObject *Args) } /*}}}*/ +// debExtractArchive - Exctract the archive /*{{{*/ +// --------------------------------------------------------------------- +static char *doc_debExtractArchive = +"debExtractArchve(File,rootdir) -> Bool\n" +"Extracts the Archive into the given root dir"; +static PyObject *debExtractArchive(PyObject *Self,PyObject *Args) +{ + char *Rootdir = NULL; + PyObject *File; + if (PyArg_ParseTuple(Args,"O!|s",&PyFile_Type,&File,&Rootdir) == 0) + return 0; + + // Subscope makes sure any clean up errors are properly handled. + bool res = false; + { + if(Rootdir != NULL) + { + chdir(Rootdir); + } + + // Open the file and associate the .deb + FileFd Fd(fileno(PyFile_AsFile(File)),false); + debDebFile Deb(Fd); + if (_error->PendingError() == true) + return HandleErrors(); + + // extracts relative to the current dir + pkgDirStream Extract; + res = Deb.ExtractArchive(Extract); + + if (res == false) + return HandleErrors(); + } + return HandleErrors(Py_BuildValue("b",res)); +} + /*}}}*/ + // initapt_inst - Core Module Initialization /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -73,6 +110,7 @@ static PyMethodDef methods[] = { // Stuff {"debExtractControl",debExtractControl,METH_VARARGS,doc_debExtractControl}, + {"debExtractArchive",debExtractArchive,METH_VARARGS,doc_debExtractArchive}, {"tarExtract",tarExtract,METH_VARARGS,doc_tarExtract}, {"debExtract",debExtract,METH_VARARGS,doc_debExtract}, diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc index ce337f0f..e73628c3 100644 --- a/python/apt_pkgmodule.cc +++ b/python/apt_pkgmodule.cc @@ -396,6 +396,13 @@ static PyMethodDef methods[] = // Cdrom {"GetCdrom",GetCdrom,METH_VARARGS,"GetCdrom() -> Cdrom"}, + // Acquire + {"GetAcquire",GetAcquire,METH_VARARGS,"GetAcquire() -> Acquire"}, + {"GetPkgAcqFile",(PyCFunction)GetPkgAcqFile,METH_KEYWORDS|METH_VARARGS,"GetPkgAcquireFile() -> pkgAcquireFile"}, + + // PkgManager + {"GetPackageManager",GetPkgManager,METH_VARARGS,"GetPackageManager() -> PackageManager"}, + {} }; diff --git a/python/apt_pkgmodule.h b/python/apt_pkgmodule.h index eefa6ca7..fe7dfe88 100644 --- a/python/apt_pkgmodule.h +++ b/python/apt_pkgmodule.h @@ -72,11 +72,27 @@ PyObject *GetPkgProblemResolver(PyObject *Self, PyObject *Args); extern PyTypeObject PkgCdromType; PyObject *GetCdrom(PyObject *Self,PyObject *Args); +// acquire +extern PyTypeObject PkgAcquireType; +PyObject *GetAcquire(PyObject *Self,PyObject *Args); +PyObject *GetPkgAcqFile(PyObject *Self, PyObject *Args, PyObject *kwds); + +// packagemanager +extern PyTypeObject PkgManagerType; +PyObject *GetPkgManager(PyObject *Self,PyObject *Args); + // PkgRecords Stuff extern PyTypeObject PkgRecordsType; PyObject *GetPkgRecords(PyObject *Self,PyObject *Args); PyObject *GetPkgSrcRecords(PyObject *Self,PyObject *Args); + +// pkgSourceList +extern PyTypeObject PkgSourceListType; PyObject *GetPkgSourceList(PyObject *Self,PyObject *Args); +// pkgSourceList +extern PyTypeObject PackageIndexFileType; + + #endif diff --git a/python/cache.cc b/python/cache.cc index 5c1760d4..174423c2 100644 --- a/python/cache.cc +++ b/python/cache.cc @@ -231,6 +231,17 @@ static PyObject *CacheMapOp(PyObject *Self,PyObject *Arg) return CppOwnedPyObject_NEW<pkgCache::PkgIterator>(Self,&PackageType,Pkg); } +// we need a special dealloc here to make sure that the CacheFile +// is closed before deallocation the cache (otherwise we have a bad) +// memory leak +void PkgCacheFileDealloc(PyObject *Self) +{ + PyObject *CacheFilePy = GetOwner<pkgCache*>(Self); + pkgCacheFile *CacheF = GetCpp<pkgCacheFile*>(CacheFilePy); + CacheF->Close(); + CppOwnedDealloc<pkgCache *>(Self); +} + static PyMappingMethods CacheMap = {0,CacheMapOp,0}; PyTypeObject PkgCacheType = { @@ -240,7 +251,7 @@ PyTypeObject PkgCacheType = sizeof(CppOwnedPyObject<pkgCache *>), // tp_basicsize 0, // tp_itemsize // Methods - CppOwnedDealloc<pkgCache *>, // tp_dealloc + PkgCacheFileDealloc, // tp_dealloc 0, // tp_print CacheAttr, // tp_getattr 0, // tp_setattr @@ -452,7 +463,17 @@ static PyObject *MakeDepends(PyObject *Owner,pkgCache::VerIterator &Ver, // Switch/create a new dict entry if (LastDepType != Start->Type || LastDep != 0) { - PyObject *Dep = PyString_FromString(Start.DepType()); + // must be in sync with pkgCache::DepType in libapt + // it sucks to have it here duplicated, but we get it + // translated from libapt and that is certainly not what + // we want in a programing interface + const char *Types[] = + { + "", "Depends","PreDepends","Suggests", + "Recommends","Conflicts","Replaces", + "Obsoletes" + }; + PyObject *Dep = PyString_FromString(Types[Start->Type]); LastDepType = Start->Type; LastDep = PyDict_GetItem(Dict,Dep); if (LastDep == 0) @@ -637,8 +658,6 @@ static PyObject *PackageFileAttr(PyObject *Self,char *Name) return Py_BuildValue("i",(File->Flags & pkgCache::Flag::NotAutomatic) != 0); else if (strcmp("ID",Name) == 0) return Py_BuildValue("i",File->ID); - /* mtime is really a cookie these days and has no meaning outside the - list handlers */ PyErr_SetString(PyExc_AttributeError,Name); return 0; diff --git a/python/cdrom.cc b/python/cdrom.cc index 13889b31..aca1be26 100644 --- a/python/cdrom.cc +++ b/python/cdrom.cc @@ -30,10 +30,9 @@ static PyObject *PkgCdromAdd(PyObject *Self,PyObject *Args) PyCdromProgress progress; progress.setCallbackInst(pyCdromProgressInst); - Struct.cdrom.Add(&progress); + bool res = Struct.cdrom.Add(&progress); - Py_INCREF(Py_None); - return HandleErrors(Py_None); + return HandleErrors(Py_BuildValue("b", res)); } static PyObject *PkgCdromIdent(PyObject *Self,PyObject *Args) @@ -69,7 +68,6 @@ static PyObject *CdromAttr(PyObject *Self,char *Name) { PkgCdromStruct &Struct = GetCpp<PkgCdromStruct>(Self); - return Py_FindMethod(PkgCdromMethods,Self,Name); } diff --git a/python/depcache.cc b/python/depcache.cc index c78d0077..60bbc1a4 100644 --- a/python/depcache.cc +++ b/python/depcache.cc @@ -116,17 +116,25 @@ static PyObject *PkgDepCacheCommit(PyObject *Self,PyObject *Args) bool Failed = false; for (pkgAcquire::ItemIterator I = Fetcher.ItemsBegin(); I != Fetcher.ItemsEnd(); I++) { + + //std::cout << "looking at: " << (*I)->DestFile + // << " status: " << (*I)->Status << std::endl; + if ((*I)->Status == pkgAcquire::Item::StatDone && (*I)->Complete == true) continue; if ((*I)->Status == pkgAcquire::Item::StatIdle) { + //std::cout << "transient failure" << std::endl; + Transient = true; - // Failed = true; + //Failed = true; continue; } + //std::cout << "something is wrong!" << std::endl; + _error->Warning(_("Failed to fetch %s %s\n"),(*I)->DescURI().c_str(), (*I)->ErrorText.c_str()); Failed = true; @@ -135,6 +143,7 @@ static PyObject *PkgDepCacheCommit(PyObject *Self,PyObject *Args) if (Transient == true && Failed == true) { _error->Error(_("--fix-missing and media swapping is not currently supported")); + Py_INCREF(Py_None); return HandleErrors(Py_None); } @@ -143,27 +152,33 @@ static PyObject *PkgDepCacheCommit(PyObject *Self,PyObject *Args) { //std::cerr << "Unable to correct missing packages." << std::endl; _error->Error("Aborting install."); + Py_INCREF(Py_None); return HandleErrors(Py_None); } - _system->UnLock(); + // fail if something else went wrong + //FIXME: make this more flexible, e.g. with a failedDl handler + if(Failed) + return Py_BuildValue("b", false); + _system->UnLock(true); pkgPackageManager::OrderResult Res = iprogress.Run(PM); - //FIXME: return usefull values here + //std::cout << "iprogress.Run() returned: " << (int)Res << std::endl; + if (Res == pkgPackageManager::Failed || _error->PendingError() == true) { - result = Py_BuildValue("b", false); - return result; + return HandleErrors(Py_BuildValue("b", false)); } if (Res == pkgPackageManager::Completed) { - result = Py_BuildValue("b", true); - return result; + //std::cout << "iprogress.Run() returned Completed " << std::endl; + return Py_BuildValue("b", true); } + //std::cout << "looping again, install unfinished" << std::endl; + // Reload the fetcher object and loop again for media swapping Fetcher.Shutdown(); if (PM->GetArchives(&Fetcher,&List,&Recs) == false) { - result = Py_BuildValue("b", false); - return result; + return Py_BuildValue("b", false); } _system->Lock(); } @@ -218,15 +233,30 @@ static PyObject *PkgDepCacheUpgrade(PyObject *Self,PyObject *Args) if (PyArg_ParseTuple(Args,"|b",&distUpgrade) == 0) return 0; + bool res; if(distUpgrade) - pkgDistUpgrade(*depcache); + res = pkgDistUpgrade(*depcache); else - pkgAllUpgrade(*depcache); + res = pkgAllUpgrade(*depcache); Py_INCREF(Py_None); - return HandleErrors(Py_None); + return HandleErrors(Py_BuildValue("b",res)); +} + +static PyObject *PkgDepCacheMinimizeUpgrade(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + bool res = pkgMinimizeUpgrade(*depcache); + + Py_INCREF(Py_None); + return HandleErrors(Py_BuildValue("b",res)); } + static PyObject *PkgDepCacheReadPinFile(PyObject *Self,PyObject *Args) { pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); @@ -249,14 +279,15 @@ static PyObject *PkgDepCacheReadPinFile(PyObject *Self,PyObject *Args) static PyObject *PkgDepCacheFixBroken(PyObject *Self,PyObject *Args) { pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); - + + bool res=true; if (PyArg_ParseTuple(Args,"") == 0) return 0; - pkgFixBroken(*depcache); + res &=pkgFixBroken(*depcache); + res &=pkgMinimizeUpgrade(*depcache); - Py_INCREF(Py_None); - return HandleErrors(Py_None); + return HandleErrors(Py_BuildValue("b",res)); } @@ -339,6 +370,20 @@ static PyObject *PkgDepCacheIsUpgradable(PyObject *Self,PyObject *Args) return HandleErrors(Py_BuildValue("b",state.Upgradable())); } +static PyObject *PkgDepCacheIsGarbage(PyObject *Self,PyObject *Args) +{ + pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); + + PyObject *PackageObj; + if (PyArg_ParseTuple(Args,"O!",&PackageType,&PackageObj) == 0) + return 0; + + pkgCache::PkgIterator &Pkg = GetCpp<pkgCache::PkgIterator>(PackageObj); + pkgDepCache::StateCache &state = (*depcache)[Pkg]; + + return HandleErrors(Py_BuildValue("b",state.Garbage)); +} + static PyObject *PkgDepCacheIsNowBroken(PyObject *Self,PyObject *Args) { pkgDepCache *depcache = GetCpp<pkgDepCache *>(Self); @@ -466,6 +511,7 @@ static PyMethodDef PkgDepCacheMethods[] = {"Upgrade",PkgDepCacheUpgrade,METH_VARARGS,"Perform Upgrade (optional boolean argument if dist-upgrade should be performed)"}, {"FixBroken",PkgDepCacheFixBroken,METH_VARARGS,"Fix broken packages"}, {"ReadPinFile",PkgDepCacheReadPinFile,METH_VARARGS,"Read the pin policy"}, + {"MinimizeUpgrade",PkgDepCacheMinimizeUpgrade, METH_VARARGS,"Go over the entire set of packages and try to keep each package marked for upgrade. If a conflict is generated then the package is restored."}, // Manipulators {"MarkKeep",PkgDepCacheMarkKeep,METH_VARARGS,"Mark package for keep"}, {"MarkDelete",PkgDepCacheMarkDelete,METH_VARARGS,"Mark package for delete (optional boolean argument if it should be purged)"}, @@ -475,6 +521,7 @@ static PyMethodDef PkgDepCacheMethods[] = {"IsUpgradable",PkgDepCacheIsUpgradable,METH_VARARGS,"Is pkg upgradable"}, {"IsNowBroken",PkgDepCacheIsNowBroken,METH_VARARGS,"Is pkg is now broken"}, {"IsInstBroken",PkgDepCacheIsInstBroken,METH_VARARGS,"Is pkg broken on the current install"}, + {"IsGarbage",PkgDepCacheIsGarbage,METH_VARARGS,"Is pkg garbage (mark-n-sweep)"}, {"MarkedInstall",PkgDepCacheMarkedInstall,METH_VARARGS,"Is pkg marked for install"}, {"MarkedUpgrade",PkgDepCacheMarkedUpgrade,METH_VARARGS,"Is pkg marked for upgrade"}, {"MarkedDelete",PkgDepCacheMarkedDelete,METH_VARARGS,"Is pkg marked for delete"}, diff --git a/python/indexfile.cc b/python/indexfile.cc new file mode 100644 index 00000000..ef6ffc8a --- /dev/null +++ b/python/indexfile.cc @@ -0,0 +1,92 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +// $Id: indexfile.cc,v 1.2 2003/12/26 17:04:22 mdz Exp $ +/* ###################################################################### + + pkgIndexFile - Wrapper for the pkgIndexFilefunctions + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include "generic.h" +#include "apt_pkgmodule.h" + +#include <apt-pkg/indexfile.h> + +#include <Python.h> + +static PyObject *PackageIndexFileArchiveURI(PyObject *Self,PyObject *Args) +{ + pkgIndexFile *File = GetCpp<pkgIndexFile*>(Self); + char *path; + + if (PyArg_ParseTuple(Args, "s",&path) == 0) + return 0; + + return HandleErrors(Safe_FromString(File->ArchiveURI(path).c_str())); +} + +static PyMethodDef PackageIndexFileMethods[] = +{ + {"ArchiveURI",PackageIndexFileArchiveURI,METH_VARARGS,"Returns the ArchiveURI"}, + {} +}; + + +static PyObject *PackageIndexFileAttr(PyObject *Self,char *Name) +{ + pkgIndexFile *File = GetCpp<pkgIndexFile*>(Self); + if (strcmp("Label",Name) == 0) + return Safe_FromString(File->GetType()->Label); + else if (strcmp("Describe",Name) == 0) + return Safe_FromString(File->Describe().c_str()); + else if (strcmp("Exists",Name) == 0) + return Py_BuildValue("i",(File->Exists())); + else if (strcmp("HasPackages",Name) == 0) + return Py_BuildValue("i",(File->HasPackages())); + else if (strcmp("Size",Name) == 0) + return Py_BuildValue("i",(File->Size())); + else if (strcmp("IsTrusted",Name) == 0) + return Py_BuildValue("i",(File->IsTrusted())); + + return Py_FindMethod(PackageIndexFileMethods,Self,Name); +} + +static PyObject *PackageIndexFileRepr(PyObject *Self) +{ + pkgIndexFile *File = GetCpp<pkgIndexFile*>(Self); + + char S[300]; + snprintf(S,sizeof(S),"<pkIndexFile object: " + "Label:'%s' Describe='%s' Exists='%i' " + "HasPackages='%i' Size='%i' " + "IsTrusted='%i' ArchiveURI='%s'>", + File->GetType()->Label, File->Describe().c_str(), File->Exists(), + File->HasPackages(), File->Size(), + File->IsTrusted(), File->ArchiveURI("").c_str()); + return PyString_FromString(S); +} + +PyTypeObject PackageIndexFileType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "pkgIndexFile", // tp_name + sizeof(CppOwnedPyObject<pkgIndexFile*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppOwnedDealloc<pkgIndexFile*>, // tp_dealloc + 0, // tp_print + PackageIndexFileAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + PackageIndexFileRepr, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + + + + diff --git a/python/makefile b/python/makefile index 16bfcd88..24ef3238 100644 --- a/python/makefile +++ b/python/makefile @@ -11,7 +11,8 @@ SLIBS = -lapt-pkg LIB_MAKES = apt-pkg/makefile APT_PKG_SRC = apt_pkgmodule.cc configuration.cc generic.cc tag.cc string.cc \ cache.cc pkgrecords.cc pkgsrcrecords.cc sourcelist.cc \ - depcache.cc progress.cc cdrom.cc + depcache.cc progress.cc cdrom.cc acquire.cc pkgmanager.cc \ + indexfile.cc SOURCE := $(APT_PKG_SRC) include $(PYTHON_H) progress.h diff --git a/python/pkgmanager.cc b/python/pkgmanager.cc new file mode 100644 index 00000000..bcd4c45b --- /dev/null +++ b/python/pkgmanager.cc @@ -0,0 +1,135 @@ +// Description /*{{{*/ +// $Id: acquire.cc,v 1.1 2003/06/03 03:03:23 mvo Exp $ +/* ###################################################################### + + PkgManager - Wrapper for the pkgPackageManager code + + ##################################################################### */ + +#include "generic.h" +#include "apt_pkgmodule.h" +#include "pkgrecords.h" + +#include <apt-pkg/packagemanager.h> +#include <apt-pkg/pkgsystem.h> +#include <apt-pkg/sourcelist.h> +#include <apt-pkg/error.h> +#include <apt-pkg/acquire.h> +#include <iostream> + + +static PyObject *PkgManagerGetArchives(PyObject *Self,PyObject *Args) +{ + pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + PyObject *fetcher, *list, *recs; + + if (PyArg_ParseTuple(Args, "O!O!O!", + &PkgAcquireType,&fetcher, + &PkgSourceListType, &list, + &PkgRecordsType, &recs) == 0) + return 0; + + pkgAcquire *s_fetcher = GetCpp<pkgAcquire*>(fetcher); + pkgSourceList *s_list = GetCpp<pkgSourceList*>(list); + PkgRecordsStruct &s_records = GetCpp<PkgRecordsStruct>(recs); + + bool res = pm->GetArchives(s_fetcher, s_list, + &s_records.Records); + + return HandleErrors(Py_BuildValue("b",res)); +} + +static PyObject *PkgManagerDoInstall(PyObject *Self,PyObject *Args) +{ + //PkgManagerStruct &Struct = GetCpp<PkgManagerStruct>(Self); + pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + int status_fd = -1; + + if (PyArg_ParseTuple(Args, "|i", &status_fd) == 0) + return 0; + + pkgPackageManager::OrderResult res = pm->DoInstall(status_fd); + + return HandleErrors(Py_BuildValue("i",res)); +} + +static PyObject *PkgManagerFixMissing(PyObject *Self,PyObject *Args) +{ + //PkgManagerStruct &Struct = GetCpp<PkgManagerStruct>(Self); + pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + + if (PyArg_ParseTuple(Args, "") == 0) + return 0; + + bool res = pm->FixMissing(); + + return HandleErrors(Py_BuildValue("b",res)); +} + +static PyMethodDef PkgManagerMethods[] = +{ + {"GetArchives",PkgManagerGetArchives,METH_VARARGS,"Load the selected archvies into the fetcher"}, + {"DoInstall",PkgManagerDoInstall,METH_VARARGS,"Do the actual install"}, + {"FixMissing",PkgManagerFixMissing,METH_VARARGS,"Fix the install if a pkg couldn't be downloaded"}, + {} +}; + + +static PyObject *PkgManagerAttr(PyObject *Self,char *Name) +{ + //PkgManagerStruct &Struct = GetCpp<PkgManagerStruct>(Self); + pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + + // some constants + if(strcmp("ResultCompleted",Name) == 0) + return Py_BuildValue("i", pkgPackageManager::Completed); + if(strcmp("ResultFailed",Name) == 0) + return Py_BuildValue("i", pkgPackageManager::Failed); + if(strcmp("ResultIncomplete",Name) == 0) + return Py_BuildValue("i", pkgPackageManager::Incomplete); + + return Py_FindMethod(PkgManagerMethods,Self,Name); +} + + +PyTypeObject PkgManagerType = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, // ob_size + "PackageManager", // tp_name + sizeof(CppPyObject<pkgPackageManager*>), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDealloc<pkgPackageManager*>, // tp_dealloc + 0, // tp_print + PkgManagerAttr, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash +}; + +#include <apt-pkg/init.h> +#include <apt-pkg/configuration.h> + +PyObject *GetPkgManager(PyObject *Self,PyObject *Args) +{ + PyObject *Owner; + if (PyArg_ParseTuple(Args,"O!",&PkgDepCacheType,&Owner) == 0) + return 0; + + pkgPackageManager *pm = _system->CreatePM(GetCpp<pkgDepCache*>(Owner)); + + CppPyObject<pkgPackageManager*> *PkgManagerObj = + CppPyObject_NEW<pkgPackageManager*>(&PkgManagerType,pm); + + return PkgManagerObj; +} + + + + + /*}}}*/ diff --git a/python/pkgrecords.cc b/python/pkgrecords.cc index 7f5aa0e2..ec78f554 100644 --- a/python/pkgrecords.cc +++ b/python/pkgrecords.cc @@ -10,20 +10,12 @@ // Include Files /*{{{*/ #include "generic.h" #include "apt_pkgmodule.h" +#include "pkgrecords.h" -#include <apt-pkg/pkgrecords.h> #include <Python.h> /*}}}*/ -struct PkgRecordsStruct -{ - pkgRecords Records; - pkgRecords::Parser *Last; - - PkgRecordsStruct(pkgCache *Cache) : Records(*Cache), Last(0) {}; - PkgRecordsStruct() : Records(*(pkgCache *)0) {abort();}; // G++ Bug.. -}; // PkgRecords Class /*{{{*/ // --------------------------------------------------------------------- @@ -54,7 +46,7 @@ static PyObject *PkgRecordsLookup(PyObject *Self,PyObject *Args) // always return true (to make it consistent with the pkgsrcrecords object return Py_BuildValue("i", 1); } - + static PyMethodDef PkgRecordsMethods[] = { {"Lookup",PkgRecordsLookup,METH_VARARGS,"Changes to a new package"}, @@ -81,6 +73,12 @@ static PyObject *PkgRecordsAttr(PyObject *Self,char *Name) return CppPyString(Struct.Last->LongDesc()); else if (strcmp("Name",Name) == 0) return CppPyString(Struct.Last->Name()); + else if (strcmp("Record", Name) == 0) + { + const char *start, *stop; + Struct.Last->GetRec(start, stop); + return PyString_FromStringAndSize(start,stop-start); + } } return Py_FindMethod(PkgRecordsMethods,Self,Name); diff --git a/python/pkgrecords.h b/python/pkgrecords.h new file mode 100644 index 00000000..78787eab --- /dev/null +++ b/python/pkgrecords.h @@ -0,0 +1,10 @@ +#include <apt-pkg/pkgrecords.h> + +struct PkgRecordsStruct +{ + pkgRecords Records; + pkgRecords::Parser *Last; + + PkgRecordsStruct(pkgCache *Cache) : Records(*Cache), Last(0) {}; + PkgRecordsStruct() : Records(*(pkgCache *)0) {abort();}; // G++ Bug.. +}; diff --git a/python/pkgsrcrecords.cc b/python/pkgsrcrecords.cc index 252810c7..5e04f5fc 100644 --- a/python/pkgsrcrecords.cc +++ b/python/pkgsrcrecords.cc @@ -43,7 +43,6 @@ static PyObject *PkgSrcRecordsLookup(PyObject *Self,PyObject *Args) if (PyArg_ParseTuple(Args,"s",&Name) == 0) return 0; - Struct.Records->Restart(); Struct.Last = Struct.Records->Find(Name, false); if (Struct.Last == 0) { Struct.Records->Restart(); @@ -54,9 +53,25 @@ static PyObject *PkgSrcRecordsLookup(PyObject *Self,PyObject *Args) return Py_BuildValue("i", 1); } +static char *doc_PkgSrcRecordsRestart = "Start Lookup from the begining"; +static PyObject *PkgSrcRecordsRestart(PyObject *Self,PyObject *Args) +{ + PkgSrcRecordsStruct &Struct = GetCpp<PkgSrcRecordsStruct>(Self); + + char *Name = 0; + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + Struct.Records->Restart(); + + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + static PyMethodDef PkgSrcRecordsMethods[] = { {"Lookup",PkgSrcRecordsLookup,METH_VARARGS,doc_PkgSrcRecordsLookup}, + {"Restart",PkgSrcRecordsRestart,METH_VARARGS,doc_PkgSrcRecordsRestart}, {} }; @@ -81,8 +96,10 @@ static PyObject *PkgSrcRecordsAttr(PyObject *Self,char *Name) *b != 0; ++b) PyList_Append(List, CppPyString(*b)); - return List; // todo + } else if (strcmp("Index",Name) == 0) { + const pkgIndexFile &tmp = Struct.Last->Index(); + return CppOwnedPyObject_NEW<pkgIndexFile*>(Self,&PackageIndexFileType, (pkgIndexFile*)&tmp); } else if (strcmp("Files",Name) == 0) { PyObject *List = PyList_New(0); @@ -126,10 +143,10 @@ PyTypeObject PkgSrcRecordsType = PyObject_HEAD_INIT(&PyType_Type) 0, // ob_size "pkgSrcRecords", // tp_name - sizeof(CppOwnedPyObject<PkgSrcRecordsStruct>), // tp_basicsize + sizeof(CppPyObject<PkgSrcRecordsStruct>), // tp_basicsize 0, // tp_itemsize // Methods - CppOwnedDealloc<PkgSrcRecordsStruct>, // tp_dealloc + CppDealloc<PkgSrcRecordsStruct>, // tp_dealloc 0, // tp_print PkgSrcRecordsAttr, // tp_getattr 0, // tp_setattr @@ -145,11 +162,17 @@ PyTypeObject PkgSrcRecordsType = PyObject *GetPkgSrcRecords(PyObject *Self,PyObject *Args) { +#if 0 PyObject *Owner; if (PyArg_ParseTuple(Args,"O!",&PkgCacheType,&Owner) == 0) return 0; return HandleErrors(CppOwnedPyObject_NEW<PkgSrcRecordsStruct>(Owner, &PkgSrcRecordsType)); +#endif + if (PyArg_ParseTuple(Args,"") == 0) + return 0; + + return HandleErrors(CppPyObject_NEW<PkgSrcRecordsStruct>(&PkgSrcRecordsType)); } diff --git a/python/progress.cc b/python/progress.cc index 12f9c7a8..f00058c9 100644 --- a/python/progress.cc +++ b/python/progress.cc @@ -218,7 +218,7 @@ pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm) // support custom fork methods if(PyObject_HasAttrString(callbackInst, "fork")) { PyObject *method = PyObject_GetAttrString(callbackInst, "fork"); - //std::cerr << "custom fork found" << std::endl; + std::cerr << "custom fork found" << std::endl; PyObject *arglist = Py_BuildValue("()"); PyObject *result = PyEval_CallObject(method, arglist); Py_DECREF(arglist); @@ -227,9 +227,11 @@ pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm) PyErr_Print(); return pkgPackageManager::Failed; } - if(!PyArg_Parse(result, "i", &child_id) ) + if(!PyArg_Parse(result, "i", &child_id) ) { std::cerr << "custom fork() result could not be parsed?"<< std::endl; - //std::cerr << "got: " << child_id << std::endl; + return pkgPackageManager::Failed; + } + std::cerr << "got pid: " << child_id << std::endl; } else { //std::cerr << "using build-in fork()" << std::endl; child_id = fork(); @@ -251,15 +253,39 @@ pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm) } else { res = pm->DoInstall(); } + //std::cout << "res: " << res << std::endl; _exit(res); } StartUpdate(); - while (waitpid(child_id, &ret, WNOHANG) == 0) - UpdateInterface(); - res = (pkgPackageManager::OrderResult) WEXITSTATUS(ret); + if(PyObject_HasAttrString(callbackInst, "waitChild")) { + PyObject *method = PyObject_GetAttrString(callbackInst, "waitChild"); + //std::cerr << "custom waitChild found" << std::endl; + PyObject *arglist = Py_BuildValue("(i)",child_id); + PyObject *result = PyEval_CallObject(method, arglist); + Py_DECREF(arglist); + if (result == NULL) { + std::cerr << "waitChild method invalid" << std::endl; + PyErr_Print(); + return pkgPackageManager::Failed; + } + int child_res; + if(!PyArg_Parse(result, "i", &res) ) { + std::cerr << "custom waitChild() result could not be parsed?"<< std::endl; + return pkgPackageManager::Failed; + } + //std::cerr << "got child_res: " << res << std::endl; + } else { + //std::cerr << "using build-in waitpid()" << std::endl; + + while (waitpid(child_id, &ret, WNOHANG) == 0) + UpdateInterface(); + + res = (pkgPackageManager::OrderResult) WEXITSTATUS(ret); + //std::cerr << "build-in waitpid() got: " << res << std::endl; + } FinishUpdate(); @@ -273,6 +299,10 @@ pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm) void PyCdromProgress::Update(string text, int current) { PyObject *arglist = Py_BuildValue("(si)", text.c_str(), current); + + PyObject *o = Py_BuildValue("i", totalSteps); + PyObject_SetAttrString(callbackInst, "totalSteps", o); + RunSimpleCallback("update", arglist); } diff --git a/python/sourcelist.cc b/python/sourcelist.cc index e2343e1c..16e51368 100644 --- a/python/sourcelist.cc +++ b/python/sourcelist.cc @@ -3,7 +3,7 @@ // $Id: sourcelist.cc,v 1.2 2003/12/26 17:04:22 mdz Exp $ /* ###################################################################### - Package Records - Wrapper for the package records functions + SourcesList - Wrapper for the SourcesList functions ##################################################################### */ /*}}}*/ @@ -16,10 +16,7 @@ #include <Python.h> /*}}}*/ -struct PkgSourceListStruct -{ - pkgSourceList List; -}; + // PkgsourceList Class /*{{{*/ // --------------------------------------------------------------------- @@ -27,23 +24,57 @@ struct PkgSourceListStruct static char *doc_PkgSourceListFindIndex = "xxx"; static PyObject *PkgSourceListFindIndex(PyObject *Self,PyObject *Args) { - PkgSourceListStruct &Struct = GetCpp<PkgSourceListStruct>(Self); - return Py_BuildValue("i", 1); + pkgSourceList *list = GetCpp<pkgSourceList*>(Self); + PyObject *pyPkgFileIter; + PyObject *pyPkgIndexFile; + + if (PyArg_ParseTuple(Args, "O!", &PackageFileType,&pyPkgFileIter) == 0) + return 0; + + pkgCache::PkgFileIterator &i = GetCpp<pkgCache::PkgFileIterator>(pyPkgFileIter); + pkgIndexFile *index; + if(list->FindIndex(i, index)) + { + pyPkgIndexFile = CppOwnedPyObject_NEW<pkgIndexFile*>(pyPkgFileIter,&PackageIndexFileType,index); + return pyPkgIndexFile; + } + + //&PackageIndexFileType,&pyPkgIndexFile) + + Py_INCREF(Py_None); + return Py_None; } static char *doc_PkgSourceListReadMainList = "xxx"; static PyObject *PkgSourceListReadMainList(PyObject *Self,PyObject *Args) { - PkgSourceListStruct &Struct = GetCpp<PkgSourceListStruct>(Self); - Struct.List.ReadMainList(); + pkgSourceList *list = GetCpp<pkgSourceList*>(Self); + bool res = list->ReadMainList(); - return Py_None; + return HandleErrors(Py_BuildValue("b",res)); +} + +static char *doc_PkgSourceListGetIndexes = "Load the indexes into the fetcher"; +static PyObject *PkgSourceListGetIndexes(PyObject *Self,PyObject *Args) +{ + pkgSourceList *list = GetCpp<pkgSourceList*>(Self); + + PyObject *pyFetcher; + + if (PyArg_ParseTuple(Args, "O!",&PkgAcquireType,&pyFetcher) == 0) + return 0; + + pkgAcquire *fetcher = GetCpp<pkgAcquire*>(pyFetcher); + bool res = list->GetIndexes(fetcher); + + return HandleErrors(Py_BuildValue("b",res)); } static PyMethodDef PkgSourceListMethods[] = { {"FindIndex",PkgSourceListFindIndex,METH_VARARGS,doc_PkgSourceListFindIndex}, {"ReadMainList",PkgSourceListReadMainList,METH_VARARGS,doc_PkgSourceListReadMainList}, + {"GetIndexes",PkgSourceListGetIndexes,METH_VARARGS,doc_PkgSourceListReadMainList}, {} }; @@ -56,10 +87,10 @@ PyTypeObject PkgSourceListType = PyObject_HEAD_INIT(&PyType_Type) 0, // ob_size "pkgSourceList", // tp_name - sizeof(CppPyObject<PkgSourceListStruct>), // tp_basicsize + sizeof(CppPyObject<pkgSourceList*>), // tp_basicsize 0, // tp_itemsize // Methods - CppDealloc<PkgSourceListStruct>, // tp_dealloc + CppDealloc<pkgSourceList*>, // tp_dealloc 0, // tp_print PkgSourceListAttr, // tp_getattr 0, // tp_setattr @@ -73,6 +104,6 @@ PyTypeObject PkgSourceListType = PyObject *GetPkgSourceList(PyObject *Self,PyObject *Args) { - return CppPyObject_NEW<PkgSourceListStruct>(&PkgSourceListType); + return CppPyObject_NEW<pkgSourceList*>(&PkgSourceListType,new pkgSourceList()); } diff --git a/python/tar.cc b/python/tar.cc index 20fb1f5f..22c0327e 100644 --- a/python/tar.cc +++ b/python/tar.cc @@ -88,7 +88,7 @@ bool ProcessTar::DoItem(Item &Itm,int &Fd) // --------------------------------------------------------------------- /* */ char *doc_tarExtract = -"tarExtract(File,Func,Comp) -> None" +"tarExtract(File,Func,Comp) -> None\n" "The tar file referenced by the file object File, Func called for each\n" "Tar member. Comp must be the string \"gzip\" (gzip is automatically invoked) \n"; PyObject *tarExtract(PyObject *Self,PyObject *Args) @@ -128,7 +128,7 @@ PyObject *tarExtract(PyObject *Self,PyObject *Args) // --------------------------------------------------------------------- /* */ char *doc_debExtract = -"debExtract(File,Func,Chunk) -> None" +"debExtract(File,Func,Chunk) -> None\n" "The deb referenced by the file object File is examined. The AR member\n" "given by Chunk is treated as a tar.gz and fed through Func like\n" "tarExtract\n"; @@ -7,22 +7,18 @@ import string, glob # The apt_pkg module -files = string.split(parse_makefile("python/makefile")["APT_PKG_SRC"]); -for i in range(0,len(files)): - files[i] = "python/"+ files[i]; -apt_pkg = Extension("apt_pkg", files, - libraries=["apt-pkg"]); +files = map(lambda source: "python/"+source, + string.split(parse_makefile("python/makefile")["APT_PKG_SRC"])) +apt_pkg = Extension("apt_pkg", files, libraries=["apt-pkg"]); # The apt_inst module -files = string.split(parse_makefile("python/makefile")["APT_INST_SRC"]); -for i in range(0,len(files)): - files[i] = "python/"+ files[i]; -apt_inst = Extension("apt_inst", files, - libraries=["apt-pkg","apt-inst"]); +files = map(lambda source: "python/"+source, + string.split(parse_makefile("python/makefile")["APT_INST_SRC"])) +apt_inst = Extension("apt_inst", files, libraries=["apt-pkg","apt-inst"]); setup(name="python-apt", - version="0.6.13", + version="0.6.17", description="Python bindings for APT", author="APT Development Team", author_email="deity@lists.debian.org", diff --git a/tests/memleak.py b/tests/memleak.py new file mode 100755 index 00000000..3e59cbb7 --- /dev/null +++ b/tests/memleak.py @@ -0,0 +1,42 @@ +#!/usr/bin/python + +import apt +import apt_pkg +import time +import gc +import sys + + +cache = apt.Cache() + +# memleak +#for i in range(100): +# cache.open(None) +# print cache["apt"].name +# time.sleep(1) +# gc.collect() + +# memleak +#for i in range(100): +# cache = apt.Cache() +# time.sleep(1) +# cache = None +# gc.collect() + +# no memleak, but more or less the apt.Cache.open() code +for i in range(100): + cache = apt_pkg.GetCache() + depcache = apt_pkg.GetDepCache(cache) + records = apt_pkg.GetPkgRecords(cache) + list = apt_pkg.GetPkgSourceList() + list.ReadMainList() + dict = {} + for pkg in cache.Packages: + if len(pkg.VersionList) > 0: + dict[pkg.Name] = apt.Package(cache,depcache, + records, list, None, pkg) + + print cache["apt"] + time.sleep(1) + + gc.collect() diff --git a/tests/pkgsrcrecords.py b/tests/pkgsrcrecords.py index dc4881dd..28df3f7c 100644 --- a/tests/pkgsrcrecords.py +++ b/tests/pkgsrcrecords.py @@ -14,7 +14,7 @@ def main(): print "Running PkgSrcRecords test on all packages:" for x in cache.Packages: i += 1 - src = apt_pkg.GetPkgSrcRecords(cache) + src = apt_pkg.GetPkgSrcRecords() if src.Lookup(x.Name): #print src.Package pass |
