From 51f0b08149c39dc76664e1758aa0d71701920bd7 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 16 Jul 2009 19:50:18 +0200 Subject: apt/progress: Move apt.progress to apt.progress.old --- apt/progress/old.py | 426 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 426 insertions(+) create mode 100644 apt/progress/old.py (limited to 'apt/progress/old.py') diff --git a/apt/progress/old.py b/apt/progress/old.py new file mode 100644 index 00000000..3c5d4588 --- /dev/null +++ b/apt/progress/old.py @@ -0,0 +1,426 @@ +# progress.py - progress reporting classes +# +# Copyright (c) 2005-2009 Canonical +# +# Author: Michael Vogt +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +"""progress reporting classes. + +This module provides classes for progress reporting. They can be used with +e.g., for reporting progress on the cache opening process, the cache update +progress, or the package install progress. +""" + +import errno +import fcntl +import os +import re +import select +import sys + +import apt_pkg +from apt.deprecation import AttributeDeprecatedBy, function_deprecated_by + + +__all__ = ('CdromProgress', 'DpkgInstallProgress', 'DumbInstallProgress', + 'FetchProgress', 'InstallProgress', 'OpProgress', 'OpTextProgress', + 'TextFetchProgress') + + +class OpProgress(object): + """Abstract class to implement reporting on cache opening. + + Subclass this class to implement simple Operation progress reporting. + """ + + def __init__(self): + self.op = None + self.sub_op = None + + def update(self, percent): + """Called periodically to update the user interface.""" + + def done(self): + """Called once an operation has been completed.""" + + if apt_pkg._COMPAT_0_7: + subOp = AttributeDeprecatedBy('sub_op') + + +class OpTextProgress(OpProgress): + """A simple text based cache open reporting class.""" + + def __init__(self): + OpProgress.__init__(self) + + def update(self, percent): + """Called periodically to update the user interface.""" + sys.stdout.write("\r%s: %.2i " % (self.sub_op, percent)) + sys.stdout.flush() + + def done(self): + """Called once an operation has been completed.""" + sys.stdout.write("\r%s: Done\n" % self.op) + + +class FetchProgress(object): + """Report the download/fetching progress. + + Subclass this class to implement fetch progress reporting + """ + + # download status constants + 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"} + + 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 + + def start(self): + """Called when the fetching starts.""" + + def stop(self): + """Called when all files have been fetched.""" + + def update_status(self, uri, descr, short_descr, status): + """Called when the status of an item changes. + + This happens eg. when the downloads fails or is completed. + """ + + def update_status_full(self, uri, descr, short_descr, status, file_size, + partial_size): + """Called when the status of an item changes. + + This happens eg. when the downloads fails or is completed. This + version include information on current filesize and partial size + """ + + def pulse(self): + """Called periodically to update the user interface. + + 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)) + return True + + def pulse_items(self, items): + """Called periodically to update the user interface. + This function includes details about the items being fetched + 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)) + return True + + def media_change(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 """ + + def __init__(self): + FetchProgress.__init__(self) + self.items = {} + + def update_status(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) + self.items[uri] = status + + def pulse(self): + """Called periodically to update the user interface. + + Return True to continue or False to cancel. + """ + FetchProgress.pulse(self) + if self.current_cps > 0: + s = "[%2.f%%] %sB/s %s" % (self.percent, + apt_pkg.size_to_str(int(self.current_cps)), + apt_pkg.time_to_str(int(self.eta))) + else: + s = "%2.f%% [Working]" % (self.percent) + print "\r%s" % (s), + sys.stdout.flush() + return True + + def stop(self): + """Called when all files have been fetched.""" + print "\rDone downloading " + + def media_change(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 DumbInstallProgress(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""" + + if apt_pkg._COMPAT_0_7: + startUpdate = function_deprecated_by(start_update) + finishUpdate = function_deprecated_by(finish_update) + updateInterface = function_deprecated_by(update_interface) + + +class InstallProgress(DumbInstallProgress): + """An InstallProgress that is pretty useful. + + It supports the attributes 'percent' 'status' and callbacks for the dpkg + errors and conffiles and status changes. + """ + + def __init__(self): + DumbInstallProgress.__init__(self) + self.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, e: + if e[0] != errno.EINTR: + raise + + self.update_interface() + (pid, res) = os.waitpid(self.child_pid, os.WNOHANG) + if pid == self.child_pid: + break + return res + + def run(self, pm): + """Start installing.""" + pid = self.fork() + if pid == 0: + # child + res = pm.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(object): + """Report the cdrom add progress. + + Subclass this class to implement cdrom add progress reporting. + """ + + def __init__(self): + pass + + def update(self, text, step): + """Called periodically to update the user interface.""" + + def ask_cdrom_name(self): + """Called to ask for the name of the cdrom.""" + + def change_cdrom(self): + """Called to ask for the cdrom to be changed.""" + + if apt_pkg._COMPAT_0_7: + askCdromName = function_deprecated_by(ask_cdrom_name) + changeCdrom = function_deprecated_by(change_cdrom) + + +class DpkgInstallProgress(InstallProgress): + """Progress handler for a local Debian package installation.""" + + 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) -- cgit v1.2.3 From 837e2fd927906c229801e41a5effbf95f9c6a106 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 17 Jul 2009 16:14:56 +0200 Subject: apt/progress: Fix apt.progress with COMPAT_0_7 --- apt/progress/__init__.py | 13 ++++--------- apt/progress/old.py | 6 ++---- 2 files changed, 6 insertions(+), 13 deletions(-) (limited to 'apt/progress/old.py') diff --git a/apt/progress/__init__.py b/apt/progress/__init__.py index 67880903..c75c368b 100644 --- a/apt/progress/__init__.py +++ b/apt/progress/__init__.py @@ -17,13 +17,8 @@ """Progress reporting.""" import apt_pkg -#from apt.progress.text import AcquireProgress as TextAcquireProgress -#from apt.progress.text import OpProgress as TextOpProgress - -__all__ = [] #'TextAcquireProgress', 'TextOpProgress'] - if apt_pkg._COMPAT_0_7: - import apt.progress.old - from apt.progress.old import * - - __all__ += apt.progress.old.__all__ + from apt.progress.old import (CdromProgress, DpkgInstallProgress, + DumbInstallProgress, FetchProgress, + InstallProgress, OpProgress, + OpTextProgress, TextFetchProgress) diff --git a/apt/progress/old.py b/apt/progress/old.py index 3c5d4588..d4ff5815 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -18,7 +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 -"""progress reporting classes. +"""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 @@ -36,9 +36,7 @@ import apt_pkg from apt.deprecation import AttributeDeprecatedBy, function_deprecated_by -__all__ = ('CdromProgress', 'DpkgInstallProgress', 'DumbInstallProgress', - 'FetchProgress', 'InstallProgress', 'OpProgress', 'OpTextProgress', - 'TextFetchProgress') +__all__ = [] class OpProgress(object): -- cgit v1.2.3 From 5c219e07aea347f652cf7949dc74f37282a17144 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 19 Jul 2009 14:39:41 +0200 Subject: python/cdromprogress.cc: Add apt_pkg.CdromProgress. --- apt/progress/old.py | 22 ++-------- python/apt_pkgmodule.cc | 1 + python/apt_pkgmodule.h | 1 + python/cdrom.cc | 11 +++++ python/cdromprogress.cc | 106 ++++++++++++++++++++++++++++++++++++++++++++++++ python/progress.cc | 12 ++++-- python/progress.h | 6 +++ 7 files changed, 137 insertions(+), 22 deletions(-) create mode 100644 python/cdromprogress.cc (limited to 'apt/progress/old.py') diff --git a/apt/progress/old.py b/apt/progress/old.py index d4ff5815..63fc5d2e 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -343,27 +343,13 @@ class InstallProgress(DumbInstallProgress): updateInterface = function_deprecated_by(update_interface) -class CdromProgress(object): +class CdromProgress(apt_pkg.CdromProgress): """Report the cdrom add progress. - Subclass this class to implement cdrom add progress reporting. + This class has been replaced by apt_pkg.CdromProgress. """ - - def __init__(self): - pass - - def update(self, text, step): - """Called periodically to update the user interface.""" - - def ask_cdrom_name(self): - """Called to ask for the name of the cdrom.""" - - def change_cdrom(self): - """Called to ask for the cdrom to be changed.""" - - if apt_pkg._COMPAT_0_7: - askCdromName = function_deprecated_by(ask_cdrom_name) - changeCdrom = function_deprecated_by(change_cdrom) + askCdromName = function_deprecated_by(apt_pkg.CdromProgress.ask_cdrom_name) + changeCdrom = function_deprecated_by(apt_pkg.CdromProgress.change_cdrom) class DpkgInstallProgress(InstallProgress): diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc index d6b8e3d1..b6ae709e 100644 --- a/python/apt_pkgmodule.cc +++ b/python/apt_pkgmodule.cc @@ -651,6 +651,7 @@ extern "C" void initapt_pkg() ADDTYPE(Module,"OpProgress",&PyOpProgress_Type); ADDTYPE(Module,"AcquireProgress",&PyAcquireProgress_Type); ADDTYPE(Module,"AcquireItemDesc",&PyAcquireItemDesc_Type); + ADDTYPE(Module,"CdromProgress",&PyCdromProgress_Type); // Tag file constants PyModule_AddObject(Module,"REWRITE_PACKAGE_ORDER", CharCharToList(TFRewritePackageOrder)); diff --git a/python/apt_pkgmodule.h b/python/apt_pkgmodule.h index ad1fe9fe..1277ab60 100644 --- a/python/apt_pkgmodule.h +++ b/python/apt_pkgmodule.h @@ -114,6 +114,7 @@ extern PyTypeObject PyPolicy_Type; extern PyTypeObject PyHashes_Type; extern PyTypeObject PyOpProgress_Type; extern PyTypeObject PyAcquireProgress_Type; +extern PyTypeObject PyCdromProgress_Type; extern PyTypeObject PyAcquireItemDesc_Type; extern PyTypeObject PyAcquireWorker_Type; #include "python-apt.h" diff --git a/python/cdrom.cc b/python/cdrom.cc index 50d1b4b1..6ee3becd 100644 --- a/python/cdrom.cc +++ b/python/cdrom.cc @@ -34,9 +34,20 @@ static PyObject *PkgCdromIdent(PyObject *Self,PyObject *Args) pkgCdrom &Cdrom = GetCpp(Self); PyObject *pyCdromProgressInst = 0; +#ifdef COMPAT_0_7 if (PyArg_ParseTuple(Args, "O", &pyCdromProgressInst) == 0) { +#else + if (PyArg_ParseTuple(Args, "O!", &PyCdromProgress_Type, + &pyCdromProgressInst) == 0) { +#endif return 0; } +#ifdef COMPAT_0_7 + if (!PyObject_TypeCheck(pyCdromProgressInst, &PyCdromProgress_Type)) { + PyErr_WarnEx(PyExc_DeprecationWarning, "Argument should be a subclass of" + " apt_pkg.CdromProgress.", 1); + } +#endif PyCdromProgress progress; progress.setCallbackInst(pyCdromProgressInst); diff --git a/python/cdromprogress.cc b/python/cdromprogress.cc new file mode 100644 index 00000000..09c76a2a --- /dev/null +++ b/python/cdromprogress.cc @@ -0,0 +1,106 @@ +/* cdromprogress.cc - Base class for CdromProgress classes. + * + * Copyright 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include "apt_pkgmodule.h" +#include "progress.h" +#include +#include + +// Takes two arguments (string, int) +static PyObject *cdromprogress_update(PyObject *self, PyObject *args) +{ + Py_RETURN_NONE; +} + +// Takes no arguments +static PyObject *cdromprogress_change_cdrom(PyObject *self, PyObject *args) +{ + Py_RETURN_FALSE; +} + +// Takes a single PyObject argument as *arg +static PyObject *cdromprogress_ask_cdrom_name(PyObject *self, PyObject *arg) +{ + Py_RETURN_FALSE; +} + +static PyMethodDef cdromprogress_methods[] = { + {"update",cdromprogress_update,METH_VARARGS, + "update(text: str, current: int)\n\nCalled regularly."}, + {"change_cdrom",cdromprogress_change_cdrom,METH_NOARGS, + "change_cdrom() -> bool\n\nAsk for the CD-ROM to be changed.\n" + "Return False if the user requested to cancel the action (default)."}, + {"ask_cdrom_name",cdromprogress_ask_cdrom_name,METH_O, + "ask_cdrom_name(name: str) -> bool\n\nAsk for the name of the CD-ROM.\n" + "Return False if the user requested to cancel the action (default)."}, + {NULL} +}; + +static PyMemberDef cdromprogress_members[] = { + {"total_steps", T_INT, offsetof(PyCdromProgressObject,total_steps), 0, + "The number of total steps to be taken."}, + {NULL} +}; + +static char *cdromprogress_doc = "CdromProgress()\n\n" + "Base class for reporting the progress of adding a cdrom. Can be used\n" + "with apt_pkg.Cdrom to produce an utility like apt-cdrom."; + +PyTypeObject PyCdromProgress_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.CdromProgress", // tp_name + sizeof(PyCdromProgressObject), // tp_basicsize + 0, // tp_itemsize + // Methods + 0, // tp_dealloc + 0, // tp_print + 0, // 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 + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE, + cdromprogress_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + cdromprogress_methods, // tp_methods + cdromprogress_members, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PyType_GenericNew, // tp_new +}; diff --git a/python/progress.cc b/python/progress.cc index 123a1805..b19ab0c7 100644 --- a/python/progress.cc +++ b/python/progress.cc @@ -518,10 +518,14 @@ 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); - Py_XDECREF(o); + if (PyObject_TypeCheck(callbackInst, &PyCdromProgress_Type)) { + ((PyCdromProgressObject *)callbackInst)->total_steps = totalSteps; + } + else { + PyObject *o = Py_BuildValue("i", totalSteps); + PyObject_SetAttrString(callbackInst, "totalSteps", o); + Py_XDECREF(o); + } RunSimpleCallback("update", arglist); } diff --git a/python/progress.h b/python/progress.h index e21a5c5a..88bd3552 100644 --- a/python/progress.h +++ b/python/progress.h @@ -28,6 +28,12 @@ typedef struct { float percent; } PyOpProgressObject; + +typedef struct { + PyObject_HEAD + int total_steps; +} PyCdromProgressObject; + typedef struct { PyObject_HEAD double last_bytes; -- cgit v1.2.3 From e784c6d89265337decb35cd587e4281228d625f0 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 21 Jul 2009 21:55:02 +0200 Subject: apt/progress/old.py: Replace OpProgress.sub_op with OpProgress.subop. --- apt/progress/old.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'apt/progress/old.py') diff --git a/apt/progress/old.py b/apt/progress/old.py index 63fc5d2e..05597481 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -47,7 +47,7 @@ class OpProgress(object): def __init__(self): self.op = None - self.sub_op = None + self.subop = None def update(self, percent): """Called periodically to update the user interface.""" @@ -56,7 +56,7 @@ class OpProgress(object): """Called once an operation has been completed.""" if apt_pkg._COMPAT_0_7: - subOp = AttributeDeprecatedBy('sub_op') + subOp = AttributeDeprecatedBy('subop') class OpTextProgress(OpProgress): @@ -67,7 +67,7 @@ class OpTextProgress(OpProgress): def update(self, percent): """Called periodically to update the user interface.""" - sys.stdout.write("\r%s: %.2i " % (self.sub_op, percent)) + sys.stdout.write("\r%s: %.2i " % (self.subop, percent)) sys.stdout.flush() def done(self): -- cgit v1.2.3 From fb8e639a7199a5707ae24c8424e5dc748fe0be37 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 31 Jul 2009 15:24:09 +0200 Subject: python: Remove the progress classes in apt_pkg. They have been replaced with apt.progress.base, so stuff like GTK+ or Qt progress classes can be written using subclassing. --- apt/cache.py | 6 +- apt/cdrom.py | 3 +- apt/progress/old.py | 28 +++---- apt/progress/text.py | 36 ++++---- python/acquireprogress.cc | 208 ---------------------------------------------- python/apt_pkgmodule.cc | 3 - python/apt_pkgmodule.h | 3 - python/cache.cc | 6 -- python/cdrom.cc | 3 +- python/cdromprogress.cc | 106 ----------------------- python/opprogress.cc | 175 -------------------------------------- python/progress.h | 32 ------- setup.py | 5 +- 13 files changed, 36 insertions(+), 578 deletions(-) delete mode 100644 python/acquireprogress.cc delete mode 100644 python/cdromprogress.cc delete mode 100644 python/opprogress.cc (limited to 'apt/progress/old.py') diff --git a/apt/cache.py b/apt/cache.py index f507863c..ae4254e0 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -122,11 +122,7 @@ class Cache(object): size=len(self._cache.packages) for pkg in self._cache.packages: if progress is not None and last+100 < i: - if isinstance(progress, apt_pkg.OpProgress): - progress.percent = i/float(size)*100 - progress.update() - else: - progress.update(i/float(size)*100) + progress.update(i/float(size)*100) last=i # drop stuff with no versions (cruft) if len(pkg.version_list) > 0: diff --git a/apt/cdrom.py b/apt/cdrom.py index 126c54dd..01caa12f 100644 --- a/apt/cdrom.py +++ b/apt/cdrom.py @@ -24,6 +24,7 @@ import glob import apt_pkg from apt.deprecation import AttributeDeprecatedBy +from apt.progress.base import CdromProgress class Cdrom(apt_pkg.Cdrom): @@ -46,7 +47,7 @@ class Cdrom(apt_pkg.Cdrom): def __init__(self, progress=None, mountpoint=None, nomount=True): apt_pkg.Cdrom.__init__(self) if progress is None: - self._progress = apt_pkg.CdromProgress() + self._progress = CdromProgress() else: self._progress = progress # see if we have a alternative mountpoint diff --git a/apt/progress/old.py b/apt/progress/old.py index 88957272..adaf94b2 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -34,29 +34,21 @@ import sys import apt_pkg from apt.deprecation import AttributeDeprecatedBy, function_deprecated_by +from apt.progress import base __all__ = [] -class OpProgress(object): +class OpProgress(base.OpProgress): """Abstract class to implement reporting on cache opening. Subclass this class to implement simple Operation progress reporting. """ - def __init__(self): - self.op = None - self.subop = None - - def update(self, percent): - """Called periodically to update the user interface.""" - - def done(self): - """Called once an operation has been completed.""" - if apt_pkg._COMPAT_0_7: subOp = AttributeDeprecatedBy('subop') + Op = AttributeDeprecatedBy('op') class OpTextProgress(OpProgress): @@ -65,13 +57,15 @@ class OpTextProgress(OpProgress): def __init__(self): OpProgress.__init__(self) - def update(self, percent): + def update(self, percent=None): """Called periodically to update the user interface.""" - sys.stdout.write("\r%s: %.2i " % (self.subop, percent)) + OpProgress.update(self, percent) + sys.stdout.write("\r%s: %.2i " % (self.subop, self.percent)) sys.stdout.flush() def done(self): """Called once an operation has been completed.""" + OpProgress.done(self) sys.stdout.write("\r%s: Done\n" % self.op) @@ -349,13 +343,15 @@ class InstallProgress(DumbInstallProgress): updateInterface = function_deprecated_by(update_interface) -class CdromProgress(apt_pkg.CdromProgress): +class CdromProgress(base.CdromProgress): """Report the cdrom add progress. This class has been replaced by apt_pkg.CdromProgress. """ - askCdromName = function_deprecated_by(apt_pkg.CdromProgress.ask_cdrom_name) - changeCdrom = function_deprecated_by(apt_pkg.CdromProgress.change_cdrom) + _basetype = base.CdromProgress + askCdromName = function_deprecated_by(_basetype.ask_cdrom_name) + changeCdrom = function_deprecated_by(_basetype.change_cdrom) + del _basetype class DpkgInstallProgress(InstallProgress): diff --git a/apt/progress/text.py b/apt/progress/text.py index 54a35704..eb474d6d 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -18,7 +18,7 @@ import sys import apt_pkg -import apt.progress.base +from apt.progress import base __all__ = ['AcquireProgress', 'CdromProgress', 'OpProgress'] @@ -55,7 +55,7 @@ class TextProgress(object): self._file.flush() -class OpProgress(apt.progress.base.OpProgress, TextProgress): +class OpProgress(base.OpProgress, TextProgress): """Operation progress reporting. This closely resembles OpTextProgress in libapt-pkg. @@ -63,12 +63,12 @@ class OpProgress(apt.progress.base.OpProgress, TextProgress): def __init__(self, outfile=None): TextProgress.__init__(self, outfile) - apt.progress.base.OpProgress.__init__(self) + base.OpProgress.__init__(self) self.old_op = "" def update(self, percent=None): """Called periodically to update the user interface.""" - apt.progress.base.OpProgress.update(self, percent) + base.OpProgress.update(self, percent) if self.major_change and self.old_op: self._write(self.old_op) self._write("%s... %i%%\r" % (self.op, self.percent), False, True) @@ -76,18 +76,18 @@ class OpProgress(apt.progress.base.OpProgress, TextProgress): def done(self): """Called once an operation has been completed.""" - apt.progress.base.OpProgress.done(self) + base.OpProgress.done(self) if self.old_op: self._write(_("%c%s... Done") % ('\r', self.old_op), True, True) self.old_op = "" -class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): +class AcquireProgress(base.AcquireProgress, TextProgress): """AcquireProgress for the text interface.""" def __init__(self, outfile=None): TextProgress.__init__(self, outfile) - apt.progress.base.AcquireProgress.__init__(self) + base.AcquireProgress.__init__(self) self._signal = None self._width = 80 self._id = 1 @@ -98,7 +98,7 @@ class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): In this case, the function sets up a signal handler for SIGWINCH, i.e. window resize signals. And it also sets id to 1. """ - apt.progress.base.AcquireProgress.start(self) + base.AcquireProgress.start(self) import signal self._signal = signal.signal(signal.SIGWINCH, self._winch) # Get the window size. @@ -116,7 +116,7 @@ class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): def ims_hit(self, item): """Called when an item is update (e.g. not modified on the server).""" - apt.progress.base.AcquireProgress.ims_hit(self, item) + base.AcquireProgress.ims_hit(self, item) line = _('Hit ') + item.description if item.owner.filesize: line += ' [%sB]' % apt_pkg.size_to_str(item.owner.filesize) @@ -124,7 +124,7 @@ class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): def fail(self, item): """Called when an item is failed.""" - apt.progress.base.AcquireProgress.fail(self, item) + base.AcquireProgress.fail(self, item) if item.owner.status == item.owner.stat_done: self._write(_("Ign ") + item.description) else: @@ -133,7 +133,7 @@ class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): def fetch(self, item): """Called when some of the item's data is fetched.""" - apt.progress.base.AcquireProgress.fetch(self, item) + base.AcquireProgress.fetch(self, item) # It's complete already (e.g. Hit) if item.owner.complete: return @@ -149,7 +149,7 @@ class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): """Periodically invoked while the Acquire process is underway. Return False if the user asked to cancel the whole Acquire process.""" - apt.progress.base.AcquireProgress.pulse(self, owner) + base.AcquireProgress.pulse(self, owner) percent = (((self.current_bytes + self.current_items) * 100.0) / float(self.total_bytes + self.total_items)) @@ -209,7 +209,7 @@ class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): def media_change(self, medium, drive): """Prompt the user to change the inserted removable media.""" - apt.progress.base.AcquireProgress.media_change(self, medium, drive) + base.AcquireProgress.media_change(self, medium, drive) self._write(_("Media change: please insert the disc labeled\n" " '%s'\n" "in the drive '%s' and press enter\n") % (medium, drive)) @@ -217,7 +217,7 @@ class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): def stop(self): """Invoked when the Acquire process stops running.""" - apt.progress.base.AcquireProgress.stop(self) + base.AcquireProgress.stop(self) # Trick for getting a translation from apt self._write((_("Fetched %sB in %s (%sB/s)\n") % ( apt_pkg.size_to_str(self.fetched_bytes), @@ -229,12 +229,12 @@ class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): signal.signal(signal.SIGWINCH, self._signal) -class CdromProgress(apt.progress.base.CdromProgress, TextProgress): +class CdromProgress(base.CdromProgress, TextProgress): """Text CD-ROM progress.""" def ask_cdrom_name(self): """Ask the user to provide a name for the disc.""" - apt.progress.base.CdromProgress.ask_cdrom_name(self) + base.CdromProgress.ask_cdrom_name(self) self._write(_("Please provide a name for this Disc, such as " "'Debian 2.1r1 Disk 1'"), False) try: @@ -244,13 +244,13 @@ class CdromProgress(apt.progress.base.CdromProgress, TextProgress): def update(self, text, current): """Set the current progress.""" - apt.progress.base.CdromProgress.update(self, text, current) + base.CdromProgress.update(self, text, current) if text: self._write(text, False) def change_cdrom(self): """Ask the user to change the CD-ROM.""" - apt.progress.base.CdromProgress.change_cdrom(self) + base.CdromProgress.change_cdrom(self) self._write(_("Please insert a Disc in the drive and press enter"), False) try: diff --git a/python/acquireprogress.cc b/python/acquireprogress.cc deleted file mode 100644 index c7db8921..00000000 --- a/python/acquireprogress.cc +++ /dev/null @@ -1,208 +0,0 @@ -/* acquireprogress.cc - Base class for FetchProgress classes. - * - * Copyright 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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include "apt_pkgmodule.h" -#include "progress.h" -#include -#include - - - -// DUMMY IMPLEMENTATIONS. -static char *acquireprogress_media_change_doc = - "media_change(media: str, drive: str) -> bool\n\n" - "Invoked when the user should be prompted to change the inserted\n" - "removable media.\n\n" - "This method should not return until the user has confirmed to the user\n" - "interface that the media change is complete.\n\n" - ":param:media The name of the media type that should be changed.\n" - ":param:drive The identifying name of the drive whose media should be\n" - " changed.\n\n" - "Return True if the user confirms the media change, False if it is\n" - "cancelled."; -static PyObject *acquireprogress_media_change(PyObject *self, PyObject *args) -{ - Py_RETURN_FALSE; -} - -static char *acquireprogress_ims_hit_doc = "ims_hit(item: AcquireItemDesc)\n\n" - "Invoked when an item is confirmed to be up-to-date. For instance,\n" - "when an HTTP download is informed that the file on the server was\n" - "not modified."; -static PyObject *acquireprogress_ims_hit(PyObject *self, PyObject *arg) -{ - if (!PyAcquireItemDesc_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "ims_hit() argument must be " - "apt_pkg.AcquireItemDesc"); - return 0; - } - Py_RETURN_NONE; -} - -static char *acquireprogress_fetch_doc = "fetch(item: AcquireItemDesc)\n\n" - "Invoked when some of an item's data is fetched."; -static PyObject *acquireprogress_fetch(PyObject *self, PyObject *arg) -{ - if (!PyAcquireItemDesc_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "fetch() argument must be " - "apt_pkg.AcquireItemDesc"); - return 0; - } - Py_RETURN_NONE; -} - -static char *acquireprogress_done_doc = "done(item: AcquireItemDesc)\n\n" - "Invoked when an item is successfully and completely fetched."; -static PyObject *acquireprogress_done(PyObject *self, PyObject *arg) -{ - if (!PyAcquireItemDesc_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "done() argument must be " - "apt_pkg.AcquireItemDesc"); - return 0; - } - Py_RETURN_NONE; -} - -static char *acquireprogress_fail_doc = "fail(item: AcquireItemDesc)\n\n" - "Invoked when the process of fetching an item encounters a fatal error."; -static PyObject *acquireprogress_fail(PyObject *self, PyObject *arg) -{ - if (!PyAcquireItemDesc_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "fail() argument must be " - "apt_pkg.AcquireItemDesc"); - return 0; - } - Py_RETURN_NONE; -} - -static char *acquireprogress_pulse_doc = "pulse(owner: Acquire) -> bool\n\n" - "Periodically invoked while the Acquire process is underway.\n\n" - "Return False if the user asked to cancel the whole Acquire process."; -static PyObject *acquireprogress_pulse(PyObject *self, PyObject *arg) -{ - if (!PyAcquire_Check(arg)) { - PyErr_SetString(PyExc_TypeError, "pulse() argument must be " - "apt_pkg.Acquire"); - return 0; - } - Py_RETURN_TRUE; -} - -static char *acquireprogress_start_doc = "start()\n\n" - "Invoked when the Acquire process starts running."; -static PyObject *acquireprogress_start(PyObject *self, PyObject *args) -{ - Py_RETURN_NONE; -} - -static char *acquireprogress_stop_doc = "stop()\n\n" - "Invoked when the Acquire process stops running."; -static PyObject *acquireprogress_stop(PyObject *self, PyObject *args) -{ - Py_RETURN_NONE; -} - -static PyMethodDef acquireprogress_methods[] = { - {"media_change", acquireprogress_media_change, METH_VARARGS, - acquireprogress_media_change_doc}, - {"ims_hit",acquireprogress_ims_hit,METH_O, - acquireprogress_ims_hit_doc}, - {"fetch",acquireprogress_fetch,METH_O,acquireprogress_fetch_doc}, - {"done",acquireprogress_done,METH_O,acquireprogress_done_doc}, - {"fail",acquireprogress_fail,METH_O,acquireprogress_fail_doc}, - {"pulse",acquireprogress_pulse,METH_O,acquireprogress_pulse_doc}, - {"start",acquireprogress_start,METH_NOARGS,acquireprogress_start_doc}, - {"stop",acquireprogress_stop,METH_NOARGS,acquireprogress_stop_doc}, - {NULL} -}; - -static PyMemberDef acquireprogress_members[] = { - {"last_bytes", T_DOUBLE, offsetof(PyAcquireProgressObject, last_bytes), 0, - "The number of bytes fetched as of the previous call to pulse(),\n" - "including local items."}, - {"current_cps", T_DOUBLE, offsetof(PyAcquireProgressObject, current_cps), 0, - "The current rate of download, in bytes per second."}, - {"current_bytes", T_DOUBLE, offsetof(PyAcquireProgressObject, current_bytes), - 0, "The number of bytes fetched."}, - {"total_bytes", T_DOUBLE, offsetof(PyAcquireProgressObject, total_bytes), 0, - "The total number of bytes that need to be fetched. This member is\n" - "inaccurate, as new items might be enqueued while the download is\n" - "in progress!"}, - {"fetched_bytes", T_DOUBLE,offsetof(PyAcquireProgressObject, fetched_bytes), - 0, "The total number of bytes accounted for by items that were\n" - "successfully fetched."}, - {"elapsed_time", T_ULONG, offsetof(PyAcquireProgressObject, elapsed_time),0, - "The amount of time that has elapsed since the download started."}, - {"total_items", T_ULONG, offsetof(PyAcquireProgressObject, total_items),0, - "The total number of items that need to be fetched. This member is\n" - "inaccurate, as new items might be enqueued while the download is\n" - "in progress!"}, - {"current_items", T_ULONG, offsetof(PyAcquireProgressObject, current_items), - 0, "The number of items that have been successfully downloaded."}, - {NULL} -}; - -static char *acquireprogress_doc = "AcquireProgress()\n\n" - "A monitor object for downloads controlled by the Acquire class. This is\n" - "an mostly abstract class. You should subclass it and implement the\n" - "methods to get something useful."; - -PyTypeObject PyAcquireProgress_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "apt_pkg.AcquireProgress", // tp_name - sizeof(PyAcquireProgressObject), // tp_basicsize - 0, // tp_itemsize - // Methods - 0, // tp_dealloc - 0, // tp_print - 0, // 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 - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT | // tp_flags - Py_TPFLAGS_BASETYPE, - acquireprogress_doc, // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - acquireprogress_methods, // tp_methods - acquireprogress_members, // tp_members - 0, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - 0, // tp_init - 0, // tp_alloc - PyType_GenericNew, // tp_new -}; diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc index d53f64a6..faea423f 100644 --- a/python/apt_pkgmodule.cc +++ b/python/apt_pkgmodule.cc @@ -653,10 +653,7 @@ extern "C" void initapt_pkg() ADDTYPE(Module,"HashString",&PyHashString_Type); ADDTYPE(Module,"Policy",&PyPolicy_Type); ADDTYPE(Module,"Hashes",&PyHashes_Type); - ADDTYPE(Module,"OpProgress",&PyOpProgress_Type); - ADDTYPE(Module,"AcquireProgress",&PyAcquireProgress_Type); ADDTYPE(Module,"AcquireItemDesc",&PyAcquireItemDesc_Type); - ADDTYPE(Module,"CdromProgress",&PyCdromProgress_Type); ADDTYPE(Module,"SystemLock",&PySystemLock_Type); ADDTYPE(Module,"FileLock",&PyFileLock_Type); // Tag file constants diff --git a/python/apt_pkgmodule.h b/python/apt_pkgmodule.h index 3edba5d2..97ba05a7 100644 --- a/python/apt_pkgmodule.h +++ b/python/apt_pkgmodule.h @@ -117,9 +117,6 @@ extern PyTypeObject PyIndexRecords_Type; // Policy extern PyTypeObject PyPolicy_Type; extern PyTypeObject PyHashes_Type; -extern PyTypeObject PyOpProgress_Type; -extern PyTypeObject PyAcquireProgress_Type; -extern PyTypeObject PyCdromProgress_Type; extern PyTypeObject PyAcquireItemDesc_Type; extern PyTypeObject PyAcquireWorker_Type; extern PyTypeObject PySystemLock_Type; diff --git a/python/cache.cc b/python/cache.cc index 68ee7b9e..593bc1c2 100644 --- a/python/cache.cc +++ b/python/cache.cc @@ -246,15 +246,9 @@ static PyObject *PkgCacheNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) PyObject *pyCallbackInst = 0; char *kwlist[] = {"progress", 0}; - #ifdef COMPAT_0_7 if (PyArg_ParseTupleAndKeywords(Args, kwds, "|O", kwlist, &pyCallbackInst) == 0) return 0; - #else - if (PyArg_ParseTupleAndKeywords(Args, kwds, "|O!", kwlist, - &PyOpProgress_Type, &pyCallbackInst) == 0) - return 0; - #endif if (_system == 0) { PyErr_SetString(PyExc_ValueError,"_system not initialized"); diff --git a/python/cdrom.cc b/python/cdrom.cc index 2270b01c..4195c9cb 100644 --- a/python/cdrom.cc +++ b/python/cdrom.cc @@ -57,8 +57,7 @@ static PyObject *cdrom_ident(PyObject *Self,PyObject *Args) { pkgCdrom &Cdrom = GetCpp(Self); PyObject *pyCdromProgressInst = 0; - if (PyArg_ParseTuple(Args, "O!", &PyCdromProgress_Type, - &pyCdromProgressInst) == 0) { + if (PyArg_ParseTuple(Args, "O", &pyCdromProgressInst) == 0) { return 0; } diff --git a/python/cdromprogress.cc b/python/cdromprogress.cc deleted file mode 100644 index 440b5ce6..00000000 --- a/python/cdromprogress.cc +++ /dev/null @@ -1,106 +0,0 @@ -/* cdromprogress.cc - Base class for CdromProgress classes. - * - * Copyright 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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ -#include "apt_pkgmodule.h" -#include "progress.h" -#include -#include - -// Takes two arguments (string, int) -static PyObject *cdromprogress_update(PyObject *self, PyObject *args) -{ - Py_RETURN_NONE; -} - -// Takes no arguments -static PyObject *cdromprogress_change_cdrom(PyObject *self, PyObject *args) -{ - Py_RETURN_FALSE; -} - -// Takes a single PyObject argument as *arg -static PyObject *cdromprogress_ask_cdrom_name(PyObject *self, PyObject *arg) -{ - Py_RETURN_NONE; -} - -static PyMethodDef cdromprogress_methods[] = { - {"update",cdromprogress_update,METH_VARARGS, - "update(text: str, current: int)\n\nCalled regularly."}, - {"change_cdrom",cdromprogress_change_cdrom,METH_NOARGS, - "change_cdrom() -> bool\n\nAsk for the CD-ROM to be changed.\n" - "Return False if the user requested to cancel the action (default)."}, - {"ask_cdrom_name",cdromprogress_ask_cdrom_name,METH_O, - "ask_cdrom_name() -> str\n\nAsk for the name of the CD-ROM.\n" - "Return None if the user requested to cancel the action (default)."}, - {NULL} -}; - -static PyMemberDef cdromprogress_members[] = { - {"total_steps", T_INT, offsetof(PyCdromProgressObject,total_steps), 0, - "The number of total steps to be taken."}, - {NULL} -}; - -static char *cdromprogress_doc = "CdromProgress()\n\n" - "Base class for reporting the progress of adding a cdrom. Can be used\n" - "with apt_pkg.Cdrom to produce an utility like apt-cdrom."; - -PyTypeObject PyCdromProgress_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "apt_pkg.CdromProgress", // tp_name - sizeof(PyCdromProgressObject), // tp_basicsize - 0, // tp_itemsize - // Methods - 0, // tp_dealloc - 0, // tp_print - 0, // 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 - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT | // tp_flags - Py_TPFLAGS_BASETYPE, - cdromprogress_doc, // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - cdromprogress_methods, // tp_methods - cdromprogress_members, // tp_members - 0, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - 0, // tp_init - 0, // tp_alloc - PyType_GenericNew, // tp_new -}; diff --git a/python/opprogress.cc b/python/opprogress.cc deleted file mode 100644 index 2ee6a03e..00000000 --- a/python/opprogress.cc +++ /dev/null @@ -1,175 +0,0 @@ -/* op-progress.cc - Base class for OpProgress classes. - * - * Copyright 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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include "generic.h" -#include "progress.h" -#include -#include - - - -static PyObject *opprogress_update(PyObject *Self, PyObject *args) -{ - Py_RETURN_NONE; -} - -static PyObject *opprogress_done(PyObject *Self, PyObject *args) -{ - Py_RETURN_NONE; -} - -static PyObject *opprogress_get_op(PyOpProgressObject *self, void *closure) -{ - Py_INCREF(self->op); - return self->op; -} - -static int opprogress_set_op(PyOpProgressObject *self, PyObject *value, - void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete 'op'"); - return -1; - } - if (!PyString_Check(value)) { - PyErr_SetString(PyExc_TypeError,"'op' must be a string."); - return -1; - } - Py_DECREF(self->op); - Py_INCREF(value); - - self->op = value; - return 0; -} - -static PyObject *opprogress_get_subop(PyOpProgressObject *self, void *closure) -{ - Py_INCREF(self->subop); - return self->subop; -} - -static int opprogress_set_subop(PyOpProgressObject *self, PyObject *value, - void *closure) -{ - if (value == NULL) { - PyErr_SetString(PyExc_TypeError, "Cannot delete 'subop'."); - return -1; - } - if (!PyString_Check(value)) { - PyErr_SetString(PyExc_TypeError,"'subop' must be a string."); - return -1; - } - Py_DECREF(self->subop); - Py_INCREF(value); - self->subop = value; - return 0; -} - -static PyMethodDef opprogress_methods[] = { - {"update",opprogress_update,METH_NOARGS,"update()\n\nCalled periodically."}, - {"done",opprogress_done,METH_NOARGS,"update()\n\nCalled when done."}, - {NULL}, -}; - -#ifndef T_BOOL -# define _T_BOOL T_INT -#else -# define _T_BOOL T_BOOL -#endif -static PyMemberDef opprogress_members[] = { - {"major_change", _T_BOOL, offsetof(PyOpProgressObject, major_change), 0, - "Boolean value indicating whether the change is a major change."}, - {"percent", T_FLOAT, offsetof(PyOpProgressObject, percent), 0, - "Percentage of completion (float value)."}, - {NULL} -}; - -static PyGetSetDef opprogress_getset[] = { - {"op", (getter)opprogress_get_op, (setter)opprogress_set_op, - "Description of the current operation"}, - {"subop", (getter)opprogress_get_subop, (setter)opprogress_set_subop, - "Description of the current sub-operation"}, - {NULL}, -}; - -static void opprogress_dealloc(PyObject *self) -{ - Py_XDECREF(((PyOpProgressObject *)self)->op); - Py_XDECREF(((PyOpProgressObject *)self)->subop); - self->ob_type->tp_free(self); -} - -static PyObject *opprogress_new(PyTypeObject *type, PyObject *args, - PyObject *kwds) -{ - PyOpProgressObject *res = (PyOpProgressObject *)type->tp_alloc(type, 0); - res->op = PyString_FromString(""); - res->subop = PyString_FromString(""); - return (PyObject *)res; -} - -static char *opprogress_doc = "OpProgress()\n\n" - "A base class for writing custom operation progress classes. Subclasses\n" - "should override all the methods (and call the parent ones) but shall\n" - "not override any of the inherited descriptors because they may be\n" - "ignored."; - -PyTypeObject PyOpProgress_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "apt_pkg.OpProgress", // tp_name - sizeof(PyOpProgressObject), // tp_basicsize - 0, // tp_itemsize - // Methods - opprogress_dealloc, // tp_dealloc - 0, // tp_print - 0, // 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 - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT | // tp_flags - Py_TPFLAGS_BASETYPE, - opprogress_doc, // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - opprogress_methods, // tp_methods - opprogress_members, // tp_members - opprogress_getset, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - 0, // tp_init - 0, // tp_alloc - opprogress_new, // tp_new -}; diff --git a/python/progress.h b/python/progress.h index bc1bd640..80cb2785 100644 --- a/python/progress.h +++ b/python/progress.h @@ -32,38 +32,6 @@ #define PyCbObj_BLOCK_THREADS Py_BLOCK_THREADS #define PyCbObj_UNBLOCK_THREADS Py_UNBLOCK_THREADS -typedef struct { - PyObject_HEAD - PyObject *op; - PyObject *subop; -#ifdef T_BOOL - char major_change; -#else - int major_change; -#endif - float percent; -} PyOpProgressObject; - - -typedef struct { - PyObject_HEAD - int total_steps; -} PyCdromProgressObject; - -typedef struct { - PyObject_HEAD - double last_bytes; - double current_cps; - double current_bytes; - double total_bytes; - double fetched_bytes; - unsigned long elapsed_time; - unsigned long total_items; - unsigned long current_items; -} PyAcquireProgressObject; - - - class PyCallbackObj { protected: PyObject *callbackInst; diff --git a/setup.py b/setup.py index 93fcb436..9b33ed5d 100644 --- a/setup.py +++ b/setup.py @@ -35,9 +35,8 @@ files = ['apt_pkgmodule.cc', 'acquire.cc', 'cache.cc', 'cdrom.cc', 'hashstring.cc', 'indexfile.cc', 'indexrecords.cc', 'metaindex.cc', 'pkgmanager.cc', 'pkgrecords.cc', 'pkgsrcrecords.cc', 'policy.cc', 'progress.cc', 'sourcelist.cc', 'string.cc', 'tag.cc', - 'opprogress.cc', 'acquireprogress.cc', 'cdromprogress.cc', 'lock.cc', - 'acquire-item.cc'] -files = sorted(['python/' + fname for fname in files]) + 'lock.cc', 'acquire-item.cc'] +files = sorted(['python/' + fname for fname in files], key=lambda s: s[:-3]) apt_pkg = Extension("apt_pkg", files, libraries=["apt-pkg"]) # The apt_inst module -- cgit v1.2.3 From bee2af041668dcd1e3d23197e275ffe3b3605a6f Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 31 Jul 2009 15:39:08 +0200 Subject: apt/progress/old.py: Derive some more old classes from new classes. OpTextProgress is now derived from text.OpProgress and DumbInstallProgress is derived from base.InstallProgress. --- apt/progress/old.py | 43 ++++++++++--------------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) (limited to 'apt/progress/old.py') diff --git a/apt/progress/old.py b/apt/progress/old.py index adaf94b2..6b6e21de 100644 --- a/apt/progress/old.py +++ b/apt/progress/old.py @@ -34,7 +34,7 @@ import sys import apt_pkg from apt.deprecation import AttributeDeprecatedBy, function_deprecated_by -from apt.progress import base +from apt.progress import base, text __all__ = [] @@ -51,22 +51,12 @@ class OpProgress(base.OpProgress): Op = AttributeDeprecatedBy('op') -class OpTextProgress(OpProgress): +class OpTextProgress(text.OpProgress): """A simple text based cache open reporting class.""" - def __init__(self): - OpProgress.__init__(self) - - def update(self, percent=None): - """Called periodically to update the user interface.""" - OpProgress.update(self, percent) - sys.stdout.write("\r%s: %.2i " % (self.subop, self.percent)) - sys.stdout.flush() - - def done(self): - """Called once an operation has been completed.""" - OpProgress.done(self) - sys.stdout.write("\r%s: Done\n" % self.op) + if apt_pkg._COMPAT_0_7: + subOp = AttributeDeprecatedBy('subop') + Op = AttributeDeprecatedBy('op') class FetchProgress(object): @@ -209,29 +199,16 @@ class TextFetchProgress(FetchProgress): mediaChange = function_deprecated_by(media_change) -class DumbInstallProgress(object): +class DumbInstallProgress(base.InstallProgress): """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""" - - if apt_pkg._COMPAT_0_7: - startUpdate = function_deprecated_by(start_update) - finishUpdate = function_deprecated_by(finish_update) - updateInterface = function_deprecated_by(update_interface) + startUpdate = function_deprecated_by(base.InstallProgress.start_update) + finishUpdate = function_deprecated_by(base.InstallProgress.finish_update) + updateInterface = function_deprecated_by( + base.InstallProgress.update_interface) class InstallProgress(DumbInstallProgress): -- 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/old.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