]> git.ipfire.org Git - pakfire.git/commitdiff
python: Make callbacks available from Python
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 9 Dec 2021 11:59:10 +0000 (11:59 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 9 Dec 2021 11:59:10 +0000 (11:59 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/pakfire.c
src/_pakfire/pakfire.h

index 1cdf5a963dde763153dc7839854e957941197bd9..8320bdd7347f22702347fd281e5b154fe68a680c 100644 (file)
@@ -47,18 +47,22 @@ static PyObject* Pakfire_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
        PakfireObject* self = (PakfireObject *)type->tp_alloc(type, 0);
        if (self) {
                self->pakfire = NULL;
-               self->logger = NULL;
+
+               // Callbacks
+               self->callbacks.log = NULL;
+               self->callbacks.status = NULL;
+               self->callbacks.progress = NULL;
        }
 
        return (PyObject *)self;
 }
 
-static void Pakfire_logging_callback(void* data, int priority, const char* file, int line,
+static void Pakfire_log_callback(void* data, int priority, const char* file, int line,
                const char* fn, const char* format, va_list args) {
-       PyObject* callback = (PyObject*)data;
+       struct callbacks* callbacks = (struct callbacks*)data;
 
        // Do nothing if callback isn't set
-       if (!callback)
+       if (!callbacks->log)
                return;
 
        // Translate priority to Python logging priorities
@@ -95,7 +99,7 @@ static void Pakfire_logging_callback(void* data, int priority, const char* file,
                goto ERROR;
 
        // Call the callback
-       result = PyObject_CallObject(callback, tuple);
+       result = PyObject_CallObject(callbacks->log, tuple);
 
 ERROR:
        if (buffer)
@@ -104,29 +108,87 @@ ERROR:
        Py_XDECREF(result);
 }
 
+static void Pakfire_status_callback(void* data, const char* message) {
+       struct callbacks* callbacks = (struct callbacks*)data;
+
+       // Do nothing if callback isn't set
+       if (!callbacks->status)
+               return;
+
+       PyObject* args = NULL;
+       PyObject* result = NULL;
+
+       // Create arguments tuple
+       args = Py_BuildValue("(s)", message);
+       if (!args)
+               goto ERROR;
+
+       // Call the callback
+       result = PyObject_CallObject(callbacks->status, args);
+
+ERROR:
+       Py_XDECREF(args);
+       Py_XDECREF(result);
+}
+
+static void Pakfire_progress_callback(void* data, int progress) {
+       struct callbacks* callbacks = (struct callbacks*)data;
+
+       // Do nothing if callback isn't set
+       if (!callbacks->progress)
+               return;
+
+       PyObject* args = NULL;
+       PyObject* result = NULL;
+
+       // Create arguments tuple
+       args = Py_BuildValue("(i)", progress);
+       if (!args)
+               goto ERROR;
+
+       // Call the callback
+       result = PyObject_CallObject(callbacks->progress, args);
+
+ERROR:
+       Py_XDECREF(args);
+       Py_XDECREF(result);
+}
+
 static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
        char* kwlist[] = { "path", "arch", "logger", "offline", "conf", "build",
-               "enable_ccache", "enable_snapshot", NULL };
+               "enable_ccache", "enable_snapshot", "status_callback", "progress_callback", NULL };
        const char* path = NULL;
        const char* arch = NULL;
-       PyObject* logger = NULL;
        const char* conf = NULL;
        int offline = 0;
        int build = 0;
        int enable_ccache = 1;
        int enable_snapshot = 1;
 
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOpzppp", kwlist,
-                       &path, &arch, &logger, &offline, &conf, &build,
-                       &enable_ccache, &enable_snapshot))
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOpzpppOO", kwlist,
+                       &path, &arch, &self->callbacks.log, &offline, &conf, &build,
+                       &enable_ccache, &enable_snapshot, &self->callbacks.status,
+                       &self->callbacks.progress))
                return -1;
 
-       // Check if logger is callable
-       if (logger && !PyCallable_Check(logger)) {
+       // Check if log callback is callable
+       if (self->callbacks.log && !PyCallable_Check(self->callbacks.log)) {
                PyErr_SetString(PyExc_TypeError, "logger must be callable\n");
                return -1;
        }
 
+       // Check if status callback is callable
+       if (self->callbacks.status && !PyCallable_Check(self->callbacks.status)) {
+               PyErr_SetString(PyExc_TypeError, "status callback must be callable\n");
+               return -1;
+       }
+
+       // Check if progress callback is callable
+       if (self->callbacks.progress && !PyCallable_Check(self->callbacks.progress)) {
+               PyErr_SetString(PyExc_TypeError, "progress callback must be callable\n");
+               return -1;
+       }
+
        int flags = 0;
 
        // Enable offline mode
@@ -146,10 +208,24 @@ static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
 
        // Configure callbacks
        struct pakfire_callbacks callbacks = {
-               .data = logger,
-               .log  = (logger) ? Pakfire_logging_callback : NULL,
+               .data = &self->callbacks,
        };
 
+       if (self->callbacks.log) {
+               callbacks.log = Pakfire_log_callback;
+               Py_INCREF(self->callbacks.log);
+       }
+
+       if (self->callbacks.status) {
+               callbacks.status = Pakfire_status_callback;
+               Py_INCREF(self->callbacks.status);
+       }
+
+       if (self->callbacks.progress) {
+               callbacks.progress = Pakfire_progress_callback;
+               Py_INCREF(self->callbacks.progress);
+       }
+
        // Create a new Pakfire instance
        int r = pakfire_create(&self->pakfire, path, arch, conf, flags, &callbacks);
        if (r) {
@@ -167,12 +243,6 @@ static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
                return -1;
     }
 
-       // Store a reference to the logger
-       if (logger) {
-               self->logger = logger;
-               Py_INCREF(self->logger);
-       }
-
        return 0;
 }
 
@@ -189,8 +259,9 @@ static void Pakfire_dealloc(PakfireObject* self) {
 
                TODO This has to move into struct pakfire or something similar.
        */
-       if (self->logger)
-               Py_DECREF(self->logger);
+       Py_XDECREF(self->callbacks.log);
+       Py_XDECREF(self->callbacks.status);
+       Py_XDECREF(self->callbacks.progress);
 #endif
 
        Py_TYPE(self)->tp_free((PyObject *)self);
index c8215766e01ee69a0c52096fbc61bddb2493d4ab..f720f1402b84ad7f5427c01c7eb82241477f13b4 100644 (file)
 typedef struct {
        PyObject_HEAD
     struct pakfire* pakfire;
-    PyObject* logger;
+
+       // Callbacks
+       struct callbacks {
+               PyObject* log;
+               PyObject* status;
+               PyObject* progress;
+       } callbacks;
 } PakfireObject;
 
 extern PyTypeObject PakfireType;