|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <Python.h> |
|
#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 <apt-pkg/install-progress.h> |
|
#include "progress.h" |
|
#include "generic.h" |
|
#include "apt_pkgmodule.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
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); |
|
if (value == NULL) |
|
return false; |
|
|
|
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; |
|
} |
|
|
|
|
|
bool PyCallbackObj::RunSimpleCallback(const char* method_name, |
|
PyObject *arglist, |
|
PyObject **res) |
|
{ |
|
if(callbackInst == 0) { |
|
Py_XDECREF(arglist); |
|
return false; |
|
} |
|
|
|
PyObject *method = PyObject_GetAttrString(callbackInst,(char*) method_name); |
|
if(method == NULL) { |
|
|
|
Py_XDECREF(arglist); |
|
if (res) { |
|
Py_INCREF(Py_None); |
|
*res = Py_None; |
|
} |
|
return false; |
|
} |
|
|
|
PyObject *result = PyObject_CallObject(method, arglist); |
|
Py_XDECREF(arglist); |
|
|
|
if(result == NULL) { |
|
|
|
std::cerr << "Error in function " << method_name << std::endl; |
|
PyErr_Print(); |
|
PyErr_Clear(); |
|
|
|
return false; |
|
} |
|
if(res != NULL) |
|
*res = result; |
|
else |
|
Py_XDECREF(result); |
|
Py_XDECREF(method); |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
void PyOpProgress::Update() |
|
{ |
|
|
|
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", "N", MkPyNumber(Percent)); |
|
RunSimpleCallback("update"); |
|
} |
|
|
|
void PyOpProgress::Done() |
|
{ |
|
RunSimpleCallback("done"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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(std::string Media, std::string Drive) |
|
{ |
|
PyCbObj_END_ALLOW_THREADS |
|
|
|
PyObject *arglist = Py_BuildValue("(ss)", Media.c_str(), Drive.c_str()); |
|
PyObject *result = NULL; |
|
|
|
if(PyObject_HasAttrString(callbackInst, "mediaChange")) |
|
RunSimpleCallback("mediaChange", arglist, &result); |
|
else |
|
RunSimpleCallback("media_change", arglist, &result); |
|
|
|
bool res = true; |
|
if(!PyArg_Parse(result, "b", &res)) { |
|
|
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
return false; |
|
} |
|
|
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
return res; |
|
} |
|
|
|
void PyFetchProgress::UpdateStatus(pkgAcquire::ItemDesc &Itm, int status) |
|
{ |
|
|
|
|
|
|
|
|
|
PyObject *arglist = Py_BuildValue("(sssNNN)", Itm.URI.c_str(), |
|
Itm.Description.c_str(), |
|
Itm.ShortDesc.c_str(), |
|
MkPyNumber(status), |
|
MkPyNumber(Itm.Owner->FileSize), |
|
MkPyNumber(Itm.Owner->PartialSize)); |
|
|
|
RunSimpleCallback("update_status_full", arglist); |
|
|
|
|
|
|
|
arglist = Py_BuildValue("(sssN)", Itm.URI.c_str(), Itm.Description.c_str(), |
|
Itm.ShortDesc.c_str(), MkPyNumber(status)); |
|
|
|
if(PyObject_HasAttrString(callbackInst, "updateStatus")) |
|
RunSimpleCallback("updateStatus", arglist); |
|
else |
|
RunSimpleCallback("update_status", arglist); |
|
} |
|
|
|
void PyFetchProgress::IMSHit(pkgAcquire::ItemDesc &Itm) |
|
{ |
|
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) |
|
{ |
|
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) |
|
{ |
|
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; |
|
} |
|
|
|
|
|
if (Itm.Owner->Status == pkgAcquire::Item::StatIdle) { |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
return; |
|
} |
|
|
|
if (Itm.Owner->Status == pkgAcquire::Item::StatDone) |
|
{ |
|
UpdateStatus(Itm, DLIgnored); |
|
} |
|
|
|
|
|
if (PyObject_HasAttrString(callbackInst, "fail")) |
|
RunSimpleCallback("fail", TUPLEIZE(GetDesc(&Itm))); |
|
else |
|
UpdateStatus(Itm, DLFailed); |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
} |
|
|
|
void PyFetchProgress::Start() |
|
{ |
|
|
|
pkgAcquireStatus::Start(); |
|
|
|
|
|
RunSimpleCallback("start"); |
|
|
|
|
|
|
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
} |
|
|
|
|
|
void PyFetchProgress::Stop() |
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
PyCbObj_END_ALLOW_THREADS |
|
|
|
pkgAcquireStatus::Stop(); |
|
RunSimpleCallback("stop"); |
|
} |
|
|
|
bool PyFetchProgress::Pulse(pkgAcquire * Owner) |
|
{ |
|
PyCbObj_END_ALLOW_THREADS |
|
pkgAcquireStatus::Pulse(Owner); |
|
|
|
|
|
if(callbackInst == 0) { |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
return false; |
|
} |
|
|
|
setattr(callbackInst, "last_bytes", "N", MkPyNumber(LastBytes)); |
|
setattr(callbackInst, "current_cps", "N", MkPyNumber(CurrentCPS)); |
|
setattr(callbackInst, "current_bytes", "N", MkPyNumber(CurrentBytes)); |
|
setattr(callbackInst, "total_bytes", "N", MkPyNumber(TotalBytes)); |
|
setattr(callbackInst, "fetched_bytes", "N", MkPyNumber(FetchedBytes)); |
|
setattr(callbackInst, "elapsed_time", "N", MkPyNumber(ElapsedTime)); |
|
setattr(callbackInst, "current_items", "N", MkPyNumber(CurrentItems)); |
|
setattr(callbackInst, "total_items", "N", MkPyNumber(TotalItems)); |
|
|
|
|
|
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 && |
|
result1 != Py_None && |
|
PyArg_Parse(result1, "b", &res1) && |
|
res1 == false) { |
|
|
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
return false; |
|
} |
|
} |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
void PyInstallProgress::StartUpdate() |
|
{ |
|
RunSimpleCallback("start_update"); |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
} |
|
|
|
void PyInstallProgress::UpdateInterface() |
|
{ |
|
PyCbObj_END_ALLOW_THREADS |
|
RunSimpleCallback("update_interface"); |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
} |
|
|
|
void PyInstallProgress::FinishUpdate() |
|
{ |
|
PyCbObj_END_ALLOW_THREADS |
|
RunSimpleCallback("finish_update"); |
|
} |
|
|
|
pkgPackageManager::OrderResult PyInstallProgress::Run(pkgPackageManager *pm) |
|
{ |
|
pkgPackageManager::OrderResult res; |
|
int ret; |
|
pid_t child_id; |
|
|
|
#if 0 |
|
res = pm->DoInstallPreFork(); |
|
if (res == pkgPackageManager::Failed) |
|
return res; |
|
#endif |
|
|
|
|
|
if(PyObject_HasAttrString(callbackInst, "fork")) { |
|
PyObject *method = PyObject_GetAttrString(callbackInst, "fork"); |
|
std::cerr << "custom fork found" << std::endl; |
|
PyObject *arglist = Py_BuildValue("()"); |
|
PyObject *result = PyObject_CallObject(method, arglist); |
|
Py_DECREF(arglist); |
|
if (result == NULL) { |
|
std::cerr << "fork method invalid" << std::endl; |
|
PyErr_Print(); |
|
return pkgPackageManager::Failed; |
|
} |
|
if(!PyArg_Parse(result, "i", &child_id) ) { |
|
std::cerr << "custom fork() result could not be parsed?"<< std::endl; |
|
return pkgPackageManager::Failed; |
|
} |
|
std::cerr << "got pid: " << child_id << std::endl; |
|
} else { |
|
|
|
child_id = fork(); |
|
} |
|
|
|
PyObject *child_o = MkPyNumber(child_id); |
|
PyObject_SetAttrString(callbackInst, "child_pid", child_o); |
|
Py_DECREF(child_o); |
|
|
|
#if 0 |
|
if (child_id == 0) { |
|
res = pm->DoInstallPostFork(); |
|
_exit(res); |
|
} |
|
#endif |
|
if (child_id == 0) { |
|
PyObject *v = PyObject_GetAttrString(callbackInst, "writefd"); |
|
if(v) { |
|
int fd = PyObject_AsFileDescriptor(v); |
|
std::cout << "got fd: " << fd << std::endl; |
|
|
|
APT::Progress::PackageManagerProgressFd progress(fd); |
|
res = pm->DoInstall(&progress); |
|
} else { |
|
APT::Progress::PackageManagerProgressFd progress(-1); |
|
res = pm->DoInstall(&progress); |
|
} |
|
|
|
_exit(res); |
|
} |
|
|
|
StartUpdate(); |
|
|
|
|
|
PyCbObj_END_ALLOW_THREADS |
|
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"); |
|
|
|
PyObject *result = PyObject_CallObject(method, NULL); |
|
if (result == NULL) { |
|
std::cerr << "waitChild method invalid" << std::endl; |
|
PyErr_Print(); |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
return pkgPackageManager::Failed; |
|
} |
|
if(!PyArg_Parse(result, "i", &res) ) { |
|
std::cerr << "custom waitChild() result could not be parsed?"<< std::endl; |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
return pkgPackageManager::Failed; |
|
} |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
|
|
} else { |
|
|
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
while (waitpid(child_id, &ret, WNOHANG) == 0) { |
|
PyCbObj_END_ALLOW_THREADS |
|
UpdateInterface(); |
|
PyCbObj_BEGIN_ALLOW_THREADS |
|
} |
|
|
|
res = (pkgPackageManager::OrderResult) WEXITSTATUS(ret); |
|
|
|
} |
|
|
|
FinishUpdate(); |
|
|
|
return res; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
void PyCdromProgress::Update(std::string text, int current) |
|
{ |
|
PyObject *arglist = Py_BuildValue("(si)", text.c_str(), current); |
|
setattr(callbackInst, "total_steps", "i", totalSteps); |
|
RunSimpleCallback("update", arglist); |
|
} |
|
|
|
bool PyCdromProgress::ChangeCdrom() |
|
{ |
|
PyObject *arglist = Py_BuildValue("()"); |
|
PyObject *result = NULL; |
|
if (PyObject_HasAttrString(callbackInst, "changeCdrom")) |
|
RunSimpleCallback("changeCdrom", arglist, &result); |
|
else |
|
RunSimpleCallback("change_cdrom", arglist, &result); |
|
|
|
bool res = true; |
|
if(!PyArg_Parse(result, "b", &res)) |
|
std::cerr << "ChangeCdrom: result could not be parsed" << std::endl; |
|
|
|
return res; |
|
} |
|
|
|
|
|
bool PyCdromProgress::AskCdromName(std::string &Name) |
|
{ |
|
PyObject *arglist = Py_BuildValue("()"); |
|
const char *new_name; |
|
bool res; |
|
PyObject *result = NULL; |
|
|
|
|
|
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; |
|
|
|
Name =std:: string(new_name); |
|
return res; |
|
} |
|
|
|
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 = std::string(new_name); |
|
return true; |
|
} |
|
} |
|
|