From 22b5c5d28c31eed85d7fad3a7638e1067200029a Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 16 Jul 2009 15:25:30 +0200 Subject: apt/progress/text.py: Introduce new progress classes for text. These are based on the new classes in apt_pkg and work better, because they correctly clear the screen. --- apt/progress/text.py | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 apt/progress/text.py (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py new file mode 100644 index 00000000..6024f124 --- /dev/null +++ b/apt/progress/text.py @@ -0,0 +1,122 @@ +# 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 +"""Progress reporting for text interfaces.""" +import sys + +import apt_pkg + +__all__ = ['AcquireProgress', 'OpProgress'] + + +class TextProgress(object): + """Internal Base class for text progress classes.""" + + def __init__(self, outfile=None): + self._file = outfile or sys.stdout + self._width = 0 + + def _write(self, msg, newline=True): + """Write the message on the terminal, fill remaining space.""" + self._file.write("\r") + self._file.write(msg) + # Fill remaining stuff with whitespace + if self._width > len(msg): + self._file.write((self._width - len(msg)) * ' ') + else: + self._width = max(self._width, len(msg)) + if newline: + self._file.write("\n") + else: + self._file.write("\r") + self._file.flush() + + +class OpProgress(apt_pkg.OpProgress, TextProgress): + """Operation progress reporting. + + This closely resembles OpTextProgress in libapt-pkg. + """ + + def __init__(self, outfile=None): + TextProgress.__init__(self, outfile) + apt_pkg.OpProgress.__init__(self) + self.old_op = "" + + def update(self, percent=None): + """Called periodically to update the user interface.""" + if percent: + self.percent = percent + apt_pkg.OpProgress.update(self) + if self.major_change and self.old_op: + self._write(self.old_op) + self._write("%s... %i%%" % (self.op, self.percent), False) + self.old_op = self.op + + def done(self): + """Called once an operation has been completed.""" + apt_pkg.OpProgress.done(self) + if self.old_op: + self._write("%s... Done" % self.old_op) + self.old_op = "" + + +class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): + """AcquireProgress for the text interface.""" + + def ims_hit(self, item): + """Called when an item is update (e.g. not modified on the server).""" + self._write("Hit %s" % item.description) + + def done(self, item): + """Called when an item is completely fetched.""" + self._write("Done %s" % item.description) + + def fail(self, item): + """Called when an item is failed.""" + self._write("Fail %s" % item.description) + + def fetch(self, item): + """Called when some of the item's data is fetched.""" + self._write("Fetch %s" % item.description) + + def pulse(self, owner): + """Periodically invoked while the Acquire process is underway. + + Return False if the user asked to cancel the whole Acquire process.""" + + percent = (((self.current_bytes + self.current_items) * 100.0) / + float(self.total_bytes + self.total_items)) + if self.current_cps > 0: + eta = ((self.total_bytes - self.current_bytes) / + float(self.current_cps)) + self._write("[%2.f%%] %sB/s %s" % (percent, + apt_pkg.size_to_str(int(self.current_cps)), + apt_pkg.time_to_str(int(eta))), False) + else: + self._write("%2.f%% [Working]" % (percent), False) + return True + + def media_change(self, medium, drive): + """Prompt the user to change the inserted removable media.""" + 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') + + def stop(self): + """Invoked when the Acquire process stops running.""" + self._write("Done downloading") -- cgit v1.2.3 From c8f2e068538dd54206669394507a52115ce9a621 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 16 Jul 2009 19:43:38 +0200 Subject: apt/progress/text.py: 'Sync' AcquireProgress with the one used for apt-get. --- apt/progress/text.py | 111 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 18 deletions(-) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index 6024f124..eb196b55 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -36,12 +36,12 @@ class TextProgress(object): # Fill remaining stuff with whitespace if self._width > len(msg): self._file.write((self._width - len(msg)) * ' ') - else: - self._width = max(self._width, len(msg)) + #else: + # self._width = max(self._width, len(msg)) if newline: self._file.write("\n") else: - self._file.write("\r") + #self._file.write("\r") self._file.flush() @@ -63,7 +63,7 @@ class OpProgress(apt_pkg.OpProgress, TextProgress): apt_pkg.OpProgress.update(self) if self.major_change and self.old_op: self._write(self.old_op) - self._write("%s... %i%%" % (self.op, self.percent), False) + self._write("%s... %i%%\r" % (self.op, self.percent), False) self.old_op = self.op def done(self): @@ -77,21 +77,47 @@ class OpProgress(apt_pkg.OpProgress, TextProgress): class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): """AcquireProgress for the text interface.""" + def __init__(self, outfile=None): + TextProgress.__init__(self, outfile) + apt_pkg.AcquireProgress.__init__(self) + import signal + self._signal = signal.signal(signal.SIGWINCH, self._winch) + self._winch() + self._id = 1L + + def _winch(self, *a): + import fcntl + import termios + import struct + buf = fcntl.ioctl(self._file.fileno(),termios.TIOCGWINSZ, 8 * ' ') + row, col, rpx, cpx = struct.unpack('hhhh', buf) + self._width = col - 1 # 1 for the cursor + def ims_hit(self, item): """Called when an item is update (e.g. not modified on the server).""" - self._write("Hit %s" % item.description) - - def done(self, item): - """Called when an item is completely fetched.""" - self._write("Done %s" % item.description) + line = 'Hit %s' % item.description + if (item.owner.filesize != 0): + line+= ' [%sB]' % apt_pkg.size_to_str(item.owner.filesize) + self._write(line) def fail(self, item): """Called when an item is failed.""" self._write("Fail %s" % item.description) + if item.owner.status == item.owner.stat_done: + self._write("Ign %s" % item.description) + else: + self._write("Err %s" % item.description) + self._write(" %s" % item.owner.error_text) def fetch(self, item): """Called when some of the item's data is fetched.""" - self._write("Fetch %s" % item.description) + item.owner.id = self._id + self._id += 1 + line = "Get:%s %s" % (item.owner.id, item.description) + if item.owner.filesize != 0: + line += (" [%sB]" % apt_pkg.size_to_str(item.owner.filesize)) + + self._write(line) def pulse(self, owner): """Periodically invoked while the Acquire process is underway. @@ -100,14 +126,59 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): percent = (((self.current_bytes + self.current_items) * 100.0) / float(self.total_bytes + self.total_items)) - if self.current_cps > 0: - eta = ((self.total_bytes - self.current_bytes) / - float(self.current_cps)) - self._write("[%2.f%%] %sB/s %s" % (percent, - apt_pkg.size_to_str(int(self.current_cps)), - apt_pkg.time_to_str(int(eta))), False) + + shown = False + mode = 'long' + tval = '%i%%' % percent + + end = "" + if self.current_cps: + eta = int(float(self.total_bytes - self.current_bytes) / self.current_cps) + end = " %sB/s %s" % (apt_pkg.size_to_str(self.current_cps), + apt_pkg.time_to_str(eta)) + + for worker in owner.workers: + val = '' + if not worker.current_item: + if worker.status: + val += ' [%s]' % worker.status + shown = True + continue + shown = True + + if worker.current_item.owner.id != 0: + val += " [%i %s" % (worker.current_item.owner.id, worker.current_item.shortdesc) + else: + val += ' [%s' % worker.current_item.description + if worker.current_item.owner.mode: + val += ' %s' % worker.current_item.owner.mode + if mode == 'long' and False: + val += ' %i' % worker.current_size + elif mode == 'medium' or worker.total_size == 0 or True: + val += ' %sB' % apt_pkg.size_to_str(worker.current_size) + + # Add the total size and percent + if worker.total_size > 0 and worker.current_item.owner.complete == False: + if mode == 'short': + val += ' %i%%' % worker.current_size*100.0/worker.total_size + else: + val += "/%sB %i%%" % ( apt_pkg.size_to_str(worker.total_size), + worker.current_size*100.0/worker.total_size ) + + val += ']' + + tval += val + + if not shown: + tval += ' [Working]' + + if self.current_cps: + tval += (self._width - len(end) - len(tval)) * ' ' + end + + if len(tval) <= self._width: + self._write(tval, False) else: - self._write("%2.f%% [Working]" % (percent), False) + self._write(tval) return True def media_change(self, medium, drive): @@ -119,4 +190,8 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def stop(self): """Invoked when the Acquire process stops running.""" - self._write("Done downloading") + if self.fetched_bytes != 0: + self._write("Fetched %sB in %s (%sB/s)" % ( + apt_pkg.size_to_str(self.fetched_bytes), + apt_pkg.time_to_str(self.elapsed_time), + apt_pkg.size_to_str(self.current_cps))) -- cgit v1.2.3 From 212ab0a6b95395bad245eb18d4aa710b01b24e9e Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 16 Jul 2009 20:08:00 +0200 Subject: apt/progress/text.py: Print status messages. --- apt/progress/text.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index eb196b55..2b2e5f27 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -29,15 +29,15 @@ class TextProgress(object): self._file = outfile or sys.stdout self._width = 0 - def _write(self, msg, newline=True): + def _write(self, msg, newline=True, maximize=False): """Write the message on the terminal, fill remaining space.""" self._file.write("\r") self._file.write(msg) # Fill remaining stuff with whitespace if self._width > len(msg): self._file.write((self._width - len(msg)) * ' ') - #else: - # self._width = max(self._width, len(msg)) + elif maximize: # Needed for OpProgress. + self._width = max(self._width, len(msg)) if newline: self._file.write("\n") else: @@ -63,14 +63,14 @@ class OpProgress(apt_pkg.OpProgress, TextProgress): apt_pkg.OpProgress.update(self) if self.major_change and self.old_op: self._write(self.old_op) - self._write("%s... %i%%\r" % (self.op, self.percent), False) + self._write("%s... %i%%\r" % (self.op, self.percent), False, True) self.old_op = self.op def done(self): """Called once an operation has been completed.""" apt_pkg.OpProgress.done(self) if self.old_op: - self._write("%s... Done" % self.old_op) + self._write("%s... Done" % self.old_op, True, True) self.old_op = "" @@ -102,7 +102,6 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def fail(self, item): """Called when an item is failed.""" - self._write("Fail %s" % item.description) if item.owner.status == item.owner.stat_done: self._write("Ign %s" % item.description) else: @@ -141,7 +140,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): val = '' if not worker.current_item: if worker.status: - val += ' [%s]' % worker.status + tval += ' [%s]' % worker.status shown = True continue shown = True -- cgit v1.2.3 From 7f861d478db844037d14aeb423eaab88a0a47716 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 16 Jul 2009 20:16:27 +0200 Subject: apt/progress/text.py: Limit number of displayed items by display size. --- apt/progress/text.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index 2b2e5f27..4cdd266f 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -140,7 +140,10 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): val = '' if not worker.current_item: if worker.status: - tval += ' [%s]' % worker.status + val = ' [%s]' % worker.status + if len(tval) + len(val) + len(end) >= self._width: + break + tval += val shown = True continue shown = True @@ -166,7 +169,10 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): val += ']' - tval += val + if len(tval) + len(val) + len(end) >= self._width: + break + else: + tval += val if not shown: tval += ' [Working]' -- cgit v1.2.3 From 5dbe872723f375db9f5d371051f6a9756fdc4c60 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 17 Jul 2009 13:00:41 +0200 Subject: apt/progress/text.py: Don't display complete items in AcquireProgress.fetch --- apt/progress/text.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index 4cdd266f..2a6b188d 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -110,6 +110,9 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def fetch(self, item): """Called when some of the item's data is fetched.""" + # It's complete already (e.g. Hit) + if item.owner.complete == True: + return item.owner.id = self._id self._id += 1 line = "Get:%s %s" % (item.owner.id, item.description) -- cgit v1.2.3 From 4e2bcf7853acd661bd9b56be7c774cc361fdebb4 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 17 Jul 2009 16:45:51 +0200 Subject: apt/progress/text.py: Cleanup, add i18n (and try apt translation if we have none). --- apt/progress/text.py | 92 +++++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 40 deletions(-) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index 2a6b188d..b50502e6 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -16,12 +16,22 @@ # USA """Progress reporting for text interfaces.""" import sys +from gettext import gettext, dgettext import apt_pkg __all__ = ['AcquireProgress', 'OpProgress'] +def _(msg): + """Translate the message, also try apt if translation is missing.""" + res = dgettext("python-apt", msg) + if res == msg: + return dgettext("apt", msg) + else: + return res + + class TextProgress(object): """Internal Base class for text progress classes.""" @@ -70,7 +80,7 @@ class OpProgress(apt_pkg.OpProgress, TextProgress): """Called once an operation has been completed.""" apt_pkg.OpProgress.done(self) if self.old_op: - self._write("%s... Done" % self.old_op, True, True) + self._write(_("%c%s... Done") % ('\r', self.old_op), True, True) self.old_op = "" @@ -85,42 +95,51 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): self._winch() self._id = 1L - def _winch(self, *a): + def __del__(self): + import signal + signal.signal(signal.SIGWINCH, self._signal) + + def _winch(self, *dummy): + """Signal handler for window resize signals.""" import fcntl import termios import struct - buf = fcntl.ioctl(self._file.fileno(),termios.TIOCGWINSZ, 8 * ' ') - row, col, rpx, cpx = struct.unpack('hhhh', buf) + buf = fcntl.ioctl(self._file, termios.TIOCGWINSZ, 8 * ' ') + dummy, col, dummy, dummy = struct.unpack('hhhh', buf) self._width = col - 1 # 1 for the cursor def ims_hit(self, item): """Called when an item is update (e.g. not modified on the server).""" - line = 'Hit %s' % item.description - if (item.owner.filesize != 0): - line+= ' [%sB]' % apt_pkg.size_to_str(item.owner.filesize) + line = _('Hit ') + item.description + if item.owner.filesize: + line += ' [%sB]' % apt_pkg.size_to_str(item.owner.filesize) self._write(line) def fail(self, item): """Called when an item is failed.""" if item.owner.status == item.owner.stat_done: - self._write("Ign %s" % item.description) + self._write(_("Ign ") + item.description) else: - self._write("Err %s" % item.description) + self._write(_("Err ") + item.description) self._write(" %s" % item.owner.error_text) def fetch(self, item): """Called when some of the item's data is fetched.""" # It's complete already (e.g. Hit) - if item.owner.complete == True: + if item.owner.complete: return item.owner.id = self._id self._id += 1 - line = "Get:%s %s" % (item.owner.id, item.description) - if item.owner.filesize != 0: + line = _("Get:") + "%s %s" % (item.owner.id, item.description) + if item.owner.filesize: line += (" [%sB]" % apt_pkg.size_to_str(item.owner.filesize)) self._write(line) + @staticmethod + def _fmt_worker(worker): + """Format a worker.""" + def pulse(self, owner): """Periodically invoked while the Acquire process is underway. @@ -130,14 +149,14 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): float(self.total_bytes + self.total_items)) shown = False - mode = 'long' tval = '%i%%' % percent end = "" if self.current_cps: - eta = int(float(self.total_bytes - self.current_bytes) / self.current_cps) + eta = int(float(self.total_bytes - self.current_bytes) / + self.current_cps) end = " %sB/s %s" % (apt_pkg.size_to_str(self.current_cps), - apt_pkg.time_to_str(eta)) + apt_pkg.time_to_str(eta)) for worker in owner.workers: val = '' @@ -151,55 +170,48 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): continue shown = True - if worker.current_item.owner.id != 0: - val += " [%i %s" % (worker.current_item.owner.id, worker.current_item.shortdesc) + if worker.current_item.owner.id: + val += " [%i %s" % (worker.current_item.owner.id, + worker.current_item.shortdesc) else: val += ' [%s' % worker.current_item.description if worker.current_item.owner.mode: val += ' %s' % worker.current_item.owner.mode - if mode == 'long' and False: - val += ' %i' % worker.current_size - elif mode == 'medium' or worker.total_size == 0 or True: - val += ' %sB' % apt_pkg.size_to_str(worker.current_size) + + val += ' %sB' % apt_pkg.size_to_str(worker.current_size) # Add the total size and percent - if worker.total_size > 0 and worker.current_item.owner.complete == False: - if mode == 'short': - val += ' %i%%' % worker.current_size*100.0/worker.total_size - else: - val += "/%sB %i%%" % ( apt_pkg.size_to_str(worker.total_size), - worker.current_size*100.0/worker.total_size ) + if worker.total_size and not worker.current_item.owner.complete: + val += "/%sB %i%%" % (apt_pkg.size_to_str(worker.total_size), + worker.current_size*100.0/worker.total_size) val += ']' - if len(tval) + len(val) + len(end) >= self._width: + if len(tval) + len(val) + len(end) >= self._width: break else: tval += val if not shown: - tval += ' [Working]' + tval += _(" [Working]") if self.current_cps: tval += (self._width - len(end) - len(tval)) * ' ' + end - if len(tval) <= self._width: - self._write(tval, False) - else: - self._write(tval) + self._write(tval, False) return True def media_change(self, medium, drive): """Prompt the user to change the inserted removable media.""" - print ("Media change: please insert the disc labeled " - "'%s' in the drive '%s' and press enter") % (medium, drive) - + self._write(_("Media change: please insert the disc labeled\n" + " '%s'\n" + "in the drive '%s' and press enter\n") % (medium, drive)) return raw_input() not in ('c', 'C') def stop(self): """Invoked when the Acquire process stops running.""" - if self.fetched_bytes != 0: - self._write("Fetched %sB in %s (%sB/s)" % ( - apt_pkg.size_to_str(self.fetched_bytes), + if self.fetched_bytes: + self._write(_("Fetched %sB in %s (%sB/s)\n") % ( + apt_pkg.size_to_str(self.fetched_bytes), apt_pkg.time_to_str(self.elapsed_time), - apt_pkg.size_to_str(self.current_cps))) + apt_pkg.size_to_str(self.current_cps)), False) -- cgit v1.2.3 From db6032394c794c6bbe59675bb38802d208d993cb Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 17 Jul 2009 17:24:58 +0200 Subject: apt/progress/text.py: Improve final summary. --- apt/progress/text.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index b50502e6..ba8e158d 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -16,7 +16,7 @@ # USA """Progress reporting for text interfaces.""" import sys -from gettext import gettext, dgettext +from gettext import dgettext import apt_pkg @@ -90,15 +90,22 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def __init__(self, outfile=None): TextProgress.__init__(self, outfile) apt_pkg.AcquireProgress.__init__(self) + self._signal = None + self._width = 80 + self._id = 1 + + def start(self): + """Start an Acquire progress. + + In this case, the function sets up a signal handler for SIGWINCH, i.e. + window resize signals. And it also sets id to 1. + """ import signal self._signal = signal.signal(signal.SIGWINCH, self._winch) + # Get the window size. self._winch() self._id = 1L - def __del__(self): - import signal - signal.signal(signal.SIGWINCH, self._signal) - def _winch(self, *dummy): """Signal handler for window resize signals.""" import fcntl @@ -136,10 +143,6 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): self._write(line) - @staticmethod - def _fmt_worker(worker): - """Format a worker.""" - def pulse(self, owner): """Periodically invoked while the Acquire process is underway. @@ -188,6 +191,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): val += ']' if len(tval) + len(val) + len(end) >= self._width: + # Display as many items as screen width break else: tval += val @@ -210,8 +214,12 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def stop(self): """Invoked when the Acquire process stops running.""" - if self.fetched_bytes: - self._write(_("Fetched %sB in %s (%sB/s)\n") % ( - apt_pkg.size_to_str(self.fetched_bytes), - apt_pkg.time_to_str(self.elapsed_time), - apt_pkg.size_to_str(self.current_cps)), False) + # Trick for getting a translation from apt + self._write((_("Fetched %sB in %s (%sB/s)\n") % ( + apt_pkg.size_to_str(self.fetched_bytes), + apt_pkg.time_to_str(self.elapsed_time), + apt_pkg.size_to_str(self.current_cps))).rstrip("\n")) + + # Delete the signal again. + import signal + signal.signal(signal.SIGWINCH, self._signal) -- cgit v1.2.3 From 9bd7c1dcf9942d6ce294aa5ac58d90d6c1aa9f51 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 17 Jul 2009 19:06:20 +0200 Subject: apt: Use apt_pkg.gettext instead of Python's gettext. --- apt/__init__.py | 9 +-------- apt/cache.py | 6 +----- apt/debfile.py | 2 +- apt/package.py | 7 +------ apt/progress/gtk2.py | 2 +- apt/progress/text.py | 6 ++---- 6 files changed, 7 insertions(+), 25 deletions(-) (limited to 'apt/progress/text.py') diff --git a/apt/__init__.py b/apt/__init__.py index 2ef8add3..a75218a8 100644 --- a/apt/__init__.py +++ b/apt/__init__.py @@ -18,8 +18,6 @@ # USA # import the core of apt_pkg """High-Level Interface for working with apt.""" -import locale - import apt_pkg # import some fancy classes @@ -30,15 +28,10 @@ from apt.cdrom import Cdrom if apt_pkg._COMPAT_0_7: from apt.progress.old import (OpProgress, FetchProgress, InstallProgress, CdromProgress) - from apt_pkg import (size_to_str as SizeToStr, - time_to_str as TimeToStr, + from apt_pkg import (size_to_str as SizeToStr, time_to_str as TimeToStr, version_compare as VersionCompare) # init the package system apt_pkg.init() -locale.setlocale(locale.LC_ALL, '') -#import warnings -#warnings.warn("apt API not stable yet", FutureWarning) -#del warnings __all__ = ['Cache', 'Cdrom', 'Package'] diff --git a/apt/cache.py b/apt/cache.py index 6e11d215..9982559b 100644 --- a/apt/cache.py +++ b/apt/cache.py @@ -21,19 +21,15 @@ import os import weakref -from gettext import dgettext import apt_pkg from apt import Package +from apt_pkg import gettext as _ from apt.deprecation import (AttributeDeprecatedBy, function_deprecated_by, deprecated_args) import apt.progress.text -def _(msg): - return dgettext('python-apt', msg) - - class FetchCancelledException(IOError): """Exception that is thrown when the user cancels a fetch operation.""" diff --git a/apt/debfile.py b/apt/debfile.py index 84bbe3ab..e05233f4 100644 --- a/apt/debfile.py +++ b/apt/debfile.py @@ -17,12 +17,12 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA """Classes for working with locally available Debian packages.""" -from gettext import gettext as _ import os import sys import apt_inst import apt_pkg +from apt_pkg import gettext as _ # Constants for comparing the local package file with the version in the cache diff --git a/apt/package.py b/apt/package.py index 491571c2..1307ca3e 100644 --- a/apt/package.py +++ b/apt/package.py @@ -19,7 +19,6 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # USA """Functionality related to packages.""" -import gettext import httplib import os import sys @@ -36,6 +35,7 @@ except ImportError: import apt_pkg import apt.progress.text +from apt_pkg import gettext as _ from apt.deprecation import (function_deprecated_by, AttributeDeprecatedBy, deprecated_args) @@ -43,11 +43,6 @@ __all__ = ('BaseDependency', 'Dependency', 'Origin', 'Package', 'Record', 'Version') -def _(string): - """Return the translation of the string.""" - return gettext.dgettext("python-apt", string) - - def _file_is_same(path, size, md5): """Return ``True`` if the file is the same.""" if (os.path.exists(path) and os.path.getsize(path) == size and diff --git a/apt/progress/gtk2.py b/apt/progress/gtk2.py index c0f9ed82..066271c6 100644 --- a/apt/progress/gtk2.py +++ b/apt/progress/gtk2.py @@ -22,7 +22,6 @@ # USA """GObject-powered progress classes and a GTK+ status widget.""" -from gettext import gettext as _ import os import time @@ -39,6 +38,7 @@ import vte import apt.progress.old import apt_pkg +from apt_pkg import gettext as _ from apt.deprecation import function_deprecated_by diff --git a/apt/progress/text.py b/apt/progress/text.py index ba8e158d..b93a8e81 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -16,7 +16,6 @@ # USA """Progress reporting for text interfaces.""" import sys -from gettext import dgettext import apt_pkg @@ -25,13 +24,12 @@ __all__ = ['AcquireProgress', 'OpProgress'] def _(msg): """Translate the message, also try apt if translation is missing.""" - res = dgettext("python-apt", msg) + res = apt_pkg.gettext(msg) if res == msg: - return dgettext("apt", msg) + return apt_pkg.gettext(msg, "apt") else: return res - class TextProgress(object): """Internal Base class for text progress classes.""" -- cgit v1.2.3 From 7debfcbb984fe059ff08b7edba40f14bff2c28a6 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 19 Jul 2009 15:46:46 +0200 Subject: apt/progress/text.py: Introduce CdromProgress. --- apt/progress/text.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index b93a8e81..49707a23 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -26,9 +26,8 @@ def _(msg): """Translate the message, also try apt if translation is missing.""" res = apt_pkg.gettext(msg) if res == msg: - return apt_pkg.gettext(msg, "apt") - else: - return res + res = apt_pkg.gettext(msg, "apt") + return res class TextProgress(object): """Internal Base class for text progress classes.""" @@ -40,7 +39,8 @@ class TextProgress(object): def _write(self, msg, newline=True, maximize=False): """Write the message on the terminal, fill remaining space.""" self._file.write("\r") - self._file.write(msg) + print >> self._file, msg, + # Fill remaining stuff with whitespace if self._width > len(msg): self._file.write((self._width - len(msg)) * ' ') @@ -221,3 +221,26 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): # Delete the signal again. import signal signal.signal(signal.SIGWINCH, self._signal) + +class CdromProgress(apt_pkg.CdromProgress, TextProgress): + """Text CD-ROM progress.""" + + def ask_cdrom_name(self): + self._write(_("Please provide a name for this Disc, such as " + "'Debian 2.1r1 Disk 1'"), False) + try: + return raw_input(":") + except KeyboardInterrupt: + return + + def update(self, text, current): + if text: + self._write(text, False) + + def change_cdrom(self): + self._write(_("Please insert a Disc in the drive and press enter"), + False) + try: + return (raw_input() == '') + except KeyboardInterrupt: + return False -- cgit v1.2.3 From 2731686d7ef756062eeaf78d7809d18f71e9aaf5 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 19 Jul 2009 16:49:30 +0200 Subject: apt/progress/text.py: Add some docstrings. --- apt/progress/text.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index 49707a23..1316952c 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -29,6 +29,7 @@ def _(msg): res = apt_pkg.gettext(msg, "apt") return res + class TextProgress(object): """Internal Base class for text progress classes.""" @@ -222,10 +223,12 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): import signal signal.signal(signal.SIGWINCH, self._signal) + class CdromProgress(apt_pkg.CdromProgress, TextProgress): """Text CD-ROM progress.""" def ask_cdrom_name(self): + """Ask the user to provide a name for the disc.""" self._write(_("Please provide a name for this Disc, such as " "'Debian 2.1r1 Disk 1'"), False) try: @@ -234,10 +237,12 @@ class CdromProgress(apt_pkg.CdromProgress, TextProgress): return def update(self, text, current): + """Set the current progress.""" if text: self._write(text, False) def change_cdrom(self): + """Ask the user to change the CD-ROM.""" self._write(_("Please insert a Disc in the drive and press enter"), False) try: -- cgit v1.2.3 From 86007bcc5e1faa40d2d4e456121b839f96136fb6 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 19 Jul 2009 17:51:16 +0200 Subject: apt/progress/text.py: Always call methods of the parent class. --- apt/progress/text.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index 1316952c..a121eaaa 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -99,6 +99,7 @@ class AcquireProgress(apt_pkg.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_pkg.AcquireProgress.start(self) import signal self._signal = signal.signal(signal.SIGWINCH, self._winch) # Get the window size. @@ -116,6 +117,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def ims_hit(self, item): """Called when an item is update (e.g. not modified on the server).""" + apt_pkg.AcquireProgress.ims_hit(self, item) line = _('Hit ') + item.description if item.owner.filesize: line += ' [%sB]' % apt_pkg.size_to_str(item.owner.filesize) @@ -123,6 +125,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def fail(self, item): """Called when an item is failed.""" + apt_pkg.AcquireProgress.fail(self, item) if item.owner.status == item.owner.stat_done: self._write(_("Ign ") + item.description) else: @@ -131,6 +134,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def fetch(self, item): """Called when some of the item's data is fetched.""" + apt_pkg.AcquireProgress.fetch(self, item) # It's complete already (e.g. Hit) if item.owner.complete: return @@ -146,7 +150,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): """Periodically invoked while the Acquire process is underway. Return False if the user asked to cancel the whole Acquire process.""" - + apt_pkg.AcquireProgress.pulse(self, owner) percent = (((self.current_bytes + self.current_items) * 100.0) / float(self.total_bytes + self.total_items)) @@ -206,6 +210,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def media_change(self, medium, drive): """Prompt the user to change the inserted removable media.""" + apt_pkg.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)) @@ -213,6 +218,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def stop(self): """Invoked when the Acquire process stops running.""" + apt_pkg.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,6 +235,7 @@ class CdromProgress(apt_pkg.CdromProgress, TextProgress): def ask_cdrom_name(self): """Ask the user to provide a name for the disc.""" + apt_pkg.CdromProgress.ask_cdrom_name(self) self._write(_("Please provide a name for this Disc, such as " "'Debian 2.1r1 Disk 1'"), False) try: @@ -238,11 +245,13 @@ class CdromProgress(apt_pkg.CdromProgress, TextProgress): def update(self, text, current): """Set the current progress.""" + apt_pkg.CdromProgress.change_cdrom(self, text, current) if text: self._write(text, False) def change_cdrom(self): """Ask the user to change the CD-ROM.""" + apt_pkg.CdromProgress.change_cdrom(self) self._write(_("Please insert a Disc in the drive and press enter"), False) try: -- cgit v1.2.3 From 1195d1d5b3b9c22d1756ba13780cb553c3d4d168 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Thu, 23 Jul 2009 16:47:13 +0200 Subject: python/cdrom.cc: Do not check arguments in PkgCdromNew. --- apt/progress/text.py | 2 +- python/cdrom.cc | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index a121eaaa..c9e2882b 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -245,7 +245,7 @@ class CdromProgress(apt_pkg.CdromProgress, TextProgress): def update(self, text, current): """Set the current progress.""" - apt_pkg.CdromProgress.change_cdrom(self, text, current) + apt_pkg.CdromProgress.update(self, text, current) if text: self._write(text, False) diff --git a/python/cdrom.cc b/python/cdrom.cc index bd181af7..5044f3fa 100644 --- a/python/cdrom.cc +++ b/python/cdrom.cc @@ -91,10 +91,6 @@ static PyObject *PkgCdromNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) { pkgCdrom *cdrom = new pkgCdrom(); - char *kwlist[] = {NULL}; - if (PyArg_ParseTupleAndKeywords(Args,kwds,"",kwlist) == 0) - return 0; - CppOwnedPyObject *CdromObj = CppOwnedPyObject_NEW(0,type, *cdrom); -- cgit v1.2.3 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 +++++++++++++++++++++++++++++++++++++++++++++++++++ apt/progress/text.py | 39 ++++++------ 2 files changed, 183 insertions(+), 20 deletions(-) create mode 100644 apt/progress/base.py (limited to 'apt/progress/text.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.""" diff --git a/apt/progress/text.py b/apt/progress/text.py index c9e2882b..54a35704 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -18,8 +18,9 @@ import sys import apt_pkg +import apt.progress.base -__all__ = ['AcquireProgress', 'OpProgress'] +__all__ = ['AcquireProgress', 'CdromProgress', 'OpProgress'] def _(msg): @@ -54,7 +55,7 @@ class TextProgress(object): self._file.flush() -class OpProgress(apt_pkg.OpProgress, TextProgress): +class OpProgress(apt.progress.base.OpProgress, TextProgress): """Operation progress reporting. This closely resembles OpTextProgress in libapt-pkg. @@ -62,14 +63,12 @@ class OpProgress(apt_pkg.OpProgress, TextProgress): def __init__(self, outfile=None): TextProgress.__init__(self, outfile) - apt_pkg.OpProgress.__init__(self) + apt.progress.base.OpProgress.__init__(self) self.old_op = "" def update(self, percent=None): """Called periodically to update the user interface.""" - if percent: - self.percent = percent - apt_pkg.OpProgress.update(self) + apt.progress.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) @@ -77,18 +76,18 @@ class OpProgress(apt_pkg.OpProgress, TextProgress): def done(self): """Called once an operation has been completed.""" - apt_pkg.OpProgress.done(self) + apt.progress.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_pkg.AcquireProgress, TextProgress): +class AcquireProgress(apt.progress.base.AcquireProgress, TextProgress): """AcquireProgress for the text interface.""" def __init__(self, outfile=None): TextProgress.__init__(self, outfile) - apt_pkg.AcquireProgress.__init__(self) + apt.progress.base.AcquireProgress.__init__(self) self._signal = None self._width = 80 self._id = 1 @@ -99,7 +98,7 @@ class AcquireProgress(apt_pkg.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_pkg.AcquireProgress.start(self) + apt.progress.base.AcquireProgress.start(self) import signal self._signal = signal.signal(signal.SIGWINCH, self._winch) # Get the window size. @@ -117,7 +116,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def ims_hit(self, item): """Called when an item is update (e.g. not modified on the server).""" - apt_pkg.AcquireProgress.ims_hit(self, item) + apt.progress.base.AcquireProgress.ims_hit(self, item) line = _('Hit ') + item.description if item.owner.filesize: line += ' [%sB]' % apt_pkg.size_to_str(item.owner.filesize) @@ -125,7 +124,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def fail(self, item): """Called when an item is failed.""" - apt_pkg.AcquireProgress.fail(self, item) + apt.progress.base.AcquireProgress.fail(self, item) if item.owner.status == item.owner.stat_done: self._write(_("Ign ") + item.description) else: @@ -134,7 +133,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def fetch(self, item): """Called when some of the item's data is fetched.""" - apt_pkg.AcquireProgress.fetch(self, item) + apt.progress.base.AcquireProgress.fetch(self, item) # It's complete already (e.g. Hit) if item.owner.complete: return @@ -150,7 +149,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): """Periodically invoked while the Acquire process is underway. Return False if the user asked to cancel the whole Acquire process.""" - apt_pkg.AcquireProgress.pulse(self, owner) + apt.progress.base.AcquireProgress.pulse(self, owner) percent = (((self.current_bytes + self.current_items) * 100.0) / float(self.total_bytes + self.total_items)) @@ -210,7 +209,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def media_change(self, medium, drive): """Prompt the user to change the inserted removable media.""" - apt_pkg.AcquireProgress.media_change(self, medium, drive) + apt.progress.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)) @@ -218,7 +217,7 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): def stop(self): """Invoked when the Acquire process stops running.""" - apt_pkg.AcquireProgress.stop(self) + apt.progress.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), @@ -230,12 +229,12 @@ class AcquireProgress(apt_pkg.AcquireProgress, TextProgress): signal.signal(signal.SIGWINCH, self._signal) -class CdromProgress(apt_pkg.CdromProgress, TextProgress): +class CdromProgress(apt.progress.base.CdromProgress, TextProgress): """Text CD-ROM progress.""" def ask_cdrom_name(self): """Ask the user to provide a name for the disc.""" - apt_pkg.CdromProgress.ask_cdrom_name(self) + apt.progress.base.CdromProgress.ask_cdrom_name(self) self._write(_("Please provide a name for this Disc, such as " "'Debian 2.1r1 Disk 1'"), False) try: @@ -245,13 +244,13 @@ class CdromProgress(apt_pkg.CdromProgress, TextProgress): def update(self, text, current): """Set the current progress.""" - apt_pkg.CdromProgress.update(self, text, current) + apt.progress.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_pkg.CdromProgress.change_cdrom(self) + apt.progress.base.CdromProgress.change_cdrom(self) self._write(_("Please insert a Disc in the drive and press enter"), False) try: -- 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/text.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 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/text.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/text.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 3c0c2fa47e2a519005f4c07dac8b1e09c86eeee4 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Sun, 17 Jan 2010 15:48:16 +0100 Subject: apt/progress/text.py: Replace one print statement with a .write() call. --- apt/progress/text.py | 2 +- debian/changelog | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'apt/progress/text.py') diff --git a/apt/progress/text.py b/apt/progress/text.py index 796577e2..5e45c1db 100644 --- a/apt/progress/text.py +++ b/apt/progress/text.py @@ -41,7 +41,7 @@ class TextProgress(object): def _write(self, msg, newline=True, maximize=False): """Write the message on the terminal, fill remaining space.""" self._file.write("\r") - print >> self._file, msg, + self._file.write(msg) # Fill remaining stuff with whitespace if self._width > len(msg): diff --git a/debian/changelog b/debian/changelog index 5001f1fe..7b711e1d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -16,6 +16,8 @@ python-apt (0.7.93) UNRELEASED; urgency=low - distro.py: Support Python 3, decode lsb_release results using utf-8. * apt/progress/base.py: - Fix some parsing of dpkg status fd. + * apt/progress/text.py: + - Replace one print statement with a .write() call. [ Colin Watson ] * apt/progress/__init__.py: -- cgit v1.2.3