summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apt/progress/__init__.py20
-rw-r--r--debian/changelog14
-rw-r--r--doc/examples/progress.py18
-rw-r--r--po/python-apt.pot20
-rw-r--r--python/progress.cc124
5 files changed, 179 insertions, 17 deletions
diff --git a/apt/progress/__init__.py b/apt/progress/__init__.py
index 6e4c6eec..47d2a861 100644
--- a/apt/progress/__init__.py
+++ b/apt/progress/__init__.py
@@ -116,6 +116,13 @@ class FetchProgress(object):
This happens eg. when the downloads fails or is completed.
"""
+ def update_status_full(self, uri, descr, short_descr, status, file_size,
+ partial_size):
+ """Called when the status of an item changes.
+
+ This happens eg. when the downloads fails or is completed. This
+ version include information on current filesize and partial size
+ """
def pulse(self):
"""Called periodically to update the user interface.
@@ -129,6 +136,19 @@ class FetchProgress(object):
float(self.current_cps))
return True
+ def pulse_items(self, items):
+ """Called periodically to update the user interface.
+ This function includes details about the items being fetched
+ Return True to continue or False to cancel.
+
+ """
+ self.percent = (((self.current_bytes + self.current_items) * 100.0) /
+ float(self.total_bytes + self.total_items))
+ if self.current_cps > 0:
+ self.eta = ((self.total_bytes - self.current_bytes) /
+ float(self.current_cps))
+ return True
+
def media_change(self, medium, drive):
"""react to media change events."""
diff --git a/debian/changelog b/debian/changelog
index 55e68a52..ca215554 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -36,6 +36,20 @@ python-apt (0.7.90) experimental; urgency=low
-- Julian Andres Klode <jak@debian.org> Wed, 15 Apr 2009 13:47:42 +0200
+python-apt (0.7.10.4) UNRELEASED; urgency=low
+
+ [ Stephan Peijnik ]
+ * apt/progress/__init__.py:
+ - add update_status_full() that takes file_size/partial_size as
+ additional callback arguments
+ - add pulse_items() that takes a addtional "items" tuple that
+ gives the user full access to the individual items that are
+ fetched
+ * python/progress.cc:
+ - low level code for update_status_full and pulse_items()
+
+ -- Michael Vogt <michael.vogt@ubuntu.com> Tue, 05 May 2009 11:57:57 +0200
+
python-apt (0.7.10.3) unstable; urgency=low
* apt/package.py: Handle cases where no candidate is available, by returning
diff --git a/doc/examples/progress.py b/doc/examples/progress.py
index 2231001f..c007681f 100644
--- a/doc/examples/progress.py
+++ b/doc/examples/progress.py
@@ -35,15 +35,31 @@ class TextFetchProgress(apt.FetchProgress):
pass
def updateStatus(self, uri, descr, shortDescr, status):
- print "UpdateStatus: '%s' '%s' '%s' '%i'" % (
+ print "UpdateStatus: '%s' '%s' '%s' '%i' " % (
uri, descr, shortDescr, status)
+ def update_status_full(self, uri, descr, shortDescr, status, fileSize,
+ partialSize):
+ print "update_status_full: '%s' '%s' '%s' '%i' '%d/%d'" % (
+ uri, descr, shortDescr, status, partialSize, fileSize)
+
def pulse(self):
print "Pulse: CPS: %s/s; Bytes: %s/%s; Item: %s/%s" % (
apt.SizeToStr(self.currentCPS), apt.SizeToStr(self.currentBytes),
apt.SizeToStr(self.totalBytes), self.currentItems, self.totalItems)
return True
+ def pulse_items(self, items):
+ print "Pulse: CPS: %s/s; Bytes: %s/%s; Item: %s/%s" % (
+ apt.SizeToStr(self.currentCPS), apt.SizeToStr(self.currentBytes),
+ apt.SizeToStr(self.totalBytes), self.currentItems, self.totalItems)
+ print "Pulse-Items: "
+ for itm in items:
+ uri, descr, shortDescr, fileSize, partialSize = itm
+ print " - '%s' '%s' '%s' '%d/%d'" % (
+ uri, descr, shortDescr, partialSize, fileSize)
+ return True
+
def mediaChange(self, medium, drive):
print "Please insert medium %s in drive %s" % (medium, drive)
sys.stdin.readline()
diff --git a/po/python-apt.pot b/po/python-apt.pot
index 3fcd395a..5920f93a 100644
--- a/po/python-apt.pot
+++ b/po/python-apt.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2009-04-16 19:54+0200\n"
+"POT-Creation-Date: 2009-06-08 16:52+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -331,39 +331,39 @@ msgstr ""
msgid "Custom servers"
msgstr ""
-#: ../apt/progress/gtk2.py:246
+#: ../apt/progress/gtk2.py:258
#, python-format
msgid "Downloading file %(current)li of %(total)li with %(speed)s/s"
msgstr ""
-#: ../apt/progress/gtk2.py:252
+#: ../apt/progress/gtk2.py:264
#, python-format
msgid "Downloading file %(current)li of %(total)li"
msgstr ""
#. Setup some child widgets
-#: ../apt/progress/gtk2.py:272
+#: ../apt/progress/gtk2.py:284
msgid "Details"
msgstr ""
-#: ../apt/progress/gtk2.py:354
+#: ../apt/progress/gtk2.py:366
msgid "Starting..."
msgstr ""
-#: ../apt/progress/gtk2.py:360
+#: ../apt/progress/gtk2.py:372
msgid "Complete"
msgstr ""
-#: ../apt/package.py:286
+#: ../apt/package.py:301
#, python-format
msgid "Invalid unicode in description for '%s' (%s). Please report."
msgstr ""
-#: ../apt/package.py:846 ../apt/package.py:950
+#: ../apt/package.py:861 ../apt/package.py:965
msgid "The list of changes is not available"
msgstr ""
-#: ../apt/package.py:954
+#: ../apt/package.py:969
#, python-format
msgid ""
"The list of changes is not available yet.\n"
@@ -372,7 +372,7 @@ msgid ""
"until the changes become available or try again later."
msgstr ""
-#: ../apt/package.py:960
+#: ../apt/package.py:975
msgid ""
"Failed to download the list of changes. \n"
"Please check your Internet connection."
diff --git a/python/progress.cc b/python/progress.cc
index 8214a789..39124df1 100644
--- a/python/progress.cc
+++ b/python/progress.cc
@@ -9,7 +9,10 @@
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
+#include <map>
+#include <utility>
#include <apt-pkg/acquire-item.h>
+#include <apt-pkg/acquire-worker.h>
#include "progress.h"
// generic
@@ -30,14 +33,16 @@ bool PyCallbackObj::RunSimpleCallback(const char* method_name,
return false;
}
PyObject *result = PyEval_CallObject(method, arglist);
+
Py_XDECREF(arglist);
if(result == NULL) {
// exception happend
std::cerr << "Error in function " << method_name << std::endl;
PyErr_Print();
+ PyErr_Clear();
- return NULL;
+ return false;
}
if(res != NULL)
*res = result;
@@ -89,6 +94,7 @@ void PyOpProgress::Done()
// apt interface
+
bool PyFetchProgress::MediaChange(string Media, string Drive)
{
//std::cout << "MediaChange" << std::endl;
@@ -112,7 +118,24 @@ bool PyFetchProgress::MediaChange(string Media, string Drive)
void PyFetchProgress::UpdateStatus(pkgAcquire::ItemDesc &Itm, int status)
{
//std::cout << "UpdateStatus: " << Itm.URI << " " << status << std::endl;
- PyObject *arglist = Py_BuildValue("(sssi)", Itm.URI.c_str(), Itm.Description.c_str(), Itm.ShortDesc.c_str(), status);
+
+ // Added object file size and object partial size to
+ // parameters that are passed to updateStatus.
+ // -- Stephan
+ PyObject *arglist = Py_BuildValue("(sssikk)", Itm.URI.c_str(),
+ Itm.Description.c_str(),
+ Itm.ShortDesc.c_str(),
+ status,
+ Itm.Owner->FileSize,
+ Itm.Owner->PartialSize);
+
+ RunSimpleCallback("update_status_full", arglist);
+
+ // legacy version of the interface
+ arglist = Py_BuildValue("(sssi)", Itm.URI.c_str(),
+ Itm.Description.c_str(),
+ Itm.ShortDesc.c_str(),
+ status);
if(PyObject_HasAttrString(callbackInst, "update_status"))
RunSimpleCallback("update_status", arglist);
else
@@ -152,6 +175,28 @@ void PyFetchProgress::Start()
{
//std::cout << "Start" << std::endl;
pkgAcquireStatus::Start();
+
+ // These attributes should be initialized before the first callback (start)
+ // is invoked.
+ // -- Stephan
+ PyObject *o;
+
+ o = Py_BuildValue("f", 0.0f);
+ PyObject_SetAttrString(callbackInst, "currentCPS", o);
+ Py_XDECREF(o);
+ o = Py_BuildValue("f", 0.0f);
+ PyObject_SetAttrString(callbackInst, "currentBytes", o);
+ Py_XDECREF(o);
+ o = Py_BuildValue("i", 0);
+ PyObject_SetAttrString(callbackInst, "currentItems", o);
+ Py_XDECREF(o);
+ o = Py_BuildValue("i", 0);
+ PyObject_SetAttrString(callbackInst, "totalItems", o);
+ Py_XDECREF(o);
+ o = Py_BuildValue("f", 0.0f);
+ PyObject_SetAttrString(callbackInst, "totalBytes", o);
+ Py_XDECREF(o);
+
RunSimpleCallback("start");
}
@@ -204,12 +249,79 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
PyObject_SetAttrString(callbackInst, "totalBytes", o);
Py_XDECREF(o);
- PyObject *arglist = Py_BuildValue("()");
- PyObject *result;
- RunSimpleCallback("pulse", arglist, &result);
+ // Go through the list of items and add active items to the
+ // activeItems vector.
+ map<pkgAcquire::Worker *, pkgAcquire::ItemDesc *> activeItemMap;
+ for(pkgAcquire::Worker *Worker = Owner->WorkersBegin();
+ Worker != 0; Worker = Owner->WorkerStep(Worker)) {
+
+ if (Worker->CurrentItem == 0) {
+ // Ignore workers with no item running
+ continue;
+ }
+ activeItemMap.insert(std::make_pair(Worker, Worker->CurrentItem));
+ }
+
+ // Create the tuple that is passed as argument to pulse().
+ // This tuple contains activeItemMap.size() item tuples.
+ PyObject *arglist;
+
+ if (((int)activeItemMap.size()) > 0) {
+ PyObject *itemsTuple = PyTuple_New((Py_ssize_t) activeItemMap.size());
+
+ // Go through activeItems, create an item tuple in the form
+ // (URI, Description, ShortDesc, FileSize, PartialSize) and
+ // add that tuple to itemsTuple.
+ map<pkgAcquire::Worker *, pkgAcquire::ItemDesc *>::iterator iter;
+ int tuplePos;
+
+ for(tuplePos = 0, iter = activeItemMap.begin();
+ iter != activeItemMap.end(); ++iter, tuplePos++) {
+ pkgAcquire::Worker *worker = iter->first;
+ pkgAcquire::ItemDesc *itm = iter->second;
+
+ PyObject *itmTuple = Py_BuildValue("(ssskk)", itm->URI.c_str(),
+ itm->Description.c_str(),
+ itm->ShortDesc.c_str(),
+ worker->TotalSize,
+ worker->CurrentSize);
+ PyTuple_SetItem(itemsTuple, tuplePos, itmTuple);
+ }
+
+ // Now our itemsTuple is ready for being passed to pulse().
+ // pulse() is going to receive a single argument, being the
+ // tuple of items, which again contains one tuple with item
+ // information per item.
+ //
+ // Python Example:
+ //
+ // class MyFetchProgress(FetchProgress):
+ // def pulse(self, items):
+ // for itm in items:
+ // uri, desc, shortdesc, filesize, partialsize = itm
+ //
+ arglist = PyTuple_Pack(1, itemsTuple);
+ }
+ else {
+ arglist = Py_BuildValue("(())");
+ }
+
+ PyObject *result;
bool res = true;
- if(!PyArg_Parse(result, "b", &res))
+
+ RunSimpleCallback("pulse_items", arglist, &result);
+ if (result != NULL && PyArg_Parse(result, "b", &res) && res == false) {
+ // the user returned a explicit false here, stop
+ return false;
+ }
+
+ arglist = Py_BuildValue("()");
+ if (!RunSimpleCallback("pulse", arglist, &result)) {
+ return true;
+ }
+
+ if((result == NULL) || (!PyArg_Parse(result, "b", &res)))
{
// most of the time the user who subclasses the pulse()
// method forgot to add a return {True,False} so we just