]> git.ipfire.org Git - pakfire.git/commitdiff
python: Export pakfire_execute_script
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 2 Mar 2021 21:52:06 +0000 (21:52 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 2 Mar 2021 21:52:06 +0000 (21:52 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/pakfire.c
src/libpakfire/libpakfire.sym

index 68a7663305bfc13be583b331f715545159023587..39b040970b62c604f00220c26d78967e32b5a4f9 100644 (file)
@@ -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,
index 69a17d3290a97c7abdd2b79fe97304d0b78ccd3e..a8e259697289b486056b50fca731ddf1f57e6526 100644 (file)
@@ -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;