Bug#623485: python-apt: please add bindings pkgOrderList
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())
Reply to: