summaryrefslogtreecommitdiff
path: root/python/progress.cc
diff options
context:
space:
mode:
authorMichael Vogt <michael.vogt@ubuntu.com>2010-03-23 14:18:44 +0100
committerMichael Vogt <michael.vogt@ubuntu.com>2010-03-23 14:18:44 +0100
commit37650a078f5504dfbc6622d2c06f4435a3302dd4 (patch)
tree35d7df75535420cbe0712a5f7b7b66d61f5e44d1 /python/progress.cc
parent2aa709e41d8896ef897863ea9181c409c4c87a8c (diff)
parent3a08cfb10590d5cf5df1f45d94a424ef6a0f674b (diff)
downloadpython-apt-37650a078f5504dfbc6622d2c06f4435a3302dd4.tar.gz
merged from lp:~mvo/python-apt/mvo
Diffstat (limited to 'python/progress.cc')
-rw-r--r--python/progress.cc329
1 files changed, 213 insertions, 116 deletions
diff --git a/python/progress.cc b/python/progress.cc
index 82967687..097f06cf 100644
--- a/python/progress.cc
+++ b/python/progress.cc
@@ -5,7 +5,7 @@
Progress - Wrapper for the progress related functions
##################################################################### */
-
+#include <Python.h>
#include <iostream>
#include <sys/types.h>
#include <sys/wait.h>
@@ -13,8 +13,32 @@
#include <utility>
#include <apt-pkg/acquire-item.h>
#include <apt-pkg/acquire-worker.h>
-#include "generic.h"
#include "progress.h"
+#include "generic.h"
+#include "apt_pkgmodule.h"
+
+/**
+ * Set an attribute on an object, after creating the value with
+ * Py_BuildValue(fmt, arg). Afterwards, decrease its refcount and return
+ * whether setting the attribute was successful.
+ */
+template<class T>
+inline bool setattr(PyObject *object, const char *attr, const char *fmt, T arg)
+{
+ if (!object)
+ return false;
+ PyObject *value = Py_BuildValue(fmt, arg);
+
+ int result = PyObject_SetAttrString(object, attr, value);
+ Py_DECREF(value);
+ return result != -1;
+}
+
+inline PyObject *TUPLEIZE(PyObject *op) {
+ PyObject *ret = Py_BuildValue("(O)", op);
+ Py_DECREF(op);
+ return ret;
+}
// generic
bool PyCallbackObj::RunSimpleCallback(const char* method_name,
@@ -36,8 +60,8 @@ bool PyCallbackObj::RunSimpleCallback(const char* method_name,
}
return false;
}
- PyObject *result = PyEval_CallObject(method, arglist);
-
+
+ PyObject *result = PyObject_CallObject(method, arglist);
Py_XDECREF(arglist);
if(result == NULL) {
@@ -61,26 +85,24 @@ bool PyCallbackObj::RunSimpleCallback(const char* method_name,
// OpProgress interface
void PyOpProgress::Update()
{
- PyObject *o;
- o = Py_BuildValue("s", Op.c_str());
- PyObject_SetAttrString(callbackInst, "op", o);
- Py_XDECREF(o);
- o = Py_BuildValue("s", SubOp.c_str());
- PyObject_SetAttrString(callbackInst, "subOp", o);
- Py_XDECREF(o);
- o = Py_BuildValue("b", MajorChange);
- PyObject_SetAttrString(callbackInst, "majorChange", o);
- Py_XDECREF(o);
-
- // CheckChange takes a time delta argument how often we
- // should run update - for interactive UIs it makes sense
- // to run ~25/sec
- if(CheckChange(0.04))
- {
- PyObject *arglist = Py_BuildValue("(f)", Percent);
- RunSimpleCallback("update", arglist);
- }
-};
+ // Build up the argument list...
+ if(!CheckChange(0.7))
+ return;
+
+ setattr(callbackInst, "op", "s", Op.c_str());
+ setattr(callbackInst, "subop", "s", SubOp.c_str());
+ setattr(callbackInst, "major_change", "b", MajorChange);
+ setattr(callbackInst, "percent", "f", Percent);
+#ifdef COMPAT_0_7
+ setattr(callbackInst, "Op", "s", Op.c_str());
+ setattr(callbackInst, "subOp", "s", SubOp.c_str());
+ setattr(callbackInst, "majorChange", "b", MajorChange);
+ PyObject *arglist = Py_BuildValue("(f)", Percent);
+ RunSimpleCallback("update", arglist);
+#else
+ RunSimpleCallback("update");
+#endif
+}
void PyOpProgress::Done()
{
@@ -95,17 +117,32 @@ void PyOpProgress::Done()
// apt interface
+PyObject *PyFetchProgress::GetDesc(pkgAcquire::ItemDesc *item) {
+ if (!pyAcquire && item->Owner && item->Owner->GetOwner()) {
+ pyAcquire = PyAcquire_FromCpp(item->Owner->GetOwner(), false, NULL);
+ }
+ PyObject *pyItem = PyAcquireItem_FromCpp(item->Owner, false, pyAcquire);
+ PyObject *pyDesc = PyAcquireItemDesc_FromCpp(item, false, pyItem);
+ Py_DECREF(pyItem);
+ return pyDesc;
+}
+
bool PyFetchProgress::MediaChange(string Media, string Drive)
{
PyCbObj_END_ALLOW_THREADS
//std::cout << "MediaChange" << std::endl;
PyObject *arglist = Py_BuildValue("(ss)", Media.c_str(), Drive.c_str());
PyObject *result;
- RunSimpleCallback("mediaChange", arglist, &result);
+
+ if(PyObject_HasAttrString(callbackInst, "mediaChange"))
+ RunSimpleCallback("mediaChange", arglist, &result);
+ else
+ RunSimpleCallback("media_change", arglist, &result);
bool res = true;
if(!PyArg_Parse(result, "b", &res)) {
// no return value or None, assume false
+ PyCbObj_BEGIN_ALLOW_THREADS
return false;
}
@@ -116,14 +153,12 @@ bool PyFetchProgress::MediaChange(string Media, string Drive)
void PyFetchProgress::UpdateStatus(pkgAcquire::ItemDesc &Itm, int status)
{
//std::cout << "UpdateStatus: " << Itm.URI << " " << status << std::endl;
-
// Added object file size and object partial size to
// parameters that are passed to updateStatus.
// -- Stephan
- PyCbObj_END_ALLOW_THREADS
- PyObject *arglist = Py_BuildValue("(sssikk)", Itm.URI.c_str(),
- Itm.Description.c_str(),
- Itm.ShortDesc.c_str(),
+ PyObject *arglist = Py_BuildValue("(sssikk)", Itm.URI.c_str(),
+ Itm.Description.c_str(),
+ Itm.ShortDesc.c_str(),
status,
Itm.Owner->FileSize,
Itm.Owner->PartialSize);
@@ -131,42 +166,72 @@ void PyFetchProgress::UpdateStatus(pkgAcquire::ItemDesc &Itm, int status)
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);
- RunSimpleCallback("updateStatus", arglist);
- PyCbObj_BEGIN_ALLOW_THREADS
+ arglist = Py_BuildValue("(sssi)", Itm.URI.c_str(), Itm.Description.c_str(),
+ Itm.ShortDesc.c_str(), status);
+
+ if(PyObject_HasAttrString(callbackInst, "updateStatus"))
+ RunSimpleCallback("updateStatus", arglist);
+ else
+ RunSimpleCallback("update_status", arglist);
}
void PyFetchProgress::IMSHit(pkgAcquire::ItemDesc &Itm)
{
- UpdateStatus(Itm, DLHit);
+ PyCbObj_END_ALLOW_THREADS
+ if (PyObject_HasAttrString(callbackInst, "ims_hit"))
+ RunSimpleCallback("ims_hit", TUPLEIZE(GetDesc(&Itm)));
+ else
+ UpdateStatus(Itm, DLHit);
+ PyCbObj_BEGIN_ALLOW_THREADS
}
void PyFetchProgress::Fetch(pkgAcquire::ItemDesc &Itm)
{
- UpdateStatus(Itm, DLQueued);
+ PyCbObj_END_ALLOW_THREADS
+ if (PyObject_HasAttrString(callbackInst, "fetch"))
+ RunSimpleCallback("fetch", TUPLEIZE(GetDesc(&Itm)));
+ else
+ UpdateStatus(Itm, DLQueued);
+ PyCbObj_BEGIN_ALLOW_THREADS
}
void PyFetchProgress::Done(pkgAcquire::ItemDesc &Itm)
{
- UpdateStatus(Itm, DLDone);
+ PyCbObj_END_ALLOW_THREADS
+ if (PyObject_HasAttrString(callbackInst, "done"))
+ RunSimpleCallback("done", TUPLEIZE(GetDesc(&Itm)));
+ else
+ UpdateStatus(Itm, DLDone);
+ PyCbObj_BEGIN_ALLOW_THREADS
}
void PyFetchProgress::Fail(pkgAcquire::ItemDesc &Itm)
{
+ PyCbObj_END_ALLOW_THREADS
+ if (PyObject_HasAttrString(callbackInst, "fail")) {
+ RunSimpleCallback("fail", TUPLEIZE(GetDesc(&Itm)));
+ PyCbObj_BEGIN_ALLOW_THREADS
+ return;
+ }
+
// Ignore certain kinds of transient failures (bad code)
- if (Itm.Owner->Status == pkgAcquire::Item::StatIdle)
+ if (Itm.Owner->Status == pkgAcquire::Item::StatIdle) {
+ PyCbObj_BEGIN_ALLOW_THREADS
return;
+ }
if (Itm.Owner->Status == pkgAcquire::Item::StatDone)
{
UpdateStatus(Itm, DLIgnored);
}
- UpdateStatus(Itm, DLFailed);
+
+ if (PyObject_HasAttrString(callbackInst, "fail"))
+ RunSimpleCallback("fail", TUPLEIZE(GetDesc(&Itm)));
+ else
+ UpdateStatus(Itm, DLFailed);
+ PyCbObj_BEGIN_ALLOW_THREADS
}
void PyFetchProgress::Start()
@@ -174,26 +239,13 @@ 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);
+#ifdef COMPAT_0_7
+ setattr(callbackInst, "currentCPS", "d", 0);
+ setattr(callbackInst, "currentBytes", "d", 0);
+ setattr(callbackInst, "currentItems", "k", 0);
+ setattr(callbackInst, "totalItems", "k", 0);
+ setattr(callbackInst, "totalBytes", "d", 0);
+#endif
RunSimpleCallback("start");
/* After calling the start method we can safely allow
@@ -206,10 +258,11 @@ void PyFetchProgress::Start()
void PyFetchProgress::Stop()
{
/* After the stop operation occured no other threads
- * are allowed. This is done so we have a matching
+ * are allowed. This is done so we have a matching
* PyCbObj_END_ALLOW_THREADS to our previous
* PyCbObj_BEGIN_ALLOW_THREADS (Python requires this!).
*/
+
PyCbObj_END_ALLOW_THREADS
//std::cout << "Stop" << std::endl;
pkgAcquireStatus::Stop();
@@ -222,31 +275,51 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
pkgAcquireStatus::Pulse(Owner);
//std::cout << "Pulse" << std::endl;
- if(callbackInst == 0)
+ if(callbackInst == 0) {
+ PyCbObj_BEGIN_ALLOW_THREADS
return false;
+ }
- // set stats
- PyObject *o;
- o = Py_BuildValue("f", CurrentCPS);
- PyObject_SetAttrString(callbackInst, "currentCPS", o);
- Py_XDECREF(o);
- o = Py_BuildValue("f", CurrentBytes);
- PyObject_SetAttrString(callbackInst, "currentBytes", o);
- Py_XDECREF(o);
- o = Py_BuildValue("i", CurrentItems);
- PyObject_SetAttrString(callbackInst, "currentItems", o);
- Py_XDECREF(o);
- o = Py_BuildValue("i", TotalItems);
- PyObject_SetAttrString(callbackInst, "totalItems", o);
- Py_XDECREF(o);
- o = Py_BuildValue("f", TotalBytes);
- PyObject_SetAttrString(callbackInst, "totalBytes", o);
- Py_XDECREF(o);
+ setattr(callbackInst, "last_bytes", "d", LastBytes);
+ setattr(callbackInst, "current_cps", "d", CurrentCPS);
+ setattr(callbackInst, "current_bytes", "d", CurrentBytes);
+ setattr(callbackInst, "total_bytes", "d", TotalBytes);
+ setattr(callbackInst, "fetched_bytes", "d", FetchedBytes);
+ setattr(callbackInst, "elapsed_time", "k", ElapsedTime);
+ setattr(callbackInst, "current_items", "k", CurrentItems);
+ setattr(callbackInst, "total_items", "k", TotalItems);
+
+ // New style
+ if (!PyObject_HasAttrString(callbackInst, "updateStatus")) {
+ PyObject *result1;
+ bool res1 = true;
+
+ if (pyAcquire == NULL) {
+ pyAcquire = PyAcquire_FromCpp(Owner, false, NULL);
+ }
+ Py_INCREF(pyAcquire);
+ if (RunSimpleCallback("pulse", TUPLEIZE(pyAcquire) , &result1)) {
+ if (result1 != NULL && PyArg_Parse(result1, "b", &res1) && res1 == false) {
+ // the user returned a explicit false here, stop
+ PyCbObj_BEGIN_ALLOW_THREADS
+ return false;
+ }
+ }
+ PyCbObj_BEGIN_ALLOW_THREADS
+ return true;
+ }
+#ifdef COMPAT_0_7
+ setattr(callbackInst, "currentCPS", "d", CurrentCPS);
+ setattr(callbackInst, "currentBytes", "d", CurrentBytes);
+ setattr(callbackInst, "totalBytes", "d", TotalBytes);
+ setattr(callbackInst, "fetchedBytes", "d", FetchedBytes);
+ setattr(callbackInst, "currentItems", "k", CurrentItems);
+ setattr(callbackInst, "totalItems", "k", TotalItems);
// 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)) {
@@ -256,7 +329,7 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
}
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;
@@ -270,8 +343,8 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
map<pkgAcquire::Worker *, pkgAcquire::ItemDesc *>::iterator iter;
int tuplePos;
- for(tuplePos = 0, iter = activeItemMap.begin();
- iter != activeItemMap.end(); ++iter, tuplePos++) {
+ for(tuplePos = 0, iter = activeItemMap.begin();
+ iter != activeItemMap.end(); ++iter, tuplePos++) {
pkgAcquire::Worker *worker = iter->first;
pkgAcquire::ItemDesc *itm = iter->second;
@@ -304,13 +377,15 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
PyObject *result;
bool res = true;
- RunSimpleCallback("pulse_items", arglist, &result);
- if (result != NULL && PyArg_Parse(result, "b", &res) && res == false) {
- // the user returned a explicit false here, stop
- PyCbObj_BEGIN_ALLOW_THREADS
- return false;
+ if (RunSimpleCallback("pulse_items", arglist, &result)) {
+ if (result != NULL && PyArg_Parse(result, "b", &res) && res == false) {
+ // the user returned a explicit false here, stop
+ PyCbObj_BEGIN_ALLOW_THREADS
+ return false;
+ }
}
+
arglist = Py_BuildValue("()");
if (!RunSimpleCallback("pulse", arglist, &result)) {
PyCbObj_BEGIN_ALLOW_THREADS
@@ -319,7 +394,7 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
if((result == NULL) || (!PyArg_Parse(result, "b", &res)))
{
- // most of the time the user who subclasses the pulse()
+ // most of the time the user who subclasses the pulse()
// method forgot to add a return {True,False} so we just
// assume he wants a True
PyCbObj_BEGIN_ALLOW_THREADS
@@ -329,6 +404,9 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
PyCbObj_BEGIN_ALLOW_THREADS
// fetching can be canceld by returning false
return res;
+#else
+ return false;
+#endif
}
@@ -337,26 +415,28 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
void PyInstallProgress::StartUpdate()
{
- RunSimpleCallback("startUpdate");
+ if (!RunSimpleCallback("startUpdate"))
+ RunSimpleCallback("start_update");
PyCbObj_BEGIN_ALLOW_THREADS
}
void PyInstallProgress::UpdateInterface()
{
PyCbObj_END_ALLOW_THREADS
- RunSimpleCallback("updateInterface");
+ if (!RunSimpleCallback("updateInterface"))
+ RunSimpleCallback("update_interface");
PyCbObj_BEGIN_ALLOW_THREADS
}
void PyInstallProgress::FinishUpdate()
{
PyCbObj_END_ALLOW_THREADS
- RunSimpleCallback("finishUpdate");
+ if (!RunSimpleCallback("finishUpdate"))
+ RunSimpleCallback("finish_update");
}
pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm)
{
- void *dummy;
pkgPackageManager::OrderResult res;
int ret;
pid_t child_id;
@@ -372,7 +452,7 @@ pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm)
PyObject *method = PyObject_GetAttrString(callbackInst, "fork");
std::cerr << "custom fork found" << std::endl;
PyObject *arglist = Py_BuildValue("()");
- PyObject *result = PyEval_CallObject(method, arglist);
+ PyObject *result = PyObject_CallObject(method, arglist);
Py_DECREF(arglist);
if (result == NULL) {
std::cerr << "fork method invalid" << std::endl;
@@ -412,18 +492,23 @@ pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm)
StartUpdate();
PyCbObj_END_ALLOW_THREADS
- if(PyObject_HasAttrString(callbackInst, "waitChild")) {
- PyObject *method = PyObject_GetAttrString(callbackInst, "waitChild");
+ if(PyObject_HasAttrString(callbackInst, "waitChild") ||
+ PyObject_HasAttrString(callbackInst, "wait_child")) {
+ PyObject *method;
+ if (PyObject_HasAttrString(callbackInst, "waitChild"))
+ method = PyObject_GetAttrString(callbackInst, "waitChild");
+ else
+ method = PyObject_GetAttrString(callbackInst, "wait_child");
//std::cerr << "custom waitChild found" << std::endl;
PyObject *arglist = Py_BuildValue("(i)",child_id);
- PyObject *result = PyEval_CallObject(method, arglist);
+ PyObject *result = PyObject_CallObject(method, arglist);
Py_DECREF(arglist);
if (result == NULL) {
std::cerr << "waitChild method invalid" << std::endl;
PyErr_Print();
+ PyCbObj_BEGIN_ALLOW_THREADS
return pkgPackageManager::Failed;
}
- int child_res;
if(!PyArg_Parse(result, "i", &res) ) {
std::cerr << "custom waitChild() result could not be parsed?"<< std::endl;
PyCbObj_BEGIN_ALLOW_THREADS
@@ -456,11 +541,10 @@ pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm)
void PyCdromProgress::Update(string text, int current)
{
PyObject *arglist = Py_BuildValue("(si)", text.c_str(), current);
-
- PyObject *o = Py_BuildValue("i", totalSteps);
- PyObject_SetAttrString(callbackInst, "totalSteps", o);
- Py_XDECREF(o);
-
+ setattr(callbackInst, "total_steps", "i", totalSteps);
+ #ifdef COMPAT_0_7
+ setattr(callbackInst, "totalSteps", "i", totalSteps);
+ #endif
RunSimpleCallback("update", arglist);
}
@@ -468,7 +552,10 @@ bool PyCdromProgress::ChangeCdrom()
{
PyObject *arglist = Py_BuildValue("()");
PyObject *result;
- RunSimpleCallback("changeCdrom", arglist, &result);
+ if (PyObject_HasAttrString(callbackInst, "changeCdrom"))
+ RunSimpleCallback("changeCdrom", arglist, &result);
+ else
+ RunSimpleCallback("change_cdrom", arglist, &result);
bool res = true;
if(!PyArg_Parse(result, "b", &res))
@@ -481,18 +568,28 @@ bool PyCdromProgress::ChangeCdrom()
bool PyCdromProgress::AskCdromName(string &Name)
{
PyObject *arglist = Py_BuildValue("()");
- PyObject *result;
- RunSimpleCallback("askCdromName", arglist, &result);
-
const char *new_name;
bool res;
- if(!PyArg_Parse(result, "(bs)", &res, &new_name))
- std::cerr << "AskCdromName: result could not be parsed" << std::endl;
-
- //std::cerr << "got: " << res << " " << "name: " << new_name << std::endl;
-
- // set the new name
- Name = string(new_name);
+ PyObject *result;
- return res;
+ // Old style: (True, name) on success, (False, name) on failure.
+ if (PyObject_HasAttrString(callbackInst, "askAdromName")) {
+ RunSimpleCallback("askAdromName", arglist, &result);
+ if(!PyArg_Parse(result, "(bs)", &res, &new_name))
+ std::cerr << "AskCdromName: result could not be parsed" << std::endl;
+ // set the new name
+ Name = string(new_name);
+ return res;
+ }
+ // New style: String on success, None on failure.
+ else {
+ RunSimpleCallback("ask_cdrom_name", arglist, &result);
+ if(result == Py_None)
+ return false;
+ if(!PyArg_Parse(result, "s", &new_name))
+ std::cerr << "ask_cdrom_name: result could not be parsed" << std::endl;
+ else
+ Name = string(new_name);
+ return true;
+ }
}