diff options
| author | Michael Vogt <michael.vogt@ubuntu.com> | 2010-03-23 14:18:44 +0100 |
|---|---|---|
| committer | Michael Vogt <michael.vogt@ubuntu.com> | 2010-03-23 14:18:44 +0100 |
| commit | 37650a078f5504dfbc6622d2c06f4435a3302dd4 (patch) | |
| tree | 35d7df75535420cbe0712a5f7b7b66d61f5e44d1 /python/progress.cc | |
| parent | 2aa709e41d8896ef897863ea9181c409c4c87a8c (diff) | |
| parent | 3a08cfb10590d5cf5df1f45d94a424ef6a0f674b (diff) | |
| download | python-apt-37650a078f5504dfbc6622d2c06f4435a3302dd4.tar.gz | |
merged from lp:~mvo/python-apt/mvo
Diffstat (limited to 'python/progress.cc')
| -rw-r--r-- | python/progress.cc | 329 |
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; + } } |
