From f441b008883170d6a8c4cfeb814b0c07a27e6afd Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Tue, 12 Apr 2011 11:38:25 +0200 Subject: apt_pkg: Fix unsigned/long-vs-int issues (LP: #610820) This fix is large, but simple in concept. Instead of relying on Py_BuildValue and type signatures, or type-specific conversion functions, create a new set of overloaded MkPyNumber() functions that automatically do the right thing for each numerical type. --- python/pkgmanager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python/pkgmanager.cc') diff --git a/python/pkgmanager.cc b/python/pkgmanager.cc index 95e8c27e..a65c88f8 100644 --- a/python/pkgmanager.cc +++ b/python/pkgmanager.cc @@ -79,7 +79,7 @@ static PyObject *PkgManagerDoInstall(PyObject *Self,PyObject *Args) pkgPackageManager::OrderResult res = pm->DoInstall(status_fd); - return HandleErrors(Py_BuildValue("i",res)); + return HandleErrors(MkPyNumber(res)); } static PyObject *PkgManagerFixMissing(PyObject *Self,PyObject *Args) -- cgit v1.2.3 From 750f432e42c605747d86826886c29b76d19269a3 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 29 Apr 2011 12:24:46 +0200 Subject: apt_pkg: Add subclassing fun to PackageManager, for #623485 as well --- debian/changelog | 1 + doc/source/library/apt_pkg.rst | 59 +++++++++ doc/source/whatsnew/0.8.0.rst | 12 +- python/apt_pkgmodule.cc | 3 +- python/apt_pkgmodule.h | 1 + python/pkgmanager.cc | 277 +++++++++++++++++++++++++++++++++++------ 6 files changed, 313 insertions(+), 40 deletions(-) (limited to 'python/pkgmanager.cc') diff --git a/debian/changelog b/debian/changelog index ff07fc21..b6f3da51 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,6 +1,7 @@ python-apt (0.8.0~exp4) UNRELEASED; urgency=low * apt_pkg: Add OrderList, wanted for mancoosi (Closes: #623485) + * apt_pkg: Add subclassing fun to PackageManager, for #623485 as well * apt.cache: Emit change signals in ProblemResolver * apt.Cache: Add a _changes_count member for later use diff --git a/doc/source/library/apt_pkg.rst b/doc/source/library/apt_pkg.rst index fce4f804..81f2d408 100644 --- a/doc/source/library/apt_pkg.rst +++ b/doc/source/library/apt_pkg.rst @@ -423,6 +423,65 @@ Installing with :class:`PackageManager` A constant for checking whether the the result of the call to :meth:`do_install` is 'incomplete'. + All instances of this class also support the following methods: + + .. note:: + + This methods are provided mainly for subclassing purposes + and should not be used in most programs. This class is a + subclass of an internal :class:`_PackageManager` which does + not provide that methods. As the public C++ API creates such + an object without those methods, you should not rely on those + methods to be available unless you used the constructor of + :class:`PackageManager` to create the object. + + .. method:: configure(pkg: Package) -> bool + + Notify the package manager that the :class:`Package` given + by *pkg* is to be configured. Must return a ``True`` value + or ``None`` to continue, or a value which is ``False`` if + evaluated as boolean to abort. + + .. versionadded:: 0.8.0 + + .. method:: install(pkg: Package, filename: str) -> bool + + Notify the package manager that the :class:`Package` given + by *pkg* is to be installed from the .deb located at + *filename*. Must return a ``True`` value or ``None`` to + continue, or a value which is ``False`` if evaluated as + boolean to abort. + + + .. versionadded:: 0.8.0 + + .. method:: remove(pkg: Package, purge: bool) -> bool + + Notify the package manager that the :class:`Package` given + by *pkg* is to be removed. If *purge* is ``True``, the package + shall be purged. Must return a ``True`` value or ``None`` to + continue, or a value which is ``False`` if evaluated as boolean + to abort. + + + .. versionadded:: 0.8.0 + + .. method:: go(status_fd: int) -> bool + + Start dpkg, writing status information to the file descriptor + given by *status_fd*. Must return a ``True`` value or ``None`` to + continue, or a value which is ``False`` if evaluated as boolean + to abort. + + .. versionadded:: 0.8.0 + + .. method:: reset() + + Reset the package manager for a new round. + + .. versionadded:: 0.8.0 + + Installation ordering with :class:`OrderList` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/source/whatsnew/0.8.0.rst b/doc/source/whatsnew/0.8.0.rst index fa58a022..2eeb135e 100644 --- a/doc/source/whatsnew/0.8.0.rst +++ b/doc/source/whatsnew/0.8.0.rst @@ -16,6 +16,16 @@ This version of python-apt introduces multi-arch support: * A new class, :class:`apt_pkg.Group` has been added. * :class:`apt_pkg.Cache` can now be indexed by ``(name, architecture)`` tuples + +Features for mancoosi +---------------------- +Several new features related to ordering have been added on request +of the mancoosi project: + + * A new class :class:`apt_pkg.OrderList` has been added + * The :class:`apt_pkg.PackageManager` class now provides new methods + for registering install/remove/configure actions which can be + subclassed to check ordering. Other changes ------------- @@ -23,8 +33,6 @@ This release of python-apt also features several other, smaller changes: * apt_pkg.Cache() now takes None for the progress parameter, preventing progress reporting. - * A new class :class:`apt_pkg.OrderList` has been added on request - of the mancoosi project. There have been various other changes, see the changelog for a complete list of changes. diff --git a/python/apt_pkgmodule.cc b/python/apt_pkgmodule.cc index 139ff016..e8490b4e 100644 --- a/python/apt_pkgmodule.cc +++ b/python/apt_pkgmodule.cc @@ -833,7 +833,8 @@ extern "C" void initapt_pkg() /* ========================= metaindex.cc ========================= */ ADDTYPE(Module,"MetaIndex",&PyMetaIndex_Type); // NO __new__() /* ========================= pkgmanager.cc ========================= */ - ADDTYPE(Module,"PackageManager",&PyPackageManager_Type); + ADDTYPE(Module,"_PackageManager",&PyPackageManager_Type); + ADDTYPE(Module,"PackageManager",&PyPackageManager2_Type); /* ========================= pkgrecords.cc ========================= */ ADDTYPE(Module,"PackageRecords",&PyPackageRecords_Type); /* ========================= pkgsrcrecords.cc ========================= */ diff --git a/python/apt_pkgmodule.h b/python/apt_pkgmodule.h index 89179551..b3534a30 100644 --- a/python/apt_pkgmodule.h +++ b/python/apt_pkgmodule.h @@ -102,6 +102,7 @@ PyObject *GetPkgAcqFile(PyObject *Self, PyObject *Args, PyObject *kwds); // packagemanager extern PyTypeObject PyPackageManager_Type; +extern PyTypeObject PyPackageManager2_Type; PyObject *GetPkgManager(PyObject *Self,PyObject *Args); diff --git a/python/pkgmanager.cc b/python/pkgmanager.cc index a65c88f8..b7bed658 100644 --- a/python/pkgmanager.cc +++ b/python/pkgmanager.cc @@ -17,36 +17,10 @@ #include #include #include +#include #include -static PyObject *PkgManagerNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) -{ - PyObject *Owner; - char *kwlist[] = {"depcache",0}; - if (PyArg_ParseTupleAndKeywords(Args,kwds,"O!",kwlist,&PyDepCache_Type, - &Owner) == 0) - return 0; - - pkgPackageManager *pm = _system->CreatePM(GetCpp(Owner)); - - CppPyObject *PkgManagerObj = - CppPyObject_NEW(NULL, type,pm); - - return PkgManagerObj; -} - -#ifdef COMPAT_0_7 -PyObject *GetPkgManager(PyObject *Self,PyObject *Args) -{ - PyErr_WarnEx(PyExc_DeprecationWarning, "apt_pkg.GetPackageManager() is " - "deprecated. Please see apt_pkg.PackageManager() for the " - "replacement.", 1); - return PkgManagerNew(&PyPackageManager_Type,Args,0); -} -#endif - - static PyObject *PkgManagerGetArchives(PyObject *Self,PyObject *Args) { pkgPackageManager *pm = GetCpp(Self); @@ -114,17 +88,16 @@ static PyMethodDef PkgManagerMethods[] = {} }; - 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."; + "_PackageManager objects allow the fetching of packages marked for\n" + "installation and the installation of those packages.\n" + "This is an abstract base class that cannot be subclassed\n" + "in Python. The only subclass is apt_pkg.PackageManager. This\n" + "class is an implementation-detail and not part of the API."; PyTypeObject PyPackageManager_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) - "apt_pkg.PackageManager", // tp_name + "apt_pkg._PackageManager", // tp_name sizeof(CppPyObject), // tp_basicsize 0, // tp_itemsize // Methods @@ -143,8 +116,7 @@ PyTypeObject PyPackageManager_Type = _PyAptObject_getattro, // tp_getattro 0, // tp_setattro 0, // tp_as_buffer - (Py_TPFLAGS_DEFAULT | // tp_flags - Py_TPFLAGS_BASETYPE), + Py_TPFLAGS_DEFAULT, // tp_flag, packagemanager_doc, // tp_doc 0, // tp_traverse 0, // tp_clear @@ -162,9 +134,240 @@ PyTypeObject PyPackageManager_Type = 0, // tp_dictoffset 0, // tp_init 0, // tp_alloc - PkgManagerNew, // tp_new + 0, // tp_new +}; + + +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; } }; +class 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)); + } + + + PyObject *GetPyPkg(const PkgIterator &Pkg) { + PyObject *depcache = NULL; + PyObject *cache = NULL; + + depcache = GetOwner(pyinst); + if (depcache != NULL && PyDepCache_Check(depcache)) + cache = GetOwner(depcache); + + return PyPackage_FromCpp(Pkg, true, cache); + } + + /* 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; } + + PyPkgManager(pkgDepCache *Cache) : pkgDPkgPM(Cache) {}; + PyObject *pyinst; +}; + +static PyObject *PkgManagerNew(PyTypeObject *type,PyObject *Args,PyObject *kwds) +{ + PyObject *Owner; + char *kwlist[] = {"depcache",0}; + if (PyArg_ParseTupleAndKeywords(Args,kwds,"O!",kwlist,&PyDepCache_Type, + &Owner) == 0) + return 0; + + PyPkgManager *pm = new PyPkgManager(GetCpp(Owner)); + + CppPyObject *PkgManagerObj = + CppPyObject_NEW(NULL, type,pm); + + pm->pyinst = PkgManagerObj; + + return PkgManagerObj; +} + +#ifdef COMPAT_0_7 +PyObject *GetPkgManager(PyObject *Self,PyObject *Args) +{ + PyErr_WarnEx(PyExc_DeprecationWarning, "apt_pkg.GetPackageManager() is " + "deprecated. Please see apt_pkg.PackageManager() for the " + "replacement.", 1); + return PkgManagerNew(&PyPackageManager2_Type,Args,0); +} +#endif + +static PyObject *PkgManagerInstall(PyObject *Self,PyObject *Args) +{ + PyPkgManager *pm = GetCpp(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(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(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(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(Self); + + pm->callReset(); + Py_INCREF(Py_None); + return HandleErrors(Py_None); +} + +static PyMethodDef PkgManager2Methods[] = +{ + {"install",PkgManagerInstall,METH_VARARGS, + "install(pkg: Package, filename: str) -> bool \n\n" + "Add a install action. Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {"configure",PkgManagerConfigure,METH_VARARGS, + "configure(pkg: Package) -> bool \n\n" + "Add a configure action. Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {"remove",PkgManagerRemove,METH_VARARGS, + "remove(pkg: Package, purge: bool) -> bool \n\n" + "Add a removal action. Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {"go",PkgManagerGo,METH_VARARGS, + "go(status_fd: int) -> bool \n\n" + "Start dpkg. Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {"reset",PkgManagerReset,METH_VARARGS, + "reset()\n\n" + "Reset the package manager for a new round.\n" + "Can be overriden in subclasses.\n\n" + "New in version 0.8.0."}, + {} +}; + +static const char *packagemanager2_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.\n\n" + "Methods in this class can be overriden in sub classes\n" + "to implement behavior different from APT's dpkg implementation."; +PyTypeObject PyPackageManager2_Type = +{ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "apt_pkg.PackageManager", // tp_name + sizeof(CppPyObject), // tp_basicsize + 0, // tp_itemsize + // Methods + CppDeallocPtr, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_compare + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + (Py_TPFLAGS_DEFAULT | // tp_flags + Py_TPFLAGS_BASETYPE), + packagemanager2_doc, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + PkgManager2Methods, // tp_methods + 0, // tp_members + 0, // tp_getset + &PyPackageManager_Type, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + 0, // tp_alloc + PkgManagerNew, // tp_new +}; /*}}}*/ -- cgit v1.2.3 From ab08c42c90e9aab009b6d5f1b4bdce0c68300fa5 Mon Sep 17 00:00:00 2001 From: Julian Andres Klode Date: Fri, 27 May 2011 16:06:22 +0200 Subject: Fix spelling errors reported by Lintian (sep[a->e]rated, overrid[d]en) --- debian/changelog | 1 + doc/source/library/apt.progress.base.rst | 6 +++--- doc/source/library/apt_pkg.rst | 2 +- python/cdrom.cc | 2 +- python/pkgmanager.cc | 12 ++++++------ 5 files changed, 12 insertions(+), 11 deletions(-) (limited to 'python/pkgmanager.cc') diff --git a/debian/changelog b/debian/changelog index 85cd3166..53830d98 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,7 @@ python-apt (0.8.0~exp5) UNRELEASED; urgency=low * utils/get_debian_mirrors.py: Adjust for new Alioth SCM urls * debian/control: Standards-Version 3.9.2 * Fix Lintian overrides + * Fix spelling errors reported by Lintian (sep[a->e]rated, overrid[d]en) [ Tshepang Lekhonkhobe ] * Fix get_changelog in Python 3 (Closes: #626532) diff --git a/doc/source/library/apt.progress.base.rst b/doc/source/library/apt.progress.base.rst index 3fd2a7a0..22006f77 100644 --- a/doc/source/library/apt.progress.base.rst +++ b/doc/source/library/apt.progress.base.rst @@ -233,7 +233,7 @@ InstallProgress (Abstract) Called when a error is detected during the install. - The following method should be overriden to implement progress reporting + The following method should be overridden to implement progress reporting for dpkg-based runs i.e. calls to :meth:`run` with a filename: .. method:: processing(pkg, stage) @@ -252,7 +252,7 @@ InstallProgress file (:file:`/var/lib/dpkg/status`) and documented in :manpage:`dpkg(1)`. - The following methods should be overriden to implement progress reporting + The following methods should be overridden to implement progress reporting for :meth:`run` calls with an :class:`apt_pkg.PackageManager` object as their parameter: @@ -274,7 +274,7 @@ InstallProgress This method is called when all changes have been applied. There are also several methods which are fully implemented and should not - be overriden by subclasses unless the subclass has very special needs: + be overridden by subclasses unless the subclass has very special needs: .. method:: fork() -> int diff --git a/doc/source/library/apt_pkg.rst b/doc/source/library/apt_pkg.rst index 81f2d408..ffef9c50 100644 --- a/doc/source/library/apt_pkg.rst +++ b/doc/source/library/apt_pkg.rst @@ -45,7 +45,7 @@ Working with the cache .. note:: - The cache supports colon-seperated name:architecture pairs. For + The cache supports colon-separated name:architecture pairs. For normal architectures, they are equal to a (name, architecture) tuple. For the the "any" architecture behavior is different, as "name:any" is equivalent to ("name:any", "any"). This is done so diff --git a/python/cdrom.cc b/python/cdrom.cc index 7f89e9d3..6ac16d59 100644 --- a/python/cdrom.cc +++ b/python/cdrom.cc @@ -52,7 +52,7 @@ static PyObject *cdrom_add(PyObject *Self,PyObject *Args) static char *cdrom_ident_doc = "ident(progress: apt_pkg.CdromProgress) -> str\n\n" "Try to identify the CD-ROM and if successful return the hexadecimal\n" - "CDROM-ID (and a integer version suffix seperated by -) as a\n" + "CDROM-ID (and a integer version suffix separated by -) as a\n" "string. Otherwise, return None or raise an error.\n\n" "The ID is created by hashing all file and directory names on the\n" "CD-ROM and appending the version."; diff --git a/python/pkgmanager.cc b/python/pkgmanager.cc index b7bed658..f51dbbbc 100644 --- a/python/pkgmanager.cc +++ b/python/pkgmanager.cc @@ -295,24 +295,24 @@ static PyMethodDef PkgManager2Methods[] = { {"install",PkgManagerInstall,METH_VARARGS, "install(pkg: Package, filename: str) -> bool \n\n" - "Add a install action. Can be overriden in subclasses.\n\n" + "Add a install action. Can be overridden in subclasses.\n\n" "New in version 0.8.0."}, {"configure",PkgManagerConfigure,METH_VARARGS, "configure(pkg: Package) -> bool \n\n" - "Add a configure action. Can be overriden in subclasses.\n\n" + "Add a configure action. Can be overridden in subclasses.\n\n" "New in version 0.8.0."}, {"remove",PkgManagerRemove,METH_VARARGS, "remove(pkg: Package, purge: bool) -> bool \n\n" - "Add a removal action. Can be overriden in subclasses.\n\n" + "Add a removal action. Can be overridden in subclasses.\n\n" "New in version 0.8.0."}, {"go",PkgManagerGo,METH_VARARGS, "go(status_fd: int) -> bool \n\n" - "Start dpkg. Can be overriden in subclasses.\n\n" + "Start dpkg. Can be overridden in subclasses.\n\n" "New in version 0.8.0."}, {"reset",PkgManagerReset,METH_VARARGS, "reset()\n\n" "Reset the package manager for a new round.\n" - "Can be overriden in subclasses.\n\n" + "Can be overridden in subclasses.\n\n" "New in version 0.8.0."}, {} }; @@ -323,7 +323,7 @@ static const char *packagemanager2_doc = "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.\n\n" - "Methods in this class can be overriden in sub classes\n" + "Methods in this class can be overridden in sub classes\n" "to implement behavior different from APT's dpkg implementation."; PyTypeObject PyPackageManager2_Type = { -- cgit v1.2.3