From: Michael Tremer Date: Tue, 2 Mar 2021 21:52:06 +0000 (+0000) Subject: python: Export pakfire_execute_script X-Git-Tag: 0.9.28~1285^2~663 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6cce3cec03c5c463ae7995454ffade679496273e;p=pakfire.git python: Export pakfire_execute_script Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 68a766330..39b040970 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -537,6 +537,117 @@ static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject* Py_RETURN_NONE; } +static PyObject* Pakfire_execute_script(PakfireObject* self, PyObject* args, PyObject* kwds) { + char* kwlist[] = {"script", "environ", "enable_network", "interactive", + "logging_callback", NULL}; + + const char* script = NULL; + PyObject* environ = NULL; + int enable_network = 0; + int interactive = 0; + PyObject* logging_callback = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|OppO", kwlist, &script, &environ, + &enable_network, &interactive, &logging_callback)) + return NULL; + + // Check if logging_callback is + if (logging_callback && !PyCallable_Check(logging_callback)) { + PyErr_SetString(PyExc_TypeError, "logging_callback must be callable\n"); + 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 + + char* envp[environ_length + 1]; + int flags = 0; + + // 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) { + // Cleanup + for (unsigned int i = 0; envp[i]; i++) + free(envp[i]); + + return PyErr_NoMemory(); + } + } + } + + // Terminate envp + envp[environ_length] = NULL; + + // Enable network? + if (enable_network) + flags |= PAKFIRE_EXECUTE_ENABLE_NETWORK; + + // Interactive? + if (interactive) + flags |= PAKFIRE_EXECUTE_INTERACTIVE; + + // Set logging callback + Pakfire_execute_logging_callback = logging_callback; + + // Execute script + int r = pakfire_execute_script(self->pakfire, script, strlen(script), envp, flags, + (logging_callback) ? __Pakfire_execute_logging_callback : NULL); + + // Cleanup + for (unsigned int i = 0; envp[i]; i++) + free(envp[i]); + + // Raise an OS error if r < 0 + if (r < 0) { + errno = -r; + + PyErr_SetFromErrno(PyExc_OSError); + return NULL; + + // Raise exception when the command failed + } else if (r > 0) { + PyObject* code = PyLong_FromLong(r); + + PyErr_SetObject(PyExc_CommandExecutionError, code); + Py_DECREF(code); + + return NULL; + } + + // Return nothing + Py_RETURN_NONE; +} + static PyObject* Pakfire_read_makefile(PakfireObject* self, PyObject* args) { const char* path = NULL; @@ -581,6 +692,12 @@ static struct PyMethodDef Pakfire_methods[] = { METH_VARARGS|METH_KEYWORDS, NULL }, + { + "execute_script", + (PyCFunction)Pakfire_execute_script, + METH_VARARGS|METH_KEYWORDS, + NULL + }, { "generate_key", (PyCFunction)Pakfire_generate_key, diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index 69a17d329..a8e259697 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -29,6 +29,7 @@ global: pakfire_deactivate; pakfire_execute; pakfire_execute_command; + pakfire_execute_script; pakfire_get_arch; pakfire_get_cache_path; pakfire_get_installed_repo;