From: Michael Tremer Date: Mon, 11 Jan 2021 17:55:05 +0000 (+0000) Subject: python: Export pakfire_execute() into Python X-Git-Tag: 0.9.28~1285^2~893 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9d6b128a7babc46f3bdbbacfec1579b1b136f49b;p=pakfire.git python: Export pakfire_execute() into Python Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/_pakfiremodule.c b/src/_pakfire/_pakfiremodule.c index d46f538d5..31a91b792 100644 --- a/src/_pakfire/_pakfiremodule.c +++ b/src/_pakfire/_pakfiremodule.c @@ -102,6 +102,10 @@ PyMODINIT_FUNC PyInit__pakfire(void) { Py_INCREF(PyExc_BadSignatureError); PyModule_AddObject(module, "BadSignatureError", PyExc_BadSignatureError); + PyExc_CommandExecutionError = PyErr_NewException("_pakfire.CommandExecutionError", NULL, NULL); + Py_INCREF(PyExc_CommandExecutionError); + PyModule_AddObject(module, "CommandExecutionError", PyExc_CommandExecutionError); + PyExc_DependencyError = PyErr_NewException("_pakfire.DependencyError", NULL, NULL); Py_INCREF(PyExc_DependencyError); PyModule_AddObject(module, "DependencyError", PyExc_DependencyError); diff --git a/src/_pakfire/errors.h b/src/_pakfire/errors.h index 35033c0c0..76b94418a 100644 --- a/src/_pakfire/errors.h +++ b/src/_pakfire/errors.h @@ -25,6 +25,7 @@ // Exceptions PyObject* PyExc_BadSignatureError; +PyObject* PyExc_CommandExecutionError; PyObject* PyExc_DependencyError; #endif /* PYTHON_PAKFIRE_ERRORS_H */ diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 627280c96..3cf085d4a 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -20,6 +20,8 @@ #include +#include +#include #include #include #include @@ -27,6 +29,7 @@ #include #include +#include "errors.h" #include "key.h" #include "pakfire.h" #include "repo.h" @@ -329,7 +332,126 @@ static Py_ssize_t Pakfire_len(PakfireObject* self) { return pakfire_count_packages(self->pakfire); } +static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject* kwds) { + char* kwlist[] = {"command", "environ", NULL}; + + PyObject* command = NULL; + PyObject* environ = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, &command, &environ)) + return NULL; + + // Check if command is a list + if (!PyList_Check(command)) { + PyErr_SetString(PyExc_TypeError, "command must be a list"); + return NULL; + } + + ssize_t command_length = PyList_Size(command); + + // Check if command is not empty + if (command_length == 0) { + PyErr_SetString(PyExc_ValueError, "command is empty"); + return NULL; + } + + // All arguments in command must be strings + for (unsigned int i = 0; i < command_length; i++) { + PyObject* item = PyList_GET_ITEM(command, i); + + if (!PyUnicode_Check(item)) { + PyErr_Format(PyExc_TypeError, "Item %u in command is not a string", i); + return NULL; + } + } + + ssize_t environ_length = 0; + PyObject* key; + PyObject* value; + Py_ssize_t p = 0; + + if (environ) { + // Check if environ is a dictionary + if (!PyDict_Check(environ)) { + PyErr_SetString(PyExc_TypeError, "environ must be a dictionary"); + return NULL; + } + + // All keys and values must be strings + while (PyDict_Next(environ, &p, &key, &value)) { + if (!PyUnicode_Check(key) || !PyUnicode_Check(value)) { + PyErr_SetString(PyExc_TypeError, "Environment contains a non-string object"); + return NULL; + } + } + + environ_length = PyDict_Size(environ); + } + + // All inputs look fine + + const char* argv[command_length + 1]; + char* envp[environ_length + 1]; + + // Parse arguments + for (unsigned int i = 0; i < command_length; i++) { + PyObject* item = PyList_GET_ITEM(command, i); + argv[i] = PyUnicode_AsUTF8(item); + } + + // Parse environ + if (environ) { + unsigned int i = 0; + p = 0; + + while (PyDict_Next(environ, &p, &key, &value)) { + int r = asprintf(&envp[i], "%s=%s", PyUnicode_AsUTF8(key), PyUnicode_AsUTF8(value)); + + // Handle errors + if (r < 0) { + envp[i] = NULL; + + // Cleanup + for (unsigned int i = 0; envp[i]; i++) + free(envp[i]); + + return PyErr_NoMemory(); + } + } + } + + // Terminate argv and envp + argv[command_length] = NULL; + envp[environ_length] = NULL; + + // Execute command + int r = pakfire_execute(self->pakfire, argv[0], argv, 0); + + // Cleanup + for (unsigned int i = 0; envp[i]; i++) + free(envp[i]); + + // Raise exception when the command failed + if (r) { + PyObject* code = PyLong_FromLong(r); + + PyErr_SetObject(PyExc_CommandExecutionError, code); + Py_DECREF(code); + + return NULL; + } + + // Return nothing + Py_RETURN_NONE; +} + static struct PyMethodDef Pakfire_methods[] = { + { + "execute", + (PyCFunction)Pakfire_execute, + METH_VARARGS|METH_KEYWORDS, + NULL + }, { "generate_key", (PyCFunction)Pakfire_generate_key, diff --git a/src/pakfire/__init__.py b/src/pakfire/__init__.py index 25e884063..8a1a152b4 100644 --- a/src/pakfire/__init__.py +++ b/src/pakfire/__init__.py @@ -20,3 +20,6 @@ ############################################################################### from .base import Pakfire, PakfireServer + +# Import Exceptions +from ._pakfire import CommandExecutionError