summaryrefslogtreecommitdiff
path: root/python/progress.cc
diff options
context:
space:
mode:
Diffstat (limited to 'python/progress.cc')
-rw-r--r--python/progress.cc306
1 files changed, 193 insertions, 113 deletions
diff --git a/python/progress.cc b/python/progress.cc
index 82967687..30f62763 100644
--- a/python/progress.cc
+++ b/python/progress.cc
@@ -13,8 +13,33 @@
#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 +61,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 +86,25 @@ 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);
+#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
+ setattr(callbackInst, "percent", "f", Percent);
+ RunSimpleCallback("update");
+#endif
+}
void PyOpProgress::Done()
{
@@ -101,7 +125,8 @@ bool PyFetchProgress::MediaChange(string Media, string Drive)
//std::cout << "MediaChange" << std::endl;
PyObject *arglist = Py_BuildValue("(ss)", Media.c_str(), Drive.c_str());
PyObject *result;
- RunSimpleCallback("mediaChange", arglist, &result);
+ if(! RunSimpleCallback("media_change", arglist, &result))
+ RunSimpleCallback("mediaChange", arglist, &result);
bool res = true;
if(!PyArg_Parse(result, "b", &res)) {
@@ -116,14 +141,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,32 +154,52 @@ 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(!RunSimpleCallback("update_status", arglist))
+ RunSimpleCallback("updateStatus", arglist);
}
void PyFetchProgress::IMSHit(pkgAcquire::ItemDesc &Itm)
{
- UpdateStatus(Itm, DLHit);
+ PyCbObj_END_ALLOW_THREADS
+ if (PyObject_HasAttrString(callbackInst, "ims_hit"))
+ RunSimpleCallback("ims_hit", TUPLEIZE(PyAcquire_GetItemDesc(pyAcquire, &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(PyAcquire_GetItemDesc(pyAcquire, &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(PyAcquire_GetItemDesc(pyAcquire, &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(PyAcquire_GetItemDesc(pyAcquire, &Itm)));
+ return;
+ }
+
// Ignore certain kinds of transient failures (bad code)
if (Itm.Owner->Status == pkgAcquire::Item::StatIdle)
return;
@@ -166,7 +209,12 @@ void PyFetchProgress::Fail(pkgAcquire::ItemDesc &Itm)
UpdateStatus(Itm, DLIgnored);
}
- UpdateStatus(Itm, DLFailed);
+
+ if (PyObject_HasAttrString(callbackInst, "fail"))
+ RunSimpleCallback("fail", TUPLEIZE(PyAcquire_GetItemDesc(pyAcquire, &Itm)));
+ else
+ UpdateStatus(Itm, DLFailed);
+ PyCbObj_BEGIN_ALLOW_THREADS
}
void PyFetchProgress::Start()
@@ -174,26 +222,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 +241,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();
@@ -225,28 +261,52 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
if(callbackInst == 0)
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);
+#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);
+#endif
+
+ // New style
+#ifdef COMPAT_0_7
+ if (!PyObject_HasAttrString(callbackInst, "updateStatus")) {
+#else
+ {
+#endif
+ PyObject *result1;
+ bool res1 = true;
+
+ 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
// 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 +316,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 +330,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 +364,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 +381,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 +391,7 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
PyCbObj_BEGIN_ALLOW_THREADS
// fetching can be canceld by returning false
return res;
+#endif
}
@@ -337,26 +400,28 @@ bool PyFetchProgress::Pulse(pkgAcquire * Owner)
void PyInstallProgress::StartUpdate()
{
- RunSimpleCallback("startUpdate");
+ if (!RunSimpleCallback("start_update"))
+ RunSimpleCallback("startUpdate");
PyCbObj_BEGIN_ALLOW_THREADS
}
void PyInstallProgress::UpdateInterface()
{
PyCbObj_END_ALLOW_THREADS
- RunSimpleCallback("updateInterface");
+ if (!RunSimpleCallback("update_interface"))
+ RunSimpleCallback("updateInterface");
PyCbObj_BEGIN_ALLOW_THREADS
}
void PyInstallProgress::FinishUpdate()
{
PyCbObj_END_ALLOW_THREADS
- RunSimpleCallback("finishUpdate");
+ if (!RunSimpleCallback("finish_update"))
+ RunSimpleCallback("finishUpdate");
}
pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm)
{
- void *dummy;
pkgPackageManager::OrderResult res;
int ret;
pid_t child_id;
@@ -372,7 +437,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;
@@ -411,19 +476,24 @@ 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, "wait_child"))
+ method = PyObject_GetAttrString(callbackInst, "wait_child");
+ else
+ method = PyObject_GetAttrString(callbackInst, "waitChild");
//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();
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 +526,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 +537,8 @@ bool PyCdromProgress::ChangeCdrom()
{
PyObject *arglist = Py_BuildValue("()");
PyObject *result;
- RunSimpleCallback("changeCdrom", arglist, &result);
+ if(!RunSimpleCallback("change_cdrom", arglist, &result))
+ RunSimpleCallback("changeCdrom", arglist, &result);
bool res = true;
if(!PyArg_Parse(result, "b", &res))
@@ -481,18 +551,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;
+ // New style: String on success, None on failure.
+ if (RunSimpleCallback("ask_cdrom_name", arglist, &result)) {
+ if(result == Py_None)
+ return false;
+ if(!PyArg_Parse(result, "s", &new_name))
+ std::cerr << "AskCdromName: result could not be parsed" << std::endl;
+ else
+ Name = string(new_name);
+ return true;
+ }
+ // Old style: (True, name) on success, (False, name) on failure.
+ else {
+ RunSimpleCallback("askCdromName", 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;
+ }
}