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 + +++ python/pkgmanager.cc 2011-04-28 14:08:30 + @@ -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(GetCpppkgDepCache*(Owner)); + PyPkgManager *pm = new PyPkgManager(GetCpppkgDepCache*(Owner)); - CppPyObjectpkgPackageManager* *PkgManagerObj = - CppPyObject_NEWpkgPackageManager*(NULL, type,pm); + CppPyObjectPyPkgManager* *PkgManagerObj = + CppPyObject_NEWPyPkgManager*(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 = GetCppPyPkgManager*(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 = GetCppPyPkgManager*(Self); + PyObject *pkg; + + if
Bug#623485: python-apt: please add bindings pkgOrderList
On Do, 2011-04-21 at 16:57 +0200, Pietro Abate wrote: hello On Thu, Apr 21, 2011 at 03:53:39PM +0200, Julian Andres Klode wrote: On Mi, 2011-04-20 at 19:06 +0200, Pietro Abate wrote: This is a request to add a new binding to the class pkgOrderList of apt. The idea is to allow to compute and set the pkgOrderList independently and reason about it. Provided a bit of guidance (I'm not very familiar with the apt python bindings), we'll be happy to provide a patch. I'm going to write it next week, the 0.8.0~exp4 release next Tuesday/Wednesday would then include it. thank you ! this is fantastic ! Attaching a diff for review. Also see http://apt.alioth.debian.org/python-apt-doc/library/apt_pkg.html#apt_pkg.OrderList Note that this only adds a new OrderList class, it does not provide any integration with PackageManager. If you wish to have integration, please tell me how you'd like it to be. -- Julian Andres Klode - Debian Developer, Ubuntu Member See http://wiki.debian.org/JulianAndresKlode and http://jak-linux.org/. === modified file 'debian/changelog' --- debian/changelog 2011-04-21 13:34:01 + +++ debian/changelog 2011-04-27 10:57:27 + @@ -1,3 +1,9 @@ +python-apt (0.8.0~exp4) UNRELEASED; urgency=low + + * apt_pkg: Add OrderList, wanted for mancoosi (Closes: #623485) + + -- Julian Andres Klode j...@debian.org Wed, 27 Apr 2011 12:55:59 +0200 + python-apt (0.8.0~exp3) experimental; urgency=low [ Stéphane Graber ] === modified file 'doc/source/c++/api.rst' --- doc/source/c++/api.rst 2011-04-05 14:11:34 + +++ doc/source/c++/api.rst 2011-04-27 10:40:10 + @@ -622,6 +622,34 @@ IndexFile (pkgIndexFile) Return the :ctype:`pkgIndexFile` pointer contained in the Python object *object*. +OrderList (pkgOrderList) +--- +.. cvar:: PyTypeObject PyOrderList_Type + +The type object for :class:`apt_pkg.OrderList` objects. + +.. cfunction:: int PyOrderList_Check(PyObject *object) + +Check that the object *object* is an :class:`apt_pkg.OrderList` object, or +a subclass thereof. + +.. cfunction:: int PyOrderList_CheckExact(PyObject *object) + +Check that the object *object* is an :class:`apt_pkg.OrderList` object +and no subclass thereof. + +.. cfunction:: PyObject* PyOrderList_FromCpp(pkgOrderList *cpp, bool delete, PyObject *owner) + +Create a new :class:`apt_pkg.OrderList` object from the :ctype:`pkgOrderList` +pointer given by the parameter *cpp*. If the parameter *delete* is +true, the object pointed to by *cpp* will be deleted when the reference +count of the returned object reaches 0. The owner must be a +:class:`apt_pkg.DepCache` object. + +.. cfunction:: pkgOrderList* PyOrderList_ToCpp(PyObject *object) + +Return the :ctype:`pkgOrderList` pointer contained in the Python object +*object*. PackageManager (pkgPackageManager) -- === modified file 'doc/source/library/apt_pkg.rst' --- doc/source/library/apt_pkg.rst 2011-04-21 12:21:22 + +++ doc/source/library/apt_pkg.rst 2011-04-27 11:04:30 + @@ -422,6 +422,99 @@ Installing with :class:`PackageManager` A constant for checking whether the the result of the call to :meth:`do_install` is 'incomplete'. + +Installation ordering with :class:`OrderList` +^ + +.. class:: OrderList(depcache: DepCache) + + Represent a :ctype:`pkgOrderList`, used for installation + ordering. This class provides several methods and attributes, + is complicated and should not be used by normal programs. + + .. versionadded:: 0.8.0 + + This class is a sequence and supports the following operations: + + .. describe:: list[index] + + Get the package at the given index in the list. Negative + index is supported. + + .. describe:: len(list) + + The length of the list. + + It also supports the append() method from :class:`list`: + + .. method:: append(pkg: Package) + + Append a new package to the end of the list. Please note that + you may not append a package twice, as only as much packages + as in the cache can be added. + + The class also defines several specific attributes and methods, + to be described hereinafter. + + .. method:: score(pkg: Package) + + Return the score of the package. Packages are basically + ordered by descending score. + + This class allows flags to be set on packages. Those flags are: + + .. attribute:: FLAG_ADDED + .. attribute:: FLAG_ADD_PENDING + .. attribute:: FLAG_IMMEDIATE + .. attribute:: FLAG_LOOP + .. attribute:: FLAG_UNPACKED + .. attribute:: FLAG_CONFIGURED + .. attribute:: FLAG_REMOVED + .. attribute:: FLAG_STATES_MASK + + Same as ``FLAG_UNPACKED | FLAG_CONFIGURED | FLAG_REMOVED`` + + .. attribute:: FLAG_IN_LIST + .. attribute:: FLAG_AFTER + + The methods to work with those flags are: + + .. method:: flag(pkg: Package, flag: int[, unset_flags: int]) + + Flag a package. Sets the flags
Bug#623485: python-apt: please add bindings pkgOrderList
Hello Julian, On Wed, Apr 27, 2011 at 01:07:49PM +0200, Julian Andres Klode wrote: On Do, 2011-04-21 at 16:57 +0200, Pietro Abate wrote: On Thu, Apr 21, 2011 at 03:53:39PM +0200, Julian Andres Klode wrote: On Mi, 2011-04-20 at 19:06 +0200, Pietro Abate wrote: This is a request to add a new binding to the class pkgOrderList of apt. The idea is to allow to compute and set the pkgOrderList independently and reason about it. Attaching a diff for review. Also see http://apt.alioth.debian.org/python-apt-doc/library/apt_pkg.html#apt_pkg.OrderList Note that this only adds a new OrderList class, it does not provide any integration with PackageManager. If you wish to have integration, please tell me how you'd like it to be. This is great. I had a look at the code and doc and it seems good so far. I re-read the apt-pkg code regarding the packagemanager class and maybe I've a suggestion on a possible integration with the work you have done. the packagemanger has a number of virtual methods that are instantiated in apt-pkg/deb/dpkgpm.cc . These methods are protected in the packagemaneger class : // The Actual installation implementation virtual bool Install(PkgIterator /*Pkg*/,string /*File*/) {return false;}; virtual bool Configure(PkgIterator /*Pkg*/) {return false;}; virtual bool Remove(PkgIterator /*Pkg*/,bool /*Purge*/=false) {return false;}; virtual bool Go(int statusFd=-1) {return true;}; virtual void Reset() {}; the packagemaneger object is created in cmdline/apt-get.cc by a call to this function: SPtrpkgPackageManager PM= _system-CreatePM(Cache); In apt-get, if Simulated is specified, the package manager will be instantiated as a pkgSimulate object (that is a concrete implementation of packageManager ). The problem is that this class does not save the installation plan anywhere it only prints it on screen. My proposal of integration will be very simple. We can create a new subclass of packageManager , say pkgPlan that will implement install, configure, remove, etc and instead of printing on stdout the actions as in pkgSimulate, will save this information in a list that can be for our purposes. Since the dpkg commands are built in yet another packageManager object derived from apt-pkg/deb/dpkgpm.cc I don't think it will be easy to get a trace of what dpkg would have done if invoked (even this would be great...). But for the moment I think the list Inst/Conf/Rem will be enough. The real list of dpkg commands can be obtained (not in simulation mode) with the debug variable: Debug::pkgDPkgPM=true 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... As it is the OrderList class will allow to easily reimplement the backend and in theory to completely bypass the apt-pkg/deb/dpkgpm.cc and perform the installation via another package manager, say rpm... thanks again for your great support. pietro -- http://en.wikipedia.org/wiki/Posting_style -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of unsubscribe. Trouble? Contact listmas...@lists.debian.org
Bug#623485: python-apt: please add bindings pkgOrderList
On Do, 2011-04-21 at 16:57 +0200, Pietro Abate wrote: hello On Thu, Apr 21, 2011 at 03:53:39PM +0200, Julian Andres Klode wrote: On Mi, 2011-04-20 at 19:06 +0200, Pietro Abate wrote: This is a request to add a new binding to the class pkgOrderList of apt. The idea is to allow to compute and set the pkgOrderList independently and reason about it. At the moment the only way to compute (via apt-get) the installation plan is to execute it and print a debug trace of it. For the mancoosi project we would like to compute the plan before executing it and to simulate the installation in order to detect possible problems in the installation scripts. I'm aware that this binding will export a read-only object and that the installation plan will be recomputed by apt-get. This will be sufficient for our goals. As far as I can tell, the object would be read-write. You fill the list, then you order it, and then you read it again. So, shall I bind just the pkgOrderList class or do you want anything related as well? If I read the code correctly, you initialize the pkgOrderList with the cache (that contains the packages marked to be installed/removed) and then you read back the list of ordered packages. In this sense the object is of course read/write. You could also add some packages, order, add some more. My remark was related how the pkgOrderList class is used in the module packageManager where the orderedlist is protected. Without modifying the API of the packageManager it is not possible at the moment to pass to the installer the installation plan. This is also because the computation of the installation plan is intertwined with the real installation itself (for performances reasons I presume). What we need is a way to build the installation plan from the cache (initialized with the packages that are going to be installed/removed). There are a bunch of protected functions in packageManager that use the orderedList, but as far as I can see they are all protected... Once the pkgOrderList class will be available I think I'll need to reimplement in my application the logic of few functions in packageManager to (re)-build the installation plan (aka the order in which dpkg is called to pre-configure / unpack / configure / install / remove / *-hooks / ext ). But OrderList being available in the Python bindings only brings you the ordering itself, no integration whatsoever with PackageManager. All the interesting stuff in PackageManager is protected and thus not bound. And binding OrderList is not fun, it's severely under-documented. That's a pain to bind: Because the bindings are fully documented, I need to play detective and find out what functions and values are supposed to mean... -- Julian Andres Klode - Debian Developer, Ubuntu Member See http://wiki.debian.org/JulianAndresKlode and http://jak-linux.org/. -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of unsubscribe. Trouble? Contact listmas...@lists.debian.org
Bug#623485: python-apt: please add bindings pkgOrderList
On Mi, 2011-04-20 at 19:06 +0200, Pietro Abate wrote: Package: python-apt Version: 0.7.100.3+b1 Severity: wishlist Hello, This is a request to add a new binding to the class pkgOrderList of apt. The idea is to allow to compute and set the pkgOrderList independently and reason about it. At the moment the only way to compute (via apt-get) the installation plan is to execute it and print a debug trace of it. For the mancoosi project we would like to compute the plan before executing it and to simulate the installation in order to detect possible problems in the installation scripts. I'm aware that this binding will export a read-only object and that the installation plan will be recomputed by apt-get. This will be sufficient for our goals. As far as I can tell, the object would be read-write. You fill the list, then you order it, and then you read it again. So, shall I bind just the pkgOrderList class or do you want anything related as well? Provided a bit of guidance (I'm not very familiar with the apt python bindings), we'll be happy to provide a patch. I'm going to write it next week, the 0.8.0~exp4 release next Tuesday/Wednesday would then include it. -- Julian Andres Klode - Debian Developer, Ubuntu Member See http://wiki.debian.org/JulianAndresKlode and http://jak-linux.org/. -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of unsubscribe. Trouble? Contact listmas...@lists.debian.org
Bug#623485: python-apt: please add bindings pkgOrderList
hello On Thu, Apr 21, 2011 at 03:53:39PM +0200, Julian Andres Klode wrote: On Mi, 2011-04-20 at 19:06 +0200, Pietro Abate wrote: This is a request to add a new binding to the class pkgOrderList of apt. The idea is to allow to compute and set the pkgOrderList independently and reason about it. At the moment the only way to compute (via apt-get) the installation plan is to execute it and print a debug trace of it. For the mancoosi project we would like to compute the plan before executing it and to simulate the installation in order to detect possible problems in the installation scripts. I'm aware that this binding will export a read-only object and that the installation plan will be recomputed by apt-get. This will be sufficient for our goals. As far as I can tell, the object would be read-write. You fill the list, then you order it, and then you read it again. So, shall I bind just the pkgOrderList class or do you want anything related as well? If I read the code correctly, you initialize the pkgOrderList with the cache (that contains the packages marked to be installed/removed) and then you read back the list of ordered packages. In this sense the object is of course read/write. My remark was related how the pkgOrderList class is used in the module packageManager where the orderedlist is protected. Without modifying the API of the packageManager it is not possible at the moment to pass to the installer the installation plan. This is also because the computation of the installation plan is intertwined with the real installation itself (for performances reasons I presume). What we need is a way to build the installation plan from the cache (initialized with the packages that are going to be installed/removed). There are a bunch of protected functions in packageManager that use the orderedList, but as far as I can see they are all protected... Once the pkgOrderList class will be available I think I'll need to reimplement in my application the logic of few functions in packageManager to (re)-build the installation plan (aka the order in which dpkg is called to pre-configure / unpack / configure / install / remove / *-hooks / ext ). From my understanding of the apt code this is the easiest way to attain this goal... and it's also a lot of work that I prefer to do in python the to ack the c++ code base of apt-get. Provided a bit of guidance (I'm not very familiar with the apt python bindings), we'll be happy to provide a patch. I'm going to write it next week, the 0.8.0~exp4 release next Tuesday/Wednesday would then include it. thank you ! this is fantastic ! regards. pietro -- http://en.wikipedia.org/wiki/Posting_style -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of unsubscribe. Trouble? Contact listmas...@lists.debian.org
Bug#623485: python-apt: please add bindings pkgOrderList
Package: python-apt Version: 0.7.100.3+b1 Severity: wishlist Hello, This is a request to add a new binding to the class pkgOrderList of apt. The idea is to allow to compute and set the pkgOrderList independently and reason about it. At the moment the only way to compute (via apt-get) the installation plan is to execute it and print a debug trace of it. For the mancoosi project we would like to compute the plan before executing it and to simulate the installation in order to detect possible problems in the installation scripts. I'm aware that this binding will export a read-only object and that the installation plan will be recomputed by apt-get. This will be sufficient for our goals. Provided a bit of guidance (I'm not very familiar with the apt python bindings), we'll be happy to provide a patch. look forward for your feedback. pietro -- System Information: Debian Release: wheezy/sid APT prefers unstable APT policy: (500, 'unstable'), (500, 'testing') Architecture: amd64 (x86_64) Kernel: Linux 2.6.32-5-xen-amd64 (SMP w/2 CPU cores) Locale: LANG=en_US.utf8, LC_CTYPE=en_US.utf8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages python-apt depends on: ii apt [libapt-pkg4.10] 0.8.14.1 Advanced front-end for dpkg ii apt-utils [libapt-inst1.2]0.8.14.1 APT utility programs ii libc6 2.11.2-13 Embedded GNU C Library: Shared lib ii libgcc1 1:4.6.0-3 GCC support library ii libstdc++64.6.0-3The GNU Standard C++ Library v3 ii python2.6.6-14 interactive high-level object-orie ii python-apt-common 0.7.100.3 Python interface to libapt-pkg (lo ii python2.6 2.6.6-8+b1 An interactive high-level object-o ii python2.7 2.7.1-6An interactive high-level object-o Versions of packages python-apt recommends: ii iso-codes 3.25-1 ISO language, territory, currency, ii lsb-release 3.2-27 Linux Standard Base version report ii python2.6 2.6.6-8+b1 An interactive high-level object-o Versions of packages python-apt suggests: pn python-apt-dbg none (no description available) pn python-apt-doc none (no description available) ii python-gtk2 2.17.0-4+b2 Python bindings for the GTK+ widge pn python-vte none (no description available) -- no debconf information -- To UNSUBSCRIBE, email to debian-bugs-dist-requ...@lists.debian.org with a subject of unsubscribe. Trouble? Contact listmas...@lists.debian.org