From: Michael Tremer Date: Mon, 21 Jun 2021 10:28:47 +0000 (+0000) Subject: Implement install/erase/update with new convenience functions X-Git-Tag: 0.9.28~1219 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b7e72fe2afdd570a5d5e24b5194390ef0d356966;p=pakfire.git Implement install/erase/update with new convenience functions Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 39b3c1f5b..6a32772c0 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "errors.h" @@ -204,6 +205,173 @@ static PyObject* Pakfire_get_repo(PakfireObject* self, PyObject* args) { return obj; } +static int convert_packages(PyObject* object, void* address) { + char*** packages = (char***)address; + + // Called for cleanup + if (!object) + goto ERROR; + + if (!PySequence_Check(object)) { + PyErr_SetString(PyExc_ValueError, "Packages must be a sequence"); + goto ERROR; + } + + const unsigned int length = PySequence_Length(object); + if (!length) { + PyErr_SetString(PyExc_ValueError, "Packages list is empty"); + goto ERROR; + } + + // Allocate array + *packages = calloc(length + 1, sizeof(*packages)); + if (!*packages) { + PyErr_SetFromErrno(PyExc_OSError); + goto ERROR; + } + + for (unsigned int i = 0; i < length; i++) { + PyObject* item = PySequence_GetItem(object, i); + + // Check if input is a string + if (!PyUnicode_Check(item)) { + Py_DECREF(item); + + PyErr_SetString(PyExc_AttributeError, "Expected a string"); + goto ERROR; + } + + // Fetch string + const char* package = PyUnicode_AsUTF8(item); + if (!package) { + Py_DECREF(item); + goto ERROR; + } + + // Add package to array + *packages[i] = strdup(package); + if (!*packages[i]) { + Py_DECREF(item); + goto ERROR; + } + + Py_DECREF(item); + } + + // Success + return Py_CLEANUP_SUPPORTED; + +ERROR: + if (*packages) { + for (char** package = *packages; *package; package++) + free(*package); + free(*packages); + } + + return 0; +} + +static PyObject* Pakfire_install(PakfireObject* self, PyObject* args, PyObject* kwargs) { + char* kwlist[] = { + "packages", + "include_recommended", + NULL + }; + char** packages = NULL; + int include_recommended = 1; + int flags = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$p", kwlist, + convert_packages, &packages, &include_recommended)) + return NULL; + + // XXX include_recommended + + // Run pakfire_install + int r = pakfire_install(self->pakfire, (const char**)packages, flags, NULL); + if (r) + PyErr_SetFromErrno(PyExc_OSError); + + if (packages) { + for (char** package = packages; *package; package++) + free(*package); + free(packages); + } + + if (r) + return NULL; + + Py_RETURN_NONE; +} + +static PyObject* Pakfire_erase(PakfireObject* self, PyObject* args, PyObject* kwargs) { + char* kwlist[] = { + "packages", + NULL + }; + char** packages = NULL; + int flags = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&", kwlist, + convert_packages, &packages)) + return NULL; + + // Run pakfire_erase + int r = pakfire_erase(self->pakfire, (const char**)packages, flags, NULL); + if (r) + PyErr_SetFromErrno(PyExc_OSError); + + if (packages) { + for (char** package = packages; *package; package++) + free(*package); + free(packages); + } + + if (r) + return NULL; + + Py_RETURN_NONE; +} + +static PyObject* Pakfire_update(PakfireObject* self, PyObject* args, PyObject* kwargs) { + char* kwlist[] = { + "packages", + "allow_archchange", + "allow_vendorchange", + NULL + }; + char** packages = NULL; + int allow_archchange = 0; + int allow_vendorchange = 0; + int flags = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$pp", kwlist, + convert_packages, &packages, &allow_archchange, &allow_vendorchange)) + return NULL; + + if (allow_archchange) + flags |= PAKFIRE_SOLVER_ALLOW_ARCHCHANGE; + + if (allow_vendorchange) + flags |= PAKFIRE_SOLVER_ALLOW_VENDORCHANGE; + + // Run pakfire_update + int r = pakfire_update(self->pakfire, (const char**)packages, flags, NULL); + if (r) + PyErr_SetFromErrno(PyExc_OSError); + + if (packages) { + for (char** package = packages; *package; package++) + free(*package); + free(packages); + } + + if (r) + return NULL; + + Py_RETURN_NONE; +} + static PyObject* _import_keylist(PakfireObject* pakfire, PakfireKey* keys) { PyObject* list = PyList_New(0); @@ -911,6 +1079,12 @@ static struct PyMethodDef Pakfire_methods[] = { METH_VARARGS, NULL }, + { + "erase", + (PyCFunction)Pakfire_erase, + METH_VARARGS|METH_KEYWORDS, + NULL + }, { "execute", (PyCFunction)Pakfire_execute, @@ -947,6 +1121,12 @@ static struct PyMethodDef Pakfire_methods[] = { METH_VARARGS, NULL }, + { + "install", + (PyCFunction)Pakfire_install, + METH_VARARGS|METH_KEYWORDS, + NULL, + }, { "read_makefile", (PyCFunction)Pakfire_read_makefile, @@ -971,6 +1151,12 @@ static struct PyMethodDef Pakfire_methods[] = { METH_NOARGS, NULL, }, + { + "update", + (PyCFunction)Pakfire_update, + METH_VARARGS|METH_KEYWORDS, + NULL + }, { "version_compare", (PyCFunction)Pakfire_version_compare, diff --git a/src/pakfire/cli.py b/src/pakfire/cli.py index fe0307f69..59e5cc0a7 100644 --- a/src/pakfire/cli.py +++ b/src/pakfire/cli.py @@ -163,12 +163,8 @@ class Cli(object): help=_("Update the whole system or one specific package")) update.add_argument("package", nargs="*", help=_("Give a name of a package to update or leave emtpy for all")) - update.add_argument("--exclude", "-x", nargs="+", - help=_("Exclude package from update")) update.add_argument("--allow-archchange", action="store_true", help=_("Allow changing the architecture of packages")) - update.add_argument("--allow-downgrade", action="store_true", - help=_("Allow downgrading of packages")) update.add_argument("--allow-vendorchange", action="store_true", help=_("Allow changing the vendor of packages")) update.set_defaults(func=self.handle_update) @@ -268,9 +264,6 @@ class Cli(object): return e.exit_code - def _execute_transaction(self, transaction): - transaction.run() - def handle_info(self, ns): with self.pakfire(ns) as p: for pkg in p.info(ns.package): @@ -286,22 +279,13 @@ class Cli(object): print("%-24s: %s" % (pkg.name, pkg.summary)) - def handle_update(self, ns, check=False): - with self.pakfire(ns) as p: - transaction = p.update( - ns.package, excludes=ns.exclude, - allow_archchange=ns.allow_archchange, - allow_vendorchange=ns.allow_vendorchange, - ) - - # If we are only checking for updates, - # we dump the transaction and exit here. - if check: - self._dump_transaction(transaction) - return - - # Otherwise we execute the transaction - self._execute_transaction(transaction) + def handle_update(self, ns): + p = self.pakfire(ns) + p.update( + ns.package, + allow_archchange=ns.allow_archchange, + allow_vendorchange=ns.allow_vendorchange, + ) def handle_sync(self, ns): with self.pakfire(ns) as p: @@ -325,11 +309,8 @@ class Cli(object): ) def handle_install(self, ns): - with self.pakfire(ns) as p: - transaction = p.install(ns.package, without_recommends=ns.without_recommends) - - # Execute the transaction - self._execute_transaction(transaction) + p = self.pakfire(ns) + p.install(ns.package, include_recommended=not ns.without_recommends) def handle_reinstall(self, ns): with self.pakfire(ns) as p: @@ -339,10 +320,8 @@ class Cli(object): self._execute_transaction(transaction) def handle_remove(self, ns): - with self.pakfire(ns) as p: - transaction = p.erase(ns.package) - - self._execute_transaction(transaction) + p = self.pakfire(ns) + p.erase(ns.package) def handle_provides(self, ns, long=False): with self.pakfire(ns) as p: