[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

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: