From dd85685eb9c2a3ce4392b581818d4ac84410f296 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 31 Jul 2009 15:02:12 +0200 Subject: apt/progress/base.py: Introduce new base progress classes. Also adjust the class in apt/progress/text.py to derive from this instead of the classes in apt_pkg (which will be dropped). --- apt/progress/base.py | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 apt/progress/base.py (limited to 'apt/progress/base.py') diff --git a/apt/progress/base.py b/apt/progress/base.py new file mode 100644 index 00000000..fc5a8107 --- /dev/null +++ b/apt/progress/base.py @@ -0,0 +1,164 @@ +# apt/progress/base.py - Base classes for progress reporting. +# +# Copyright (C) 2009 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. +# +# 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 +"""Base classes for progress reporting. + +Custom progress classes should inherit from these classes. They can also be +used as dummy progress classes which simply do nothing. +""" + + +class AcquireProgress(object): + """Monitor object for downloads controlled by the Acquire class. + + This is an mostly abstract class. You should subclass it and implement the + methods to get something useful. + """ + + current_bytes = current_cps = fetched_bytes = last_bytes = total_bytes \ + = 0.0 + current_items = elapsed_time = total_items = 0 + + def done(self, item): + """Invoked when an item is successfully and completely fetched.""" + + def fail(self, item): + """Invoked when an item could not be fetched.""" + + def fetch(self, item): + """Invoked when some of the item's data is fetched.""" + + def ims_hit(self, item): + """Invoked when an item is confirmed to be up-to-date. + + Invoked when an item is confirmed to be up-to-date. For instance, + when an HTTP download is informed that the file on the server was + not modified. + """ + + def media_change(self, media, drive): + """Prompt the user to change the inserted removable media. + + The parameter 'media' decribes the name of the the media type that + should be changed, whereas the parameter 'drive' should be the + identifying name of the drive whose media should be changed. + + This method should not return until the user has confirmed to the user + interface that the media change is complete. It must return True if + the user confirms the media change, or False to cancel it. + """ + return False + + def pulse(self, owner): + """Periodically invoked while the Acquire process is underway. + + This method gets invoked while the Acquire progress given by the + parameter 'owner' is underway. It should display information about + the current state. + + This function returns a boolean value indicating whether the + acquisition should be continued (True) or cancelled (False). + """ + return True + + def start(self): + """Invoked when the Acquire process starts running.""" + # Reset all our values. + self.current_bytes = 0.0 + self.current_cps = 0.0 + self.current_items = 0 + self.elapsed_time = 0 + self.fetched_bytes = 0.0 + self.last_bytes = 0.0 + self.total_bytes = 0.0 + self.total_items = 0 + + def stop(self): + """Invoked when the Acquire process stops running.""" + + +class CdromProgress(object): + """Base class for reporting the progress of adding a cdrom. + + Can be used with apt_pkg.Cdrom to produce an utility like apt-cdrom. The + attribute 'total_steps' defines the total number of steps and can be used + in update() to display the current progress. + """ + + total_steps = 0 + + def ask_cdrom_name(self): + """Ask for the name of the cdrom. + + If a name has been provided, return it. Otherwise, return None to + cancel the operation. + """ + + def change_cdrom(self): + """Ask for the CD-ROM to be changed. + + Return True once the cdrom has been changed or False to cancel the + operation. + """ + + def update(self, text, current): + """Periodically invoked to update the interface. + + The string 'text' defines the text which should be displayed. The + integer 'current' defines the number of completed steps. + """ + + +class InstallProgress(object): + """Report the install progress. + + Subclass this class to implement install progress reporting. + """ + + def start_update(self): + """Start update.""" + + def run(self, pm): + """Start installation.""" + return pm.do_install() + + def finish_update(self): + """Called when update has finished.""" + + def update_interface(self): + """Called periodically to update the user interface.""" + + +class OpProgress(object): + """Monitor objects for operations. + + Display the progress of operations such as opening the cache.""" + + major_change, op, percent, subop = False, "", 0.0, "" + + def update(self, percent=None): + """Called periodically to update the user interface. + + You may use the optional argument 'percent' to set the attribute + 'percent' in this call. + """ + if percent is not None: + self.percent = percent + + def done(self): + """Called once an operation has been completed.""" -- cgit v1.2.3 From e556b2cbbe5878c33d9e7302e637cc7f35dd14bf Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 31 Jul 2009 20:51:57 +0200 Subject: apt/progress: Large update, introducing apt.progress.base.InstallProgress. This contains many updates including the introduction of a new InstallProgress class which replaces the old InstallProgress and DpkgInstallProgress classes. --- apt/debfile.py | 2 +- apt/package.py | 2 +- apt/progress/__init__.py | 13 ++- apt/progress/base.py | 135 ++++++++++++++++++++-- apt/progress/gtk2.py | 82 +++++-------- apt/progress/old.py | 294 +++++++++-------------------------------------- apt/progress/text.py | 2 + 7 files changed, 225 insertions(+), 305 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/debfile.py b/apt/debfile.py index e05233f4..fd6c1532 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -417,7 +417,7 @@ class DebPackage(object): def install(self, install_progress=None): """Install the package.""" if install_progress is None: - return os.system("dpkg -i %s" % self.filename) + return os.spawnlp(os.P_WAIT, "dpkg", "dpkg", "-i", self.filename) else: try: install_progress.start_update() diff --git a/apt/package.py b/apt/package.py index f8e1354b..9a1b0d68 100644 --- a/apt/package.py +++ b/apt/package.py @@ -1180,7 +1180,7 @@ class Package(object): like apt.progress.text.AcquireProgress(). The parameter *iprogress* refers to an InstallProgress() object, as - found in apt.progress.old. + found in apt.progress.base. """ self._pcache._depcache.commit(fprogress, iprogress) diff --git a/apt/progress/__init__.py b/apt/progress/__init__.py index c75c368b..10c11021 100644 --- a/apt/progress/__init__.py +++ b/apt/progress/__init__.py @@ -1,3 +1,5 @@ +# apt/progress/__init__.py - Initialization file for apt.progress. +# # Copyright (c) 2009 Julian Andres Klode # # This program is free software; you can redistribute it and/or @@ -14,9 +16,18 @@ # 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.""" +"""Progress reporting. + +This package provides progress reporting for the python-apt package. The module +'base' provides classes with no output, the module 'gtk2' provides classes for +GTK+ applications, and the module 'text' provides classes for terminals, etc. +""" import apt_pkg + +__all__ = [] + + if apt_pkg._COMPAT_0_7: from apt.progress.old import (CdromProgress, DpkgInstallProgress, DumbInstallProgress, FetchProgress, diff --git a/apt/progress/base.py b/apt/progress/base.py index fc5a8107..08d35533 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -21,6 +21,13 @@ Custom progress classes should inherit from these classes. They can also be used as dummy progress classes which simply do nothing. """ +import errno +import fcntl +import os +import re +import select + +__all__ = ['AcquireProgress', 'CdromProgress', 'InstallProgress', 'OpProgress'] class AcquireProgress(object): @@ -125,23 +132,131 @@ class CdromProgress(object): class InstallProgress(object): - """Report the install progress. + """Class to report the progress of installing packages.""" - Subclass this class to implement install progress reporting. - """ + percent, select_timeout, status = 0.0, 0.1, "" - def start_update(self): - """Start update.""" + def __init__(self): + (read, write) = os.pipe() + self.writefd = os.fdopen(write, "w") + self.statusfd = os.fdopen(read, "r") + fcntl.fcntl(self.statusfd, fcntl.F_SETFL, os.O_NONBLOCK) - def run(self, pm): - """Start installation.""" - return pm.do_install() + def start_update(self): + """(Abstract) Start update.""" def finish_update(self): - """Called when update has finished.""" + """(Abstract) Called when update has finished.""" + + def error(self, pkg, errormsg): + """(Abstract) Called when a error is detected during the install.""" + + def conffile(self, current, new): + """(Abstract) Called when a conffile question from dpkg is detected.""" + + def status_change(self, pkg, percent, status): + """(Abstract) Called when the status changed.""" + + def processing(self, pkg, stage): + """(Abstract) Sent just before a processing stage starts. + + The parameter 'stage' is one of "upgrade", "install" + (both sent before unpacking), "configure", "trigproc", "remove", + "purge". This method is used for dpkg only. + """ + + def run(self, obj): + """Install using the object 'obj'. + + This functions runs install actions. The parameter 'obj' may either + be a PackageManager object in which case its do_install() method is + called or the path to a deb file. + + If the object is a PackageManager, the functions returns the result + of calling its do_install() method. Otherwise, the function returns + the exit status of dpkg. In both cases, 0 means that there were no + problems. + """ + pid = self.fork() + if pid == 0: + try: + os._exit(obj.do_install(self.writefd.fileno())) + except AttributeError: + os._exit(os.spawnlp(os.P_WAIT, "dpkg", "dpkg", "--status-fd", + str(self.writefd.fileno()), "-i", obj)) + self.child_pid = pid + res = self.wait_child() + return os.WEXITSTATUS(res) + + def fork(self): + """Fork.""" + return os.fork() def update_interface(self): - """Called periodically to update the user interface.""" + """Update the interface.""" + try: + line = self.statusfd.readline() + except IOError, (errno_, errstr): + # resource temporarly unavailable is ignored + if errno_ != errno.EAGAIN and errno_ != errno.EWOULDBLOCK: + print errstr + return + + pkgname = status = status_str = percent = base = "" + + if line.startswith('pm'): + try: + (status, pkgname, percent, status_str) = line.split(":", 3) + except ValueError: + # silently ignore lines that can't be parsed + self.read = "" + return + elif line.startswith('status'): + try: + (base, pkgname, status, status_str) = line.split(": ", 3) + except ValueError: + (base, pkgname, status) = line.split(": ", 2) + elif line.startswith('processing'): + (status, status_str, pkgname) = line.split(": ", 2) + self.processing(pkgname.strip(), status_str.strip()) + + if status == 'pmerror' or status == 'error': + self.error(pkgname, status_str) + elif status == 'conffile-prompt' or status == 'pmconffile': + 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.status_change(pkgname, float(percent), status_str.strip()) + self.percent = float(percent) + self.status = status_str.strip() + + def wait_child(self): + """Wait for child progress to exit. + + This method is responsible for calling update_interface() from time to + time. It exits once the child has exited. + """ + (pid, res) = (0, 0) + while True: + try: + select.select([self.statusfd], [], [], self.select_timeout) + except select.error, err: + if err[0] != errno.EINTR: + raise + + self.update_interface() + try: + (pid, res) = os.waitpid(self.child_pid, os.WNOHANG) + if pid == self.child_pid: + break + except OSError, err: + if err[0] != errno.EINTR: + raise + if err[0] == errno.ECHILD: + break + return res class OpProgress(object): diff --git a/apt/progress/gtk2.py b/apt/progress/gtk2.py index edba0a4d..22788984 100644 --- a/apt/progress/gtk2.py +++ b/apt/progress/gtk2.py @@ -11,7 +11,7 @@ # 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, +# 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. @@ -42,6 +42,9 @@ from apt.deprecation import function_deprecated_by, AttributeDeprecatedBy from apt.progress import base, old +__all__ = ['GInstallProgress', 'GOpProgress', 'GtkAptProgress'] + + def mksig(params=(), run=gobject.SIGNAL_RUN_FIRST, rettype=gobject.TYPE_NONE): """Simplified Create a gobject signal. @@ -90,7 +93,7 @@ class GOpProgress(gobject.GObject, base.OpProgress): Op = AttributeDeprecatedBy('op') -class GInstallProgress(gobject.GObject, old.InstallProgress): +class GInstallProgress(gobject.GObject, base.InstallProgress): """Installation progress with GObject signals. Signals: @@ -114,7 +117,7 @@ class GInstallProgress(gobject.GObject, old.InstallProgress): "status-finished": mksig()} def __init__(self, term): - old.InstallProgress.__init__(self) + base.InstallProgress.__init__(self) gobject.GObject.__init__(self) self.finished = False self.time_last_update = time.time() @@ -152,6 +155,11 @@ class GInstallProgress(gobject.GObject, old.InstallProgress): """ self.emit("status-started") + def run(self, obj): + """Run.""" + self.finished = False + return base.InstallProgress.run(self, obj) + def finish_update(self): """Called when the update finished. @@ -159,6 +167,11 @@ class GInstallProgress(gobject.GObject, old.InstallProgress): """ self.emit("status-finished") + def processing(self, pkg, stage): + """Called when entering a new stage in dpkg.""" + # We have no percentage or alike, send -1 to let the bar pulse. + self.emit("status-changed", ("Installing %s...") % pkg, -1) + def status_change(self, pkg, percent, status): """Called when the status changed. @@ -172,7 +185,7 @@ class GInstallProgress(gobject.GObject, old.InstallProgress): Emits: status-timeout() [When a timeout happens] """ - old.InstallProgress.update_interface(self) + base.InstallProgress.update_interface(self) while self._context.pending(): self._context.iteration() if self.time_last_update + self.INSTALL_TIMEOUT < time.time(): @@ -197,34 +210,7 @@ class GInstallProgress(gobject.GObject, old.InstallProgress): childExited = function_deprecated_by(child_exited) -class GDpkgInstallProgress(old.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.""" - old.DpkgInstallProgress.run(self, debfile) - - def update_interface(self): - """Called periodically to update the interface. - - Emits: status-timeout() [When a timeout happens]""" - old.DpkgInstallProgress.update_interface(self) - if self.time_last_update + self.INSTALL_TIMEOUT < time.time(): - self.emit("status-timeout") - - if apt_pkg._COMPAT_0_7: - updateInterface = function_deprecated_by(update_interface) +GDpkgInstallProgress = GInstallProgress class GFetchProgress(gobject.GObject, old.FetchProgress): @@ -235,6 +221,8 @@ class GFetchProgress(gobject.GObject, old.FetchProgress): * status-changed(str: description, int: percent) * status-started() * status-finished() + + DEPRECATED. """ __gsignals__ = {"status-changed": mksig((str, int)), @@ -258,19 +246,19 @@ class GFetchProgress(gobject.GObject, old.FetchProgress): def pulse(self): old.FetchProgress.pulse(self) - current_item = self.current_items + 1 - if current_item > self.total_items: - current_item = self.total_items + current_item = self.currentItems + 1 + if current_item > self.totalItems: + current_item = self.totalItems if self.current_cps > 0: text = (_("Downloading file %(current)li of %(total)li with " "%(speed)s/s") % \ {"current": current_item, - "total": self.total_items, - "speed": apt_pkg.size_to_str(self.current_cps)}) + "total": self.totalItems, + "speed": apt_pkg.size_to_str(self.currentCPS)}) else: text = (_("Downloading file %(current)li of %(total)li") % \ {"current": current_item, - "total": self.total_items}) + "total": self.totalItems}) self.emit("status-changed", text, self.percent) while self._context.pending(): self._context.iteration() @@ -328,19 +316,6 @@ class GtkAptProgress(gtk.VBox): 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.""" @@ -361,7 +336,7 @@ class GtkAptProgress(gtk.VBox): @property def dpkg_install(self): """Return the install progress handler for dpkg.""" - return self._dpkg_progress_install + return self._progress_install @property def fetch(self): @@ -383,7 +358,7 @@ class GtkAptProgress(gtk.VBox): def _on_status_changed(self, progress, status, percent): """Called when the status changed.""" self._label.set_text(status) - if percent is None: + if percent is None or percent == -1: self._progressbar.pulse() else: self._progressbar.set_fraction(percent/100.0) @@ -431,6 +406,7 @@ def _test(): """Test function""" import sys + import apt from apt.debfile import DebPackage win = gtk.Window() diff --git a/apt/progress/old.py b/apt/progress/old.py index 6b6e21de..c2d95b85 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -20,72 +20,51 @@ # USA """Deprecated 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. +This module provides classes for compatibility with python-apt 0.7. They are +completely deprecated and should not be used anymore. """ -import errno -import fcntl + import os -import re -import select import sys import apt_pkg from apt.deprecation import AttributeDeprecatedBy, function_deprecated_by +import warnings from apt.progress import base, text - __all__ = [] class OpProgress(base.OpProgress): - """Abstract class to implement reporting on cache opening. - - Subclass this class to implement simple Operation progress reporting. - """ + """Abstract class to implement reporting on cache opening.""" - if apt_pkg._COMPAT_0_7: - subOp = AttributeDeprecatedBy('subop') - Op = AttributeDeprecatedBy('op') + subOp = AttributeDeprecatedBy('subop') + Op = AttributeDeprecatedBy('op') -class OpTextProgress(text.OpProgress): +class OpTextProgress(OpProgress, text.OpProgress): """A simple text based cache open reporting class.""" - if apt_pkg._COMPAT_0_7: - subOp = AttributeDeprecatedBy('subop') - Op = AttributeDeprecatedBy('op') - class FetchProgress(object): - """Report the download/fetching progress. - - Subclass this class to implement fetch progress reporting - """ + """Report the download/fetching progress.""" # download status constants - dl_done = 0 - dl_queued = 1 - dl_failed = 2 - dl_hit = 3 - dl_ignored = 4 - dl_status_str = {dl_done: "Done", - dl_queued: "Queued", - dl_failed: "Failed", - dl_hit: "Hit", - dl_ignored: "Ignored"} + (dlDone, dlQueued, dlFailed, dlHit, dlIgnored) = range(5) + 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.current_bytes = 0 - self.current_items = 0 - self.total_bytes = 0 - self.total_items = 0 - self.current_cps = 0 + self.currentBytes = 0 + self.currentItems = 0 + self.totalBytes = 0 + self.totalItems = 0 + self.currentCPS = 0 + warnings.warn("FetchProgress() is deprecated.", DeprecationWarning) def start(self): """Called when the fetching starts.""" @@ -93,7 +72,7 @@ class FetchProgress(object): def stop(self): """Called when all files have been fetched.""" - def update_status(self, uri, descr, short_descr, status): + def updateStatus(self, uri, descr, short_descr, status): """Called when the status of an item changes. This happens eg. when the downloads fails or is completed. @@ -112,11 +91,11 @@ class FetchProgress(object): Return True to continue or False to cancel. """ - self.percent = (((self.current_bytes + self.current_items) * 100.0) / - float(self.total_bytes + self.total_items)) - if self.current_cps > 0: - self.eta = ((self.total_bytes - self.current_bytes) / - float(self.current_cps)) + 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 pulse_items(self, items): @@ -125,31 +104,16 @@ class FetchProgress(object): Return True to continue or False to cancel. """ - self.percent = (((self.current_bytes + self.current_items) * 100.0) / - float(self.total_bytes + self.total_items)) - if self.current_cps > 0: - self.eta = ((self.total_bytes - self.current_bytes) / - float(self.current_cps)) + 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 media_change(self, medium, drive): + def mediaChange(self, medium, drive): """react to media change events.""" - if apt_pkg._COMPAT_0_7: - dlDone = AttributeDeprecatedBy('dl_done') - dlQueued = AttributeDeprecatedBy('dl_queued') - dlFailed = AttributeDeprecatedBy('dl_failed') - dlHit = AttributeDeprecatedBy('dl_hit') - dlIgnored = AttributeDeprecatedBy('dl_ignored') - dlStatusStr = AttributeDeprecatedBy('dl_status_str') - currentBytes = AttributeDeprecatedBy('current_bytes') - currentItems = AttributeDeprecatedBy('current_items') - totalBytes = AttributeDeprecatedBy('total_bytes') - totalItems = AttributeDeprecatedBy('total_items') - currentCPS = AttributeDeprecatedBy('current_cps') - updateStatus = function_deprecated_by(update_status) - mediaChange = function_deprecated_by(media_change) - class TextFetchProgress(FetchProgress): """ Ready to use progress object for terminal windows """ @@ -158,13 +122,13 @@ class TextFetchProgress(FetchProgress): FetchProgress.__init__(self) self.items = {} - def update_status(self, uri, descr, short_descr, status): + def updateStatus(self, uri, descr, short_descr, status): """Called when the status of an item changes. This happens eg. when the downloads fails or is completed. """ - if status != self.dl_queued: - print "\r%s %s" % (self.dl_status_str[status], descr) + if status != self.dlQueued: + print "\r%s %s" % (self.dlStatusStr[status], descr) self.items[uri] = status def pulse(self): @@ -173,9 +137,9 @@ class TextFetchProgress(FetchProgress): Return True to continue or False to cancel. """ FetchProgress.pulse(self) - if self.current_cps > 0: + if self.currentCPS > 0: s = "[%2.f%%] %sB/s %s" % (self.percent, - apt_pkg.size_to_str(int(self.current_cps)), + apt_pkg.size_to_str(int(self.currentCPS)), apt_pkg.time_to_str(int(self.eta))) else: s = "%2.f%% [Working]" % (self.percent) @@ -187,16 +151,23 @@ class TextFetchProgress(FetchProgress): """Called when all files have been fetched.""" print "\rDone downloading " - def media_change(self, medium, drive): + 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') - if apt_pkg._COMPAT_0_7: - updateStatus = function_deprecated_by(update_status) - mediaChange = function_deprecated_by(media_change) + +class CdromProgress(base.CdromProgress): + """Report the cdrom add progress. + + This class has been replaced by apt_pkg.CdromProgress. + """ + _basetype = base.CdromProgress + askCdromName = function_deprecated_by(_basetype.ask_cdrom_name) + changeCdrom = function_deprecated_by(_basetype.change_cdrom) + del _basetype class DumbInstallProgress(base.InstallProgress): @@ -208,127 +179,19 @@ class DumbInstallProgress(base.InstallProgress): startUpdate = function_deprecated_by(base.InstallProgress.start_update) finishUpdate = function_deprecated_by(base.InstallProgress.finish_update) updateInterface = function_deprecated_by( - base.InstallProgress.update_interface) + base.InstallProgress.update_interface) -class InstallProgress(DumbInstallProgress): +class InstallProgress(DumbInstallProgress, base.InstallProgress): """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.select_timeout = 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 status_change(self, pkg, percent, status): - """Called when the status changed.""" - - def update_interface(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.status_change(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 wait_child(self): - """Wait for child progress to exit.""" - while True: - try: - select.select([self.statusfd], [], [], self.select_timeout) - except select.error, (errno_, errstr): - if errno_ != errno.EINTR: - raise - - self.update_interface() - try: - (pid, res) = os.waitpid(self.child_pid, os.WNOHANG) - if pid == self.child_pid: - break - except OSError, (errno_, errstr): - if errno_ != errno.EINTR: - raise - if errno_ == errno.ECHILD: - break - return res - - def run(self, pm): - """Start installing.""" - pid = self.fork() - if pid == 0: - # child - res = pm.do_install(self.writefd) - os._exit(res) - self.child_pid = pid - res = self.wait_child() - return os.WEXITSTATUS(res) - - if apt_pkg._COMPAT_0_7: - selectTimeout = AttributeDeprecatedBy('select_timeout') - statusChange = function_deprecated_by(status_change) - waitChild = function_deprecated_by(wait_child) - updateInterface = function_deprecated_by(update_interface) - - -class CdromProgress(base.CdromProgress): - """Report the cdrom add progress. - - This class has been replaced by apt_pkg.CdromProgress. - """ - _basetype = base.CdromProgress - askCdromName = function_deprecated_by(_basetype.ask_cdrom_name) - changeCdrom = function_deprecated_by(_basetype.change_cdrom) - del _basetype + selectTimeout = AttributeDeprecatedBy('select_timeout') + statusChange = function_deprecated_by(base.InstallProgress.status_change) + waitChild = function_deprecated_by(base.InstallProgress.wait_child) class DpkgInstallProgress(InstallProgress): @@ -336,54 +199,7 @@ class DpkgInstallProgress(InstallProgress): def run(self, debfile): """Start installing the given Debian package.""" - if apt_pkg._COMPAT_0_7: # Deprecated stuff - 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, debfile)) - os._exit(os.WEXITSTATUS(res)) - self.child_pid = pid - res = self.wait_child() - return res - - def update_interface(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 - pkg_name = statusl[1].strip() - status = statusl[2].strip() - #print status - if status == "error": - self.error(pkg_name, 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 = "" - - if apt_pkg._COMPAT_0_7: - updateInterface = function_deprecated_by(update_interface) + # Deprecated stuff + self.debfile = debfile + self.debname = os.path.basename(debfile).split("_")[0] + return base.InstallProgress(self, debfile) diff --git a/apt/progress/text.py b/apt/progress/text.py index eb474d6d..3a6d3e65 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -257,3 +257,5 @@ class CdromProgress(base.CdromProgress, TextProgress): return (raw_input() == '') except KeyboardInterrupt: return False + +InstallProgress = base.InstallProgress -- cgit v1.2.3 From 6dae07e834445c193f392cf53a252b83c68f2bcd Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 15 Jan 2010 15:42:44 +0100 Subject: Make all class-level constants have uppercase names. --- apt/cache.py | 14 +++++++------- apt/package.py | 4 ++-- apt/progress/base.py | 2 +- apt/progress/text.py | 2 +- debian/changelog | 1 + doc/source/library/apt_pkg.rst | 16 ++++++++-------- python/apt_pkgmodule.cc | 18 +++++++++--------- 7 files changed, 29 insertions(+), 28 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/cache.py b/apt/cache.py index eea06d56..d339f377 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -223,9 +223,9 @@ class Cache(object): transient = False err_msg = "" for item in fetcher.items: - if item.status == item.stat_done: + if item.status == item.STAT_DONE: continue - if item.stat_idle: + if item.STAT_IDLE: transient = True continue err_msg += "Failed to fetch %s %s\n" % (item.desc_uri, @@ -311,7 +311,7 @@ class Cache(object): pulse_interval) if res == apt_pkg.Acquire.result_cancelled and raise_on_error: raise FetchCancelledException() - if res == apt_pkg.Acquire.result_failed and raise_on_error: + if res == apt_pkg.Acquire.RESULT_FAILED and raise_on_error: raise FetchFailedException() else: return res @@ -369,17 +369,17 @@ class Cache(object): # then install res = self.install_archives(pm, install_progress) - if res == pm.result_completed: + if res == pm.RESULT_COMPLETED: break - elif res == pm.result_failed: + elif res == pm.RESULT_FAILED: raise SystemError("installArchives() failed") - elif res == pm.result_incomplete: + elif res == pm.RESULT_INCOMPLETE: pass else: raise SystemError("internal-error: unknown result code from InstallArchives: %s" % res) # reload the fetcher for media swaping fetcher.shutdown() - return (res == pm.result_completed) + return (res == pm.RESULT_COMPLETED) def clear(self): """ Unmark all changes """ diff --git a/apt/package.py b/apt/package.py index 315a7589..8171f57d 100644 --- a/apt/package.py +++ b/apt/package.py @@ -500,7 +500,7 @@ class Version(object): self.size, base, destfile=destfile) acq.run() - if acqfile.status != acqfile.stat_done: + if acqfile.status != acqfile.STAT_DONE: raise FetchError("The item %r could not be fetched: %s" % (acqfile.destfile, acqfile.error_text)) print self._records.filename @@ -548,7 +548,7 @@ class Version(object): acq.run() for item in acq.items: - if item.status != item.stat_done: + if item.status != item.STAT_DONE: raise FetchError("The item %r could not be fetched: %s" % (item.destfile, item.error_text)) diff --git a/apt/progress/base.py b/apt/progress/base.py index fd6bc475..adb39e93 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -192,7 +192,7 @@ class InstallProgress(object): os._exit(os.spawnlp(os.P_WAIT, "dpkg", "dpkg", "--status-fd", str(self.writefd.fileno()), "-i", obj)) except Exception: - os._exit(apt_pkg.PackageManager.result_failed) + os._exit(apt_pkg.PackageManager.RESULT_FAILED) self.child_pid = pid res = self.wait_child() diff --git a/apt/progress/text.py b/apt/progress/text.py index 3a6d3e65..796577e2 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -125,7 +125,7 @@ class AcquireProgress(base.AcquireProgress, TextProgress): def fail(self, item): """Called when an item is failed.""" base.AcquireProgress.fail(self, item) - if item.owner.status == item.owner.stat_done: + if item.owner.status == item.owner.STAT_DONE: self._write(_("Ign ") + item.description) else: self._write(_("Err ") + item.description) diff --git a/debian/changelog b/debian/changelog index a7204a0a..acd9c3ca 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,7 @@ python-apt (0.7.93) UNRELEASED; urgency=low - Disable 2.6 and 3.1 builds previously available in experimental. * Merge lp:~forest-bond/python-apt/cache-is-virtual-package-catch-key-error - Return False in Cache.is_virtual_package if the package does not exist. + * Make all class-level constants have uppercase names. [ Colin Watson ] * apt/progress/__init__.py: diff --git a/doc/source/library/apt_pkg.rst b/doc/source/library/apt_pkg.rst index 5876fb8d..c3a74267 100644 --- a/doc/source/library/apt_pkg.rst +++ b/doc/source/library/apt_pkg.rst @@ -282,21 +282,21 @@ Working with the cache Fix the installation if a package could not be downloaded. - .. attribute:: result_completed + .. attribute:: RESULT_COMPLETED A constant for checking whether the the result is 'completed'. Compare it against the return value of :meth:`PackageManager.get_archives` or :meth:`PackageManager.do_install`. - .. attribute:: result_failed + .. attribute:: RESULT_FAILED A constant for checking whether the the result is 'failed'. Compare it against the return value of :meth:`PackageManager.get_archives` or :meth:`PackageManager.do_install`. - .. attribute:: result_incomplete + .. attribute:: RESULT_INCOMPLETE A constant for checking whether the the result is 'incomplete'. @@ -1110,23 +1110,23 @@ installation. Integer, representing the status of the item. - .. attribute:: stat_idle + .. attribute:: STAT_IDLE Constant for comparing :attr:`AcquireItem.status`. - .. attribute:: stat_fetching + .. attribute:: STAT_FETCHING Constant for comparing :attr:`AcquireItem.status` - .. attribute:: stat_done + .. attribute:: STAT_DONE Constant for comparing :attr:`AcquireItem.status` - .. attribute:: stat_error + .. attribute:: STAT_ERROR Constant for comparing :attr:`AcquireItem.status` - .. attribute:: stat_auth_error + .. attribute:: STAT_AUTH_ERROR Constant for comparing :attr:`AcquireItem.status` diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc index f20b0c87..cdd23705 100644 --- a/python/apt_pkgmodule.cc +++ b/python/apt_pkgmodule.cc @@ -670,7 +670,7 @@ extern "C" void initapt_pkg() Py_BuildValue("i", pkgAcquire::Cancelled)); PyDict_SetItemString(PyAcquire_Type.tp_dict, "result_continue", Py_BuildValue("i", pkgAcquire::Continue)); - PyDict_SetItemString(PyAcquire_Type.tp_dict, "result_failed", + PyDict_SetItemString(PyAcquire_Type.tp_dict, "RESULT_FAILED", Py_BuildValue("i", pkgAcquire::Failed)); #ifdef COMPAT_0_7 PyDict_SetItemString(PyAcquire_Type.tp_dict, "ResultCancelled", @@ -702,11 +702,11 @@ extern "C" void initapt_pkg() // PackageManager constants - PyDict_SetItemString(PyPackageManager_Type.tp_dict, "result_completed", + PyDict_SetItemString(PyPackageManager_Type.tp_dict, "RESULT_COMPLETED", Py_BuildValue("i", pkgPackageManager::Completed)); - PyDict_SetItemString(PyPackageManager_Type.tp_dict, "result_failed", + PyDict_SetItemString(PyPackageManager_Type.tp_dict, "RESULT_FAILED", Py_BuildValue("i", pkgPackageManager::Failed)); - PyDict_SetItemString(PyPackageManager_Type.tp_dict, "result_incomplete", + PyDict_SetItemString(PyPackageManager_Type.tp_dict, "RESULT_INCOMPLETE", Py_BuildValue("i", pkgPackageManager::Incomplete)); #ifdef COMPAT_0_7 @@ -719,15 +719,15 @@ extern "C" void initapt_pkg() #endif // AcquireItem Constants. - PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "stat_idle", + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_IDLE", Py_BuildValue("i", pkgAcquire::Item::StatIdle)); - PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "stat_fetching", + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_FETCHING", Py_BuildValue("i", pkgAcquire::Item::StatFetching)); - PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "stat_done", + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_DONE", Py_BuildValue("i", pkgAcquire::Item::StatDone)); - PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "stat_error", + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_ERROR", Py_BuildValue("i", pkgAcquire::Item::StatError)); - PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "stat_auth_error", + PyDict_SetItemString(PyAcquireItem_Type.tp_dict, "STAT_AUTH_ERROR", Py_BuildValue("i", pkgAcquire::Item::StatAuthError)); #ifdef COMPAT_0_7 -- cgit v1.2.3 From ef77bd9cc237bd3ddae8e22fd325b412ad46ab00 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 17 Jan 2010 13:31:33 +0100 Subject: apt/progress/base.py: Use attributes of IOError and OSError object. Do not treat them as tuples, but use the attributes. This is way more 'modern'. --- apt/progress/base.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/progress/base.py b/apt/progress/base.py index adb39e93..4df26f26 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -206,10 +206,10 @@ class InstallProgress(object): """Update the interface.""" try: line = self.statusfd.readline() - except IOError, (errno_, errstr): + except IOError, err: # resource temporarly unavailable is ignored - if errno_ != errno.EAGAIN and errno_ != errno.EWOULDBLOCK: - print errstr + if err.errno != errno.EAGAIN and err.errno != errno.EWOULDBLOCK: + print err.strerror return pkgname = status = status_str = percent = base = "" @@ -254,7 +254,7 @@ class InstallProgress(object): try: select.select([self.statusfd], [], [], self.select_timeout) except select.error, err: - if err[0] != errno.EINTR: + if err.errno != errno.EINTR: raise self.update_interface() @@ -263,9 +263,9 @@ class InstallProgress(object): if pid == self.child_pid: break except OSError, err: - if err[0] == errno.ECHILD: + if err.errno == errno.ECHILD: break - if err[0] != errno.EINTR: + if err.errno != errno.EINTR: raise return res -- cgit v1.2.3 From a1f06a125e59bf06ea8fccea9b584097221c0032 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 17 Jan 2010 15:41:44 +0100 Subject: apt/progress/base.py: Fix some parsing of dpkg status fd. --- apt/progress/base.py | 12 +++++++++--- debian/changelog | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/progress/base.py b/apt/progress/base.py index 4df26f26..64bb22dc 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -223,13 +223,18 @@ class InstallProgress(object): return elif line.startswith('status'): try: - (base, pkgname, status, status_str) = line.split(": ", 3) + (base, pkgname, status, status_str) = line.split(":", 3) except ValueError: - (base, pkgname, status) = line.split(": ", 2) + (base, pkgname, status) = line.split(":", 2) elif line.startswith('processing'): - (status, status_str, pkgname) = line.split(": ", 2) + (status, status_str, pkgname) = line.split(":", 2) self.processing(pkgname.strip(), status_str.strip()) + # Always strip the status message + pkgname = pkgname.strip() + status_str = status_str.strip() + status = status.strip() + if status == 'pmerror' or status == 'error': self.error(pkgname, status_str) elif status == 'conffile-prompt' or status == 'pmconffile': @@ -237,6 +242,7 @@ class InstallProgress(object): if match: self.conffile(match.group(1), match.group(2)) elif status == "pmstatus": + # FIXME: Float comparison if float(percent) != self.percent or status_str != self.status: self.status_change(pkgname, float(percent), status_str.strip()) self.percent = float(percent) diff --git a/debian/changelog b/debian/changelog index 646b9efe..5001f1fe 100644 --- a/debian/changelog +++ b/debian/changelog @@ -14,6 +14,8 @@ python-apt (0.7.93) UNRELEASED; urgency=low * aptsources: - Make all classes subclasses of object. - distro.py: Support Python 3, decode lsb_release results using utf-8. + * apt/progress/base.py: + - Fix some parsing of dpkg status fd. [ Colin Watson ] * apt/progress/__init__.py: -- cgit v1.2.3 From 68f67667905f8b659b7f7bc1171f6092d931908a Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Wed, 20 Jan 2010 14:58:16 +0100 Subject: apt/progress/base.py: Add InstallProgress.dpkg_status_change. --- apt/progress/base.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/progress/base.py b/apt/progress/base.py index 64bb22dc..0c0796d6 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -157,7 +157,10 @@ class InstallProgress(object): """(Abstract) Called when a conffile question from dpkg is detected.""" def status_change(self, pkg, percent, status): - """(Abstract) Called when the status changed.""" + """(Abstract) Called when the APT status changed.""" + + def dpkg_status_change(self, pkg, status): + """(Abstract) Called when the dpkg status changed.""" def processing(self, pkg, stage): """(Abstract) Sent just before a processing stage starts. @@ -184,7 +187,7 @@ class InstallProgress(object): # pm.do_install might raise a exception, # when this happens, we need to catch # it, otherwise os._exit() is not run - # and the execution continues in the + # and the execution continues in the # parent code leading to very confusing bugs try: os._exit(obj.do_install(self.writefd.fileno())) @@ -193,7 +196,7 @@ class InstallProgress(object): str(self.writefd.fileno()), "-i", obj)) except Exception: os._exit(apt_pkg.PackageManager.RESULT_FAILED) - + self.child_pid = pid res = self.wait_child() return os.WEXITSTATUS(res) @@ -247,6 +250,8 @@ class InstallProgress(object): self.status_change(pkgname, float(percent), status_str.strip()) self.percent = float(percent) self.status = status_str.strip() + elif base == "status": + self.dpkg_status_change(pkgname, status) def wait_child(self): """Wait for child progress to exit. -- cgit v1.2.3 From a3d3b31c936d7c244e7a3874ae6f453f75d5cf58 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 2 Feb 2010 08:39:06 +0100 Subject: apt/progress/base.py: select.error objects do not have an errno attribute (Closes: #568005) --- apt/progress/base.py | 4 ++-- debian/changelog | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/progress/base.py b/apt/progress/base.py index 0c0796d6..6636cccc 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -264,8 +264,8 @@ class InstallProgress(object): while True: try: select.select([self.statusfd], [], [], self.select_timeout) - except select.error, err: - if err.errno != errno.EINTR: + except select.error, (errno_, errstr): + if errno_ != errno.EINTR: raise self.update_interface() diff --git a/debian/changelog b/debian/changelog index 07263fe8..2a10635d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -21,6 +21,8 @@ python-apt (0.7.93.1) UNRELEASED; urgency=low - de.po: Update against new template * python/arfile.cc: - Handle the case where ararchive_new returns NULL in debfile_new. + * apt/progress/base.py: + - select.error objects do not have an errno attribute (Closes: #568005) -- Julian Andres Klode Sat, 23 Jan 2010 15:35:55 +0100 -- cgit v1.2.3 From 972bf036a69f3f41ae5709568e246529b8e40ba5 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 17 Feb 2010 16:45:03 +0100 Subject: * apt/cache.py: - call install_progress.startUpdate()/finishUpdate() to keep compatibility with older code * apt/progress/base.py: - restore "self.statusfd, self.writefd" type, provide additional self.status_pipe and self.write_pipe file like objects --- apt/cache.py | 9 +++++---- apt/progress/base.py | 14 +++++++------- debian/changelog | 9 +++++++++ 3 files changed, 21 insertions(+), 11 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/cache.py b/apt/cache.py index 24d63361..b5733d98 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -328,15 +328,16 @@ class Cache(object): The second parameter *install_progress* refers to an InstallProgress() object of the module apt.progress. """ + # compat with older API try: - install_progress.start_update() - except AttributeError: install_progress.startUpdate() + except AttributeError: + install_progress.start_update() res = install_progress.run(pm) try: - install_progress.finish_update() - except AttributeError: install_progress.finishUpdate() + except AttributeError: + install_progress.finish_update() return res @deprecated_args diff --git a/apt/progress/base.py b/apt/progress/base.py index 6636cccc..ccf618f9 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -139,9 +139,9 @@ class InstallProgress(object): percent, select_timeout, status = 0.0, 0.1, "" def __init__(self): - (read, write) = os.pipe() - self.writefd = os.fdopen(write, "w") - self.statusfd = os.fdopen(read, "r") + (self.statusfd, self.writefd) = os.pipe() + self.write_pipe = os.fdopen(self.writefd, "w") + self.status_pipe = os.fdopen(self.statusfd, "r") fcntl.fcntl(self.statusfd, fcntl.F_SETFL, os.O_NONBLOCK) def start_update(self): @@ -190,10 +190,10 @@ class InstallProgress(object): # and the execution continues in the # parent code leading to very confusing bugs try: - os._exit(obj.do_install(self.writefd.fileno())) + os._exit(obj.do_install(self.write_pipe.fileno())) except AttributeError: os._exit(os.spawnlp(os.P_WAIT, "dpkg", "dpkg", "--status-fd", - str(self.writefd.fileno()), "-i", obj)) + str(self.write_pipe.fileno()), "-i", obj)) except Exception: os._exit(apt_pkg.PackageManager.RESULT_FAILED) @@ -208,7 +208,7 @@ class InstallProgress(object): def update_interface(self): """Update the interface.""" try: - line = self.statusfd.readline() + line = self.status_pipe.readline() except IOError, err: # resource temporarly unavailable is ignored if err.errno != errno.EAGAIN and err.errno != errno.EWOULDBLOCK: @@ -263,7 +263,7 @@ class InstallProgress(object): (pid, res) = (0, 0) while True: try: - select.select([self.statusfd], [], [], self.select_timeout) + select.select([self.status_pipe], [], [], self.select_timeout) except select.error, (errno_, errstr): if errno_ != errno.EINTR: raise diff --git a/debian/changelog b/debian/changelog index 4b93dddc..012a6e1d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,6 @@ python-apt (0.7.93.2) UNRELEASED; urgency=low + [ Julian Andres Klode ] * Fix some places where the old API was still used: - apt/utils.py: Completely ported, previous one was old-API from Ubuntu. - apt/cache.py: Use the new progress classes instead of the old ones. @@ -21,6 +22,14 @@ python-apt (0.7.93.2) UNRELEASED; urgency=low - aptsources/distinfo.py: Support relative filenames for MirrorsFile. * debian/rules: - Run tests during build time. + + [ Michael Vogt ] + * apt/cache.py: + - call install_progress.startUpdate()/finishUpdate() to keep + compatibility with older code + * apt/progress/base.py: + - restore "self.statusfd, self.writefd" type, provide additional + self.status_pipe and self.write_pipe file like objects -- Julian Andres Klode Sun, 07 Feb 2010 19:58:40 +0100 -- cgit v1.2.3 From 178f73f96a3752d492927bd6b8925b7967a0285c Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 17 Feb 2010 16:52:33 +0100 Subject: apt/progress/base.py: call pipe ends {write,status}_stream --- apt/progress/base.py | 12 ++++++------ debian/changelog | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/progress/base.py b/apt/progress/base.py index ccf618f9..88fee206 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -140,8 +140,8 @@ class InstallProgress(object): def __init__(self): (self.statusfd, self.writefd) = os.pipe() - self.write_pipe = os.fdopen(self.writefd, "w") - self.status_pipe = os.fdopen(self.statusfd, "r") + self.write_stream = os.fdopen(self.writefd, "w") + self.status_stream = os.fdopen(self.statusfd, "r") fcntl.fcntl(self.statusfd, fcntl.F_SETFL, os.O_NONBLOCK) def start_update(self): @@ -190,10 +190,10 @@ class InstallProgress(object): # and the execution continues in the # parent code leading to very confusing bugs try: - os._exit(obj.do_install(self.write_pipe.fileno())) + os._exit(obj.do_install(self.write_stream.fileno())) except AttributeError: os._exit(os.spawnlp(os.P_WAIT, "dpkg", "dpkg", "--status-fd", - str(self.write_pipe.fileno()), "-i", obj)) + str(self.write_stream.fileno()), "-i", obj)) except Exception: os._exit(apt_pkg.PackageManager.RESULT_FAILED) @@ -208,7 +208,7 @@ class InstallProgress(object): def update_interface(self): """Update the interface.""" try: - line = self.status_pipe.readline() + line = self.status_stream.readline() except IOError, err: # resource temporarly unavailable is ignored if err.errno != errno.EAGAIN and err.errno != errno.EWOULDBLOCK: @@ -263,7 +263,7 @@ class InstallProgress(object): (pid, res) = (0, 0) while True: try: - select.select([self.status_pipe], [], [], self.select_timeout) + select.select([self.status_stream], [], [], self.select_timeout) except select.error, (errno_, errstr): if errno_ != errno.EINTR: raise diff --git a/debian/changelog b/debian/changelog index 012a6e1d..8c488e0b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -29,7 +29,7 @@ python-apt (0.7.93.2) UNRELEASED; urgency=low compatibility with older code * apt/progress/base.py: - restore "self.statusfd, self.writefd" type, provide additional - self.status_pipe and self.write_pipe file like objects + self.status_stream and self.write_stream file like objects -- Julian Andres Klode Sun, 07 Feb 2010 19:58:40 +0100 -- cgit v1.2.3 From db9e68fd14345f742211fc293823bff6a2f7d8bd Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 17 Feb 2010 18:18:29 +0100 Subject: apt/progress/base.py: more compat fixes --- apt/progress/base.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'apt/progress/base.py') diff --git a/apt/progress/base.py b/apt/progress/base.py index 88fee206..ac6ea011 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -28,6 +28,7 @@ import re import select import apt_pkg +from apt.deprecation import function_deprecated_by __all__ = ['AcquireProgress', 'CdromProgress', 'InstallProgress', 'OpProgress'] @@ -158,6 +159,9 @@ class InstallProgress(object): def status_change(self, pkg, percent, status): """(Abstract) Called when the APT status changed.""" + # compat with 0.7 + if apt_pkg._COMPAT_0_7 and hasattr(self, "statusChange"): + self.statusChange(pkg, percent, status) def dpkg_status_change(self, pkg, status): """(Abstract) Called when the dpkg status changed.""" @@ -222,7 +226,6 @@ class InstallProgress(object): (status, pkgname, percent, status_str) = line.split(":", 3) except ValueError: # silently ignore lines that can't be parsed - self.read = "" return elif line.startswith('status'): try: @@ -281,6 +284,10 @@ class InstallProgress(object): return res + if apt_pkg._COMPAT_0_7: + updateInterface = function_deprecated_by(update_interface) + waitChild = function_deprecated_by(wait_child) + class OpProgress(object): """Monitor objects for operations. -- cgit v1.2.3 From e5237896629a9fc7ba123b6248eff19d6440cf19 Mon Sep 17 00:00:00 2001 From: Michael Vogt Date: Wed, 17 Feb 2010 19:12:19 +0100 Subject: apt/progress/old.py: move compat updateInterface here --- apt/progress/base.py | 4 ---- apt/progress/old.py | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/progress/base.py b/apt/progress/base.py index ac6ea011..8075f790 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -284,10 +284,6 @@ class InstallProgress(object): return res - if apt_pkg._COMPAT_0_7: - updateInterface = function_deprecated_by(update_interface) - waitChild = function_deprecated_by(wait_child) - class OpProgress(object): """Monitor objects for operations. diff --git a/apt/progress/old.py b/apt/progress/old.py index c2d95b85..15ead890 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -191,6 +191,7 @@ class InstallProgress(DumbInstallProgress, base.InstallProgress): selectTimeout = AttributeDeprecatedBy('select_timeout') statusChange = function_deprecated_by(base.InstallProgress.status_change) + updateInterface = function_deprecated_by(base.InstallProgress.update_interface) waitChild = function_deprecated_by(base.InstallProgress.wait_child) -- cgit v1.2.3 From 78e152429187ef145124b0ac0a69ffd1d52f4ed7 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 1 Mar 2010 17:12:09 +0100 Subject: Style fixes. --- apt/cache.py | 27 ++++++++++++++------------- apt/package.py | 1 - apt/progress/base.py | 6 ++++-- apt/progress/old.py | 3 ++- apt/utils.py | 14 ++++++++++---- aptsources/distro.py | 2 ++ doc/source/examples/apt-cdrom.py | 3 ++- doc/source/examples/update-print-uris.py | 1 + 8 files changed, 35 insertions(+), 22 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/cache.py b/apt/cache.py index b5733d98..e8688d64 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -46,12 +46,12 @@ class Cache(object): """Dictionary-like package cache. This class has all the packages that are available in it's - dictionary. + dictionary. Keyword arguments: progress -- a OpProgress object - rootdir -- a alternative root directory. if that is given - the system sources.list and system lists/ files are + rootdir -- a alternative root directory. if that is given + the system sources.list and system lists/ files are not read, only files relative to the given rootdir memonly -- build the cache in memory only """ @@ -95,12 +95,12 @@ class Cache(object): "/var/lib/apt/lists/partial", ] for d in dirs: - if not os.path.exists(rootdir+d): - print "creating: ",rootdir+d - os.makedirs(rootdir+d) + if not os.path.exists(rootdir + d): + print "creating: ", rootdir + d + os.makedirs(rootdir + d) for f in files: - if not os.path.exists(rootdir+f): - open(rootdir+f,"w") + if not os.path.exists(rootdir + f): + open(rootdir + f, "w") def _run_callbacks(self, name): """ internal helper to run a callback """ @@ -125,12 +125,12 @@ class Cache(object): self._weakref.clear() progress.op = _("Building data structures") - i=last=0 - size=len(self._cache.packages) + i = last = 0 + size = len(self._cache.packages) for pkg in self._cache.packages: if progress is not None and last+100 < i: progress.update(i/float(size)*100) - last=i + last = i # drop stuff with no versions (cruft) if len(pkg.version_list) > 0: self._set.add(pkg.name) @@ -376,9 +376,10 @@ class Cache(object): elif res == pm.RESULT_FAILED: raise SystemError("installArchives() failed") elif res == pm.RESULT_INCOMPLETE: - pass + pass else: - raise SystemError("internal-error: unknown result code from InstallArchives: %s" % res) + raise SystemError("internal-error: unknown result code " + "from InstallArchives: %s" % res) # reload the fetcher for media swaping fetcher.shutdown() return (res == pm.RESULT_COMPLETED) diff --git a/apt/package.py b/apt/package.py index 84a1f1e6..6bf9554b 100644 --- a/apt/package.py +++ b/apt/package.py @@ -79,7 +79,6 @@ class BaseDependency(object): def __ne__(self, other): return str.__eq__(self, other) and str.__ne__(2 * self, other) - def __init__(self, name, rel, ver, pre, rawtype=None): self.name = name self.relation = len(rel) == 1 and self.__dstr(rel) or rel diff --git a/apt/progress/base.py b/apt/progress/base.py index 8075f790..d4342de8 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -197,7 +197,8 @@ class InstallProgress(object): os._exit(obj.do_install(self.write_stream.fileno())) except AttributeError: os._exit(os.spawnlp(os.P_WAIT, "dpkg", "dpkg", "--status-fd", - str(self.write_stream.fileno()), "-i", obj)) + str(self.write_stream.fileno()), "-i", + obj)) except Exception: os._exit(apt_pkg.PackageManager.RESULT_FAILED) @@ -266,7 +267,8 @@ class InstallProgress(object): (pid, res) = (0, 0) while True: try: - select.select([self.status_stream], [], [], self.select_timeout) + select.select([self.status_stream], [], [], + self.select_timeout) except select.error, (errno_, errstr): if errno_ != errno.EINTR: raise diff --git a/apt/progress/old.py b/apt/progress/old.py index 15ead890..b2f6f0d5 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -191,7 +191,8 @@ class InstallProgress(DumbInstallProgress, base.InstallProgress): selectTimeout = AttributeDeprecatedBy('select_timeout') statusChange = function_deprecated_by(base.InstallProgress.status_change) - updateInterface = function_deprecated_by(base.InstallProgress.update_interface) + updateInterface = function_deprecated_by( + base.InstallProgress.update_interface) waitChild = function_deprecated_by(base.InstallProgress.wait_child) diff --git a/apt/utils.py b/apt/utils.py index 61d5d54f..dd52f824 100644 --- a/apt/utils.py +++ b/apt/utils.py @@ -17,9 +17,11 @@ # this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -import apt_pkg import os.path +import apt_pkg + + def get_maintenance_end_date(release_date, m_months): """ get the (year, month) tuple when the maintenance for the distribution @@ -28,10 +30,12 @@ def get_maintenance_end_date(release_date, m_months): """ years = m_months / 12 months = m_months % 12 - support_end_year = release_date.year + years + (release_date.month + months)/12 + support_end_year = (release_date.year + years + + (release_date.month + months)/12) support_end_month = (release_date.month + months) % 12 return (support_end_year, support_end_month) + def get_release_date_from_release_file(path): """ return the release date as time_t for the given release file @@ -45,6 +49,7 @@ def get_release_date_from_release_file(path): date = section["Date"] return apt_pkg.str_to_time(date) + def get_release_filename_for_pkg(cache, pkgname, label, release): " get the release file that provides this pkg " if pkgname not in cache: @@ -54,7 +59,7 @@ def get_release_filename_for_pkg(cache, pkgname, label, release): # look for the version that comes from the repos with # the given label and origin for aver in pkg._pkg.version_list: - if aver == None or aver.file_list == None: + if aver is None or aver.file_list is None: continue for ver_file, index in aver.file_list: #print verFile @@ -71,6 +76,7 @@ def get_release_filename_for_pkg(cache, pkgname, label, release): indexfile.describe == m.describe and indexfile.is_trusted): dir = apt_pkg.config.find_dir("Dir::State::lists") - name = apt_pkg.uri_to_filename(metaindex.uri)+"dists_%s_Release" % metaindex.dist + name = (apt_pkg.uri_to_filename(metaindex.uri) + + "dists_%s_Release" % metaindex.dist) return dir+name return None diff --git a/aptsources/distro.py b/aptsources/distro.py index 1e60a0ed..e51fbe9f 100644 --- a/aptsources/distro.py +++ b/aptsources/distro.py @@ -437,6 +437,7 @@ class UbuntuDistribution(Distribution): Distribution.get_mirrors( self, mirror_template="http://%s.archive.ubuntu.com/ubuntu/") + def _lsb_release(): """Call lsb_release --idrc and return a mapping.""" from subprocess import Popen, PIPE @@ -454,6 +455,7 @@ def _lsb_release(): print 'WARNING: lsb_release failed, using defaults:', exc return result + def get_distro(id=None, codename=None, description=None, release=None): """ Check the currently used distribution and return the corresponding diff --git a/doc/source/examples/apt-cdrom.py b/doc/source/examples/apt-cdrom.py index a20b0f12..cb23e97d 100644 --- a/doc/source/examples/apt-cdrom.py +++ b/doc/source/examples/apt-cdrom.py @@ -30,7 +30,8 @@ def show_help(): " -f Fast mode, don't check package files\n" " -a Thorough scan mode\n" " -c=? Read this configuration file\n" - " -o=? Set an arbitrary configuration option, eg -o dir::cache=/tmp\n" + " -o=? Set an arbitrary configuration option, eg -o " + "dir::cache=/tmp\n" "See fstab(5)") return 0 diff --git a/doc/source/examples/update-print-uris.py b/doc/source/examples/update-print-uris.py index f078cdc5..dbe1dfde 100644 --- a/doc/source/examples/update-print-uris.py +++ b/doc/source/examples/update-print-uris.py @@ -4,6 +4,7 @@ This behaves somewhat like apt-get --print-uris update.""" import apt_pkg + def main(): apt_pkg.init_config() apt_pkg.init_system() -- cgit v1.2.3 From a8dda6d93b07b7226a3aa41baa50ca059674566e Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Mon, 1 Mar 2010 17:48:06 +0100 Subject: Some stylistic changes. --- apt/cache.py | 10 +++++++--- apt/debfile.py | 22 +++++++++++----------- apt/progress/base.py | 9 +++------ apt/progress/gtk2.py | 1 + apt/progress/old.py | 10 ++++++++++ apt/utils.py | 6 +++--- 6 files changed, 35 insertions(+), 23 deletions(-) (limited to 'apt/progress/base.py') diff --git a/apt/cache.py b/apt/cache.py index e8688d64..2e6d24e5 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -57,6 +57,10 @@ class Cache(object): """ def __init__(self, progress=None, rootdir=None, memonly=False): + self._cache = None + self._depcache = None + self._records = None + self._list = None self._callbacks = {} self._weakref = weakref.WeakValueDictionary() self._set = set() @@ -624,9 +628,9 @@ def _test(): # see if fetching works - for dir in ["/tmp/pytest", "/tmp/pytest/partial"]: - if not os.path.exists(dir): - os.mkdir(dir) + for dirname in ["/tmp/pytest", "/tmp/pytest/partial"]: + if not os.path.exists(dirname): + os.mkdir(dirname) apt_pkg.config.set("Dir::Cache::Archives", "/tmp/pytest") pm = apt_pkg.PackageManager(cache._depcache) fetcher = apt_pkg.Acquire(apt.progress.text.AcquireProgress()) diff --git a/apt/debfile.py b/apt/debfile.py index e27917d5..ccaa25e4 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -43,6 +43,9 @@ class DebPackage(object): def __init__(self, filename=None, cache=None): self._cache = cache self._need_pkgs = [] + self._debfile = None + self.pkgname = "" + self.filename = filename self._sections = {} self._installed_conflicts = set() self._failure_string = "" @@ -168,9 +171,6 @@ class DebPackage(object): """Check the or-group for conflicts with installed pkgs.""" self._dbg(2, "_check_conflicts_or_group(): %s " % (or_group)) - or_found = False - virtual_pkg = None - for dep in or_group: depname = dep[0] ver = dep[1] @@ -287,13 +287,13 @@ class DebPackage(object): else: cachever = self._cache[pkgname].candidate.version if cachever is not None: - cmp = apt_pkg.version_compare(cachever, debver) - self._dbg(1, "CompareVersion(debver,instver): %s" % cmp) - if cmp == 0: + cmpres = apt_pkg.version_compare(cachever, debver) + self._dbg(1, "CompareVersion(debver,instver): %s" % cmpres) + if cmpres == 0: return VERSION_SAME - elif cmp < 0: + elif cmpres < 0: return VERSION_NEWER - elif cmp > 0: + elif cmpres > 0: return VERSION_OUTDATED return VERSION_NONE @@ -361,7 +361,7 @@ class DebPackage(object): for pkg in self._need_pkgs: try: self._cache[pkg].mark_install(fromUser=False) - except SystemError, e: + except SystemError: self._failure_string = _("Cannot install '%s'" % pkg) self._cache.clear() return False @@ -427,7 +427,8 @@ class DscSrcPackage(DebPackage): DebPackage.__init__(self, None, cache) self._depends = [] self._conflicts = [] - self._binaries = [] + self.pkgname = "" + self.binaries = [] if filename is not None: self.open(filename) @@ -465,7 +466,6 @@ class DscSrcPackage(DebPackage): if 'Version' in sec: self._sections['Version'] = sec['Version'] finally: - del sec del tagfile fobj.close() diff --git a/apt/progress/base.py b/apt/progress/base.py index d4342de8..6822b74a 100644 --- a/apt/progress/base.py +++ b/apt/progress/base.py @@ -16,6 +16,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA +# pylint: disable-msg = R0201 """Base classes for progress reporting. Custom progress classes should inherit from these classes. They can also be @@ -28,7 +29,6 @@ import re import select import apt_pkg -from apt.deprecation import function_deprecated_by __all__ = ['AcquireProgress', 'CdromProgress', 'InstallProgress', 'OpProgress'] @@ -137,7 +137,7 @@ class CdromProgress(object): class InstallProgress(object): """Class to report the progress of installing packages.""" - percent, select_timeout, status = 0.0, 0.1, "" + child_pid, percent, select_timeout, status = 0, 0.0, 0.1, "" def __init__(self): (self.statusfd, self.writefd) = os.pipe() @@ -159,9 +159,6 @@ class InstallProgress(object): def status_change(self, pkg, percent, status): """(Abstract) Called when the APT status changed.""" - # compat with 0.7 - if apt_pkg._COMPAT_0_7 and hasattr(self, "statusChange"): - self.statusChange(pkg, percent, status) def dpkg_status_change(self, pkg, status): """(Abstract) Called when the dpkg status changed.""" @@ -269,7 +266,7 @@ class InstallProgress(object): try: select.select([self.status_stream], [], [], self.select_timeout) - except select.error, (errno_, errstr): + except select.error, (errno_, _errstr): if errno_ != errno.EINTR: raise diff --git a/apt/progress/gtk2.py b/apt/progress/gtk2.py index 29e730a3..acb01eed 100644 --- a/apt/progress/gtk2.py +++ b/apt/progress/gtk2.py @@ -124,6 +124,7 @@ class GInstallProgress(gobject.GObject, base.InstallProgress): base.InstallProgress.__init__(self) gobject.GObject.__init__(self) self.finished = False + self.apt_status = -1 self.time_last_update = time.time() self.term = term reaper = vte.reaper_get() diff --git a/apt/progress/old.py b/apt/progress/old.py index b2f6f0d5..c64eee57 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -18,6 +18,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA +# pylint: disable-msg = C0103 """Deprecated progress reporting classes. This module provides classes for compatibility with python-apt 0.7. They are @@ -195,10 +196,19 @@ class InstallProgress(DumbInstallProgress, base.InstallProgress): base.InstallProgress.update_interface) waitChild = function_deprecated_by(base.InstallProgress.wait_child) + def status_change(self, pkg, percent, status): + """(Abstract) Called when the APT status changed.""" + # compat with 0.7 + if apt_pkg._COMPAT_0_7 and hasattr(self, "statusChange"): + self.statusChange(pkg, percent, status) + class DpkgInstallProgress(InstallProgress): """Progress handler for a local Debian package installation.""" + debfile = "" + debname = "" + def run(self, debfile): """Start installing the given Debian package.""" # Deprecated stuff diff --git a/apt/utils.py b/apt/utils.py index dd52f824..80ba6d65 100644 --- a/apt/utils.py +++ b/apt/utils.py @@ -61,7 +61,7 @@ def get_release_filename_for_pkg(cache, pkgname, label, release): for aver in pkg._pkg.version_list: if aver is None or aver.file_list is None: continue - for ver_file, index in aver.file_list: + for ver_file, _index in aver.file_list: #print verFile if (ver_file.origin == label and ver_file.label == label and @@ -75,8 +75,8 @@ def get_release_filename_for_pkg(cache, pkgname, label, release): if (indexfile and indexfile.describe == m.describe and indexfile.is_trusted): - dir = apt_pkg.config.find_dir("Dir::State::lists") + dirname = apt_pkg.config.find_dir("Dir::State::lists") name = (apt_pkg.uri_to_filename(metaindex.uri) + "dists_%s_Release" % metaindex.dist) - return dir+name + return dirname + name return None -- cgit v1.2.3