On Mi, 2011-04-27 at 19:28 +0200, Pietro Abate wrote: > In the long term maybe the correct solution to all this mambo-jumbo would be > to > implement the packageManager bindings as a virtual class with a default on > dpkg > as it is now, but giving the possibility to override from the python side the > Install/Configure/Remove/Go functions in order to hack into the pkgmanager > algorithm cleanly. I'm not sure this is possible given the current > architecture... This patch implements this. It breaks the C++ API for embedding python-apt though, so we may need a slightly different solution on the C ++ side, but the Python side works. I am also attaching an example show casing this.
I try to get this PackageManager feature implemented more cleanly tomorrow. Until then, test the patch! -- Julian Andres Klode - Debian Developer, Ubuntu Member See http://wiki.debian.org/JulianAndresKlode and http://jak-linux.org/.
=== modified file 'python/pkgmanager.cc' --- python/pkgmanager.cc 2011-04-12 09:38:25 +0000 +++ python/pkgmanager.cc 2011-04-28 14:08:30 +0000 @@ -2,7 +2,7 @@ // $Id: acquire.cc,v 1.1 2003/06/03 03:03:23 mvo Exp $ /* ###################################################################### - PkgManager - Wrapper for the pkgPackageManager code + PkgManager - Wrapper for the PyPkgManager code ##################################################################### */ @@ -17,9 +17,89 @@ #include <apt-pkg/acquire.h> #include <apt-pkg/init.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/dpkgpm.h> #include <iostream> +struct CppPyRef { + PyObject *o; + CppPyRef(const CppPyRef &o) { Py_XINCREF(o); this->o = o; } + CppPyRef(PyObject *o) : o(o) {} + ~CppPyRef() { Py_XDECREF(o); } + operator PyObject *() const { return o; } + PyObject *operator->() const { return o; } +}; + + + +struct PyPkgManager : public pkgDPkgPM { + + bool res(CppPyRef result) { + if (result == NULL) { + std::cerr << "Error in function: " << std::endl; + PyErr_Print(); + PyErr_Clear(); + return false; + } + return (result != NULL && + (result == Py_None || PyObject_IsTrue(result) == 1)); + } + + PyPkgManager(pkgDepCache *Cache) : pkgDPkgPM(Cache) {}; + PyObject *GetPyPkg(const PkgIterator &Pkg) { + static PyObject * const cache = 0; /*FIXME*/ + return PyPackage_FromCpp(Pkg, true, cache); + } +protected: + /* Call through to Python */ + virtual bool Install(PkgIterator Pkg,string File) { + return res(PyObject_CallMethod(pyinst, "install", "(NN)", + GetPyPkg(Pkg), + CppPyString(File))); + } + virtual bool Configure(PkgIterator Pkg) { + return res(PyObject_CallMethod(pyinst, "configure", "(N)", + GetPyPkg(Pkg))); + } + virtual bool Remove(PkgIterator Pkg,bool Purge = false) { + return res(PyObject_CallMethod(pyinst, "remove", "(NN)", + GetPyPkg(Pkg), + PyBool_FromLong(Purge))); + } + virtual bool Go(int StatusFd=-1) { + return res(PyObject_CallMethod(pyinst, "go", "(i)", + StatusFd)); + } + virtual void Reset() { + CppPyRef(PyObject_CallMethod(pyinst, "reset", NULL)); + } + +public: + /* Those call the protected functions from the parent class */ + bool callInstall(PkgIterator Pkg,string File) { + return pkgDPkgPM::Install(Pkg, File); + } + + bool callRemove(PkgIterator Pkg, bool Purge) { + return pkgDPkgPM::Remove(Pkg, Purge); + } + bool callGo(int StatusFd=-1) { + return pkgDPkgPM::Go(StatusFd); + } + void callReset() { + return pkgDPkgPM::Reset(); + } + bool callConfigure(PkgIterator Pkg) { + return pkgDPkgPM::Configure(Pkg); + } + + pkgOrderList *getOrderList() { + return pkgPackageManager::List; + } + + PyObject *pyinst; +}; + static PyObject *PkgManagerNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) { PyObject *Owner; @@ -28,10 +108,12 @@ static PyObject *PkgManagerNew(PyTypeObj &Owner) == 0) return 0; - pkgPackageManager *pm = _system->CreatePM(GetCpp<pkgDepCache*>(Owner)); + PyPkgManager *pm = new PyPkgManager(GetCpp<pkgDepCache*>(Owner)); - CppPyObject<pkgPackageManager*> *PkgManagerObj = - CppPyObject_NEW<pkgPackageManager*>(NULL, type,pm); + CppPyObject<PyPkgManager*> *PkgManagerObj = + CppPyObject_NEW<PyPkgManager*>(NULL, type,pm); + + pm->pyinst = PkgManagerObj; return PkgManagerObj; } @@ -46,10 +128,65 @@ PyObject *GetPkgManager(PyObject *Self,P } #endif +static PyObject *PkgManagerInstall(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + PyObject *pkg; + const char *file; + + if (PyArg_ParseTuple(Args, "O!s", &PyPackage_Type,&pkg, &file) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callInstall(PyPackage_ToCpp(pkg), file))); +} + + +static PyObject *PkgManagerConfigure(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + PyObject *pkg; + + if (PyArg_ParseTuple(Args, "O!", &PyPackage_Type,&pkg) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callConfigure(PyPackage_ToCpp(pkg)))); +} + +static PyObject *PkgManagerRemove(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + PyObject *pkg; + char purge; + + if (PyArg_ParseTuple(Args, "O!b", &PyPackage_Type,&pkg, &purge) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callRemove(PyPackage_ToCpp(pkg), purge))); +} + +static PyObject *PkgManagerGo(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + int fd; + + if (PyArg_ParseTuple(Args, "i", &fd) == 0) + return 0; + + return HandleErrors(PyBool_FromLong(pm->callGo(fd))); +} + +static PyObject *PkgManagerReset(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); + + pm->callReset(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} static PyObject *PkgManagerGetArchives(PyObject *Self,PyObject *Args) { - pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); PyObject *fetcher, *list, *recs; if (PyArg_ParseTuple(Args, "O!O!O!", @@ -71,13 +208,13 @@ static PyObject *PkgManagerGetArchives(P static PyObject *PkgManagerDoInstall(PyObject *Self,PyObject *Args) { //PkgManagerStruct &Struct = GetCpp<PkgManagerStruct>(Self); - pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); int status_fd = -1; if (PyArg_ParseTuple(Args, "|i", &status_fd) == 0) return 0; - pkgPackageManager::OrderResult res = pm->DoInstall(status_fd); + PyPkgManager::OrderResult res = pm->DoInstall(status_fd); return HandleErrors(MkPyNumber(res)); } @@ -85,7 +222,7 @@ static PyObject *PkgManagerDoInstall(PyO static PyObject *PkgManagerFixMissing(PyObject *Self,PyObject *Args) { //PkgManagerStruct &Struct = GetCpp<PkgManagerStruct>(Self); - pkgPackageManager *pm = GetCpp<pkgPackageManager*>(Self); + PyPkgManager *pm = GetCpp<PyPkgManager*>(Self); if (PyArg_ParseTuple(Args, "") == 0) return 0; @@ -95,8 +232,31 @@ static PyObject *PkgManagerFixMissing(Py return HandleErrors(PyBool_FromLong(res)); } +static PyObject *PkgManagerGetOrderList(PyObject *self, void*) { + PyPkgManager *pm = GetCpp<PyPkgManager*>(self); + + return PyOrderList_FromCpp(pm->getOrderList(), false, + GetOwner<PyPkgManager*>(self)); +} + static PyMethodDef PkgManagerMethods[] = { + {"install",PkgManagerInstall,METH_VARARGS, + "install(pkg: Package, filename: str) -> bool \n\n" + "Add a install action. Can be overriden in subclasses."}, + {"configure",PkgManagerConfigure,METH_VARARGS, + "configure(pkg: Package) -> bool \n\n" + "Add a configure action. Can be overriden in subclasses."}, + {"remove",PkgManagerRemove,METH_VARARGS, + "remove(pkg: Package, purge: bool) -> bool \n\n" + "Add a removal action. Can be overriden in subclasses."}, + {"go",PkgManagerGo,METH_VARARGS, + "go(status_fd: int) -> bool \n\n" + "Start dpkg. Can be overriden in subclasses."}, + {"reset",PkgManagerReset,METH_VARARGS, + "reset()\n\n" + "Reset the package manager for a new round.\n" + "Can be overriden in subclasses."}, {"get_archives",PkgManagerGetArchives,METH_VARARGS, "get_archives(fetcher: Acquire, list: SourceList, recs: PackageRecords) -> bool\n\n" "Download the packages marked for installation via the Acquire object\n" @@ -115,20 +275,29 @@ static PyMethodDef PkgManagerMethods[] = }; +static PyGetSetDef PkgManagerGetSet[] = { + {"order_list",PkgManagerGetOrderList,0, + "The OrderList of this PackageManager"}, + {} +}; + static const char *packagemanager_doc = "PackageManager(depcache: apt_pkg.DepCache)\n\n" "PackageManager objects allow the fetching of packages marked for\n" "installation and the installation of those packages. The parameter\n" "'depcache' specifies an apt_pkg.DepCache object where information\n" - "about the package selections is retrieved from."; + "about the package selections is retrieved from.\n\n" + "Several methods in this class can be overriden in sub classes\n" + "to implement behavior different from APT's dpkg implementation.\n" + "The abitility to be overriden is documented in the methods."; PyTypeObject PyPackageManager_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "apt_pkg.PackageManager", // tp_name - sizeof(CppPyObject<pkgPackageManager*>), // tp_basicsize + sizeof(CppPyObject<PyPkgManager*>), // tp_basicsize 0, // tp_itemsize // Methods - CppDeallocPtr<pkgPackageManager*>, // tp_dealloc + CppDeallocPtr<PyPkgManager*>, // tp_dealloc 0, // tp_print 0, // tp_getattr 0, // tp_setattr @@ -154,7 +323,7 @@ PyTypeObject PyPackageManager_Type = 0, // tp_iternext PkgManagerMethods, // tp_methods 0, // tp_members - 0, // tp_getset + PkgManagerGetSet, // tp_getset 0, // tp_base 0, // tp_dict 0, // tp_descr_get
import apt_pkg, sys class PkgManager(apt_pkg.PackageManager): parent = apt_pkg.PackageManager def install(self, pkg, file): print "Installing", pkg.get_fullname(True) return True def configure(self, pkg): print "Configuring", pkg.get_fullname(True) return True def remove(self, pkg, purge): print "Removing", pkg.get_fullname(True), "..." return self.parent.remove(self, pkg, purge) def go(self, fd): return True apt_pkg.PackageManager = PkgManager import apt cache = apt.Cache() pkg = cache["xterm"] if pkg.is_installed: pkg.mark_delete() else: pkg.mark_install() print "COMMIT" cache.commit(install_progress=apt.progress.base.InstallProgress())