]> git.ipfire.org Git - pakfire.git/commitdiff
_pakfire: Remove the default context and require manual setup
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 1 Nov 2023 12:16:32 +0000 (12:16 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 1 Nov 2023 12:16:32 +0000 (12:16 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/_pakfire/_pakfiremodule.c
src/_pakfire/buildservice.c
src/_pakfire/ctx.c
src/_pakfire/ctx.h
src/_pakfire/package.c
src/_pakfire/package.h
src/_pakfire/pakfire.c
src/_pakfire/pakfire.h

index fd56a95a2bd9cc1ef34aaddcf61a7734939b56e0..e28595a14d49e47508e741e9625f3c68d06b0c16 100644 (file)
@@ -21,7 +21,6 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <libintl.h>
-#include <syslog.h>
 
 #include <pakfire/arch.h>
 #include <pakfire/dependencies.h>
@@ -50,173 +49,6 @@ PyObject* PyExc_DependencyError;
 PyObject* PyExc_CheckError;
 PyObject* PyExc_CheckFileVerificationError;
 
-struct pakfire_ctx* pakfire_ctx = NULL;
-
-static PyObject* setup_logger(void) {
-       PyObject* logging = NULL;
-       PyObject* logger = NULL;
-
-       // import logging
-       logging = PyImport_ImportModule("logging");
-       if (!logging)
-               goto ERROR;
-
-       // logging.getLogger("pakfire")
-       logger = PyObject_CallMethod(logging, "getLogger", "s", "pakfire");
-       if (!logger)
-               goto ERROR;
-
-ERROR:
-       Py_XDECREF(logging);
-
-       return logger;
-}
-
-static void __pakfire_log_callback(void* data, int level, const char* file, int line,
-               const char* fn, const char* format, va_list args) {
-       PyObject* logger = (PyObject*)data;
-       PyObject* result = NULL;
-       char* buffer = NULL;
-       int r;
-
-       PyObject* exception = NULL;
-       PyObject* type = NULL;
-       PyObject* value = NULL;
-       PyObject* traceback = NULL;
-
-       // Do nothing if the logger does not exist
-       if (!logger)
-               return;
-
-       // Translate priority to Python logging priorities
-       switch (level) {
-               case LOG_DEBUG:
-                       level = 10;
-                       break;
-
-               case LOG_INFO:
-                       level = 20;
-                       break;
-
-               case LOG_ERR:
-                       level = 40;
-                       break;
-
-               // Drop messages of an unknown level
-               default:
-                       return;
-       }
-
-       PyGILState_STATE state = PyGILState_Ensure();
-
-       // Format the log line
-       r = vasprintf(&buffer, format, args);
-       if (r < 0)
-               goto ERROR;
-
-       // Remove trailing newline
-       if (buffer[r - 1] == '\n')
-               r--;
-
-       // Call the logger
-       result = PyObject_CallMethod(logger, "log", "is#", level, buffer, r);
-       if (!result)
-               goto ERROR;
-
-ERROR:
-       /*
-               We cannot really catch any Python errors here, since we cannot send
-               any error codes up the chain.
-
-               So, in order to debug the problem, We will check if an exception has
-               occurred and if so, print it to the console.
-       */
-       exception = PyErr_Occurred();
-       if (exception) {
-               PyErr_Print();
-
-               // Fetch the exception and destroy it
-               PyErr_Fetch(&type, &value, &traceback);
-
-               Py_XDECREF(type);
-               Py_XDECREF(value);
-               Py_XDECREF(traceback);
-       }
-
-       if (buffer)
-               free(buffer);
-       Py_XDECREF(result);
-
-       // Release the GIL
-       PyGILState_Release(state);
-}
-
-static int initialize_context(void) {
-       PyObject* logger = NULL;
-       int r;
-
-       // Create a new context
-       r = pakfire_ctx_create(&pakfire_ctx, NULL);
-       if (r) {
-               PyErr_SetFromErrno(PyExc_OSError);
-               goto ERROR;
-       }
-
-       // Setup the python logger
-       logger = setup_logger();
-       if (r)
-               goto ERROR;
-
-       // Pass all log messages to Python
-       pakfire_ctx_set_log_callback(pakfire_ctx, __pakfire_log_callback, logger);
-       Py_INCREF(logger);
-
-       // Set the log level to DEBUG
-       pakfire_ctx_set_log_level(pakfire_ctx, LOG_DEBUG);
-
-       goto CLEANUP;
-
-ERROR:
-       if (pakfire_ctx)
-               pakfire_ctx_unref(pakfire_ctx);
-
-CLEANUP:
-       Py_XDECREF(logger);
-
-       return r;
-}
-
-static PyObject* _pakfire_set_cache_path(PyObject* self, PyObject* args) {
-       const char* path = NULL;
-       int r;
-
-       if (!PyArg_ParseTuple(args, "s", &path))
-               return NULL;
-
-       // Set the cache path
-       r = pakfire_ctx_set_cache_path(pakfire_ctx, path);
-       if (r) {
-               errno = -r;
-               PyErr_SetFromErrno(PyExc_OSError);
-
-               return NULL;
-       }
-
-       Py_RETURN_NONE;
-}
-
-static PyObject* _pakfire_set_log_level(PyObject* self, PyObject* args) {
-       int level = 0;
-
-       if (!PyArg_ParseTuple(args, "i", &level))
-               return NULL;
-
-       // Set the log level
-       pakfire_ctx_set_log_level(pakfire_ctx, level);
-
-       Py_RETURN_NONE;
-}
-
 static PyObject* _pakfire_supported_arches(void) {
        int r;
 
@@ -271,18 +103,6 @@ static PyObject* _pakfire_version_compare(PyObject* self, PyObject* args) {
 }
 
 static PyMethodDef pakfireModuleMethods[] = {
-       {
-               "set_cache_path",
-               (PyCFunction)_pakfire_set_cache_path,
-               METH_VARARGS,
-               NULL,
-       },
-       {
-               "set_log_level",
-               (PyCFunction)_pakfire_set_log_level,
-               METH_VARARGS,
-               NULL,
-       },
        {"supported_arches", (PyCFunction)_pakfire_supported_arches, METH_NOARGS, NULL },
        {
                "version_compare",
@@ -432,11 +252,6 @@ PyMODINIT_FUNC PyInit__pakfire(void) {
        if (PyModule_AddIntMacro(module, PAKFIRE_KEY_ALGO_ED25519) < 0)
                goto ERROR;
 
-       // Initialize the context
-       r = initialize_context();
-       if (r)
-               goto ERROR;
-
        return module;
 
 ERROR:
index 67a401be06b68384e2938e461d7ef0ab93660c2a..7772df4601b59ead5ed4c46678aaa9001ff0dc97 100644 (file)
@@ -24,8 +24,7 @@
 #include <pakfire/buildservice.h>
 
 #include "buildservice.h"
-
-extern struct pakfire_ctx* pakfire_ctx;
+#include "ctx.h"
 
 static PyObject* BuildService_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
        BuildServiceObject* self = (BuildServiceObject *)type->tp_alloc(type, 0);
@@ -36,9 +35,13 @@ static PyObject* BuildService_new(PyTypeObject* type, PyObject* args, PyObject*
 }
 
 static int BuildService_init(BuildServiceObject* self, PyObject* args, PyObject* kwds) {
+       CtxObject* ctx = NULL;
        int r;
 
-       r = pakfire_buildservice_create(&self->service, pakfire_ctx);
+       if (!PyArg_ParseTuple(args, "O!", &CtxType, &ctx))
+               return -1;
+
+       r = pakfire_buildservice_create(&self->service, ctx->ctx);
        if (r) {
                errno = -r;
 
index d1463619bf4004e20800503114c5dcf5c6a1c811..e8fd927bf3a65c93ffe6cb727da8f7d3d5fe1fdb 100644 (file)
@@ -18,7 +18,9 @@
 #                                                                             #
 #############################################################################*/
 
+#define PY_SSIZE_T_CLEAN
 #include <Python.h>
+#include <syslog.h>
 
 #include <pakfire/ctx.h>
 
@@ -32,6 +34,122 @@ static PyObject* Ctx_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
        return (PyObject *)self;
 }
 
+static void Ctx_log_callback(void* data, int level, const char* file, int line,
+               const char* fn, const char* format, va_list args) {
+       PyObject* logger = (PyObject*)data;
+       PyObject* result = NULL;
+       char* buffer = NULL;
+       int r;
+
+       PyObject* exception = NULL;
+       PyObject* type = NULL;
+       PyObject* value = NULL;
+       PyObject* traceback = NULL;
+
+       // Do nothing if the logger does not exist
+       if (!logger)
+               return;
+
+       // Translate priority to Python logging priorities
+       switch (level) {
+               case LOG_DEBUG:
+                       level = 10;
+                       break;
+
+               case LOG_INFO:
+                       level = 20;
+                       break;
+
+               case LOG_ERR:
+                       level = 40;
+                       break;
+
+               // Drop messages of an unknown level
+               default:
+                       return;
+       }
+
+       PyGILState_STATE state = PyGILState_Ensure();
+
+       // Format the log line
+       r = vasprintf(&buffer, format, args);
+       if (r < 0)
+               goto ERROR;
+
+       // Remove trailing newline
+       if (buffer[r - 1] == '\n')
+               r--;
+
+       // Call the logger
+       result = PyObject_CallMethod(logger, "log", "is#", level, buffer, r);
+       if (!result)
+               goto ERROR;
+
+ERROR:
+       /*
+               We cannot really catch any Python errors here, since we cannot send
+               any error codes up the chain.
+
+               So, in order to debug the problem, We will check if an exception has
+               occurred and if so, print it to the console.
+       */
+       exception = PyErr_Occurred();
+       if (exception) {
+               PyErr_Print();
+
+               // Fetch the exception and destroy it
+               PyErr_Fetch(&type, &value, &traceback);
+
+               Py_XDECREF(type);
+               Py_XDECREF(value);
+               Py_XDECREF(traceback);
+       }
+
+       if (buffer)
+               free(buffer);
+       Py_XDECREF(result);
+
+       // Release the GIL
+       PyGILState_Release(state);
+}
+
+static void Ctx___set_logger(CtxObject* self, PyObject* logger) {
+       // Dereference the old logger
+       Py_XDECREF(self->logger);
+
+       // Store the new logger
+       self->logger = logger;
+       Py_INCREF(self->logger);
+
+       // Set the logger
+       pakfire_ctx_set_log_callback(self->ctx, Ctx_log_callback, self->logger);
+}
+
+static int Ctx_setup_logging(CtxObject* self) {
+       PyObject* logging = NULL;
+       PyObject* logger = NULL;
+       int r = -1;
+
+       // import logging
+       logging = PyImport_ImportModule("logging");
+       if (!logging)
+               goto ERROR;
+
+       // logging.getLogger("pakfire")
+       logger = PyObject_CallMethod(logging, "getLogger", "s", "pakfire");
+       if (!logger)
+               goto ERROR;
+
+       // Set default logger
+       Ctx___set_logger(self, logger);
+
+ERROR:
+       Py_XDECREF(logging);
+       Py_XDECREF(logger);
+
+       return r;
+}
+
 static int Ctx_init(CtxObject* self, PyObject* args, PyObject* kwargs) {
        char* kwlist[] = { (char*)"path", NULL };
        const char* path = NULL;
@@ -50,6 +168,9 @@ static int Ctx_init(CtxObject* self, PyObject* args, PyObject* kwargs) {
                return -1;
        }
 
+       // Set the log level to DEBUG
+       pakfire_ctx_set_log_level(self->ctx, LOG_DEBUG);
+
        return 0;
 }
 
@@ -57,14 +178,66 @@ static void Ctx_dealloc(CtxObject* self) {
        if (self->ctx)
                pakfire_ctx_unref(self->ctx);
 
+       Py_XDECREF(self->logger);
+
        Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
+// Logging
+
+static PyObject* Ctx_set_logger(CtxObject* self, PyObject* args) {
+       PyObject* logger = NULL;
+
+       if (!PyArg_ParseTuple(args, "O", &logger))
+               return NULL;
+
+       // XXX Check if we have a log method
+
+       // Set the logger
+       Ctx___set_logger(self, logger);
+
+       Py_RETURN_NONE;
+}
+
+static PyObject* Ctx_set_cache_path(CtxObject* self, PyObject* value) {
+       const char* path = NULL;
+       int r;
+
+       // Fetch the path
+       path = PyUnicode_AsUTF8(value);
+       if (!path)
+               return NULL;
+
+       // Set the cache path
+       r = pakfire_ctx_set_cache_path(self->ctx, path);
+       if (r) {
+               errno = -r;
+               PyErr_SetFromErrno(PyExc_OSError);
+
+               return NULL;
+       }
+
+       Py_RETURN_NONE;
+}
+
 static struct PyMethodDef Ctx_methods[] = {
+       {
+               "set_logger",
+               (PyCFunction)Ctx_set_logger,
+               METH_VARARGS,
+               NULL,
+       },
        { NULL },
 };
 
 static struct PyGetSetDef Ctx_getsetters[] = {
+       {
+               "cache_path",
+               NULL,
+               (setter)Ctx_set_cache_path,
+               NULL,
+               NULL,
+       },
     { NULL },
 };
 
index 8c3177442f8cc1b4bde0815efdfe5d66b22a1521..7ff1b0dcac4dbf6893d20c8230593688599de869 100644 (file)
@@ -28,6 +28,8 @@
 typedef struct {
        PyObject_HEAD
        struct pakfire_ctx* ctx;
+
+       PyObject* logger;
 } CtxObject;
 
 extern PyTypeObject CtxType;
index a0ca9702e25160057b5bf45698e47a7a6720ae3a..a28bca09d65d1b62a49a7313f8e08c09ec3d8e84 100644 (file)
@@ -34,8 +34,6 @@
 #include "repo.h"
 #include "util.h"
 
-extern struct pakfire_ctx* pakfire_ctx;
-
 PyObject* new_package(PyTypeObject* type, struct pakfire_package* pkg) {
        PackageObject* self = (PackageObject *)type->tp_alloc(type, 0);
        if (self) {
@@ -48,6 +46,7 @@ PyObject* new_package(PyTypeObject* type, struct pakfire_package* pkg) {
 static PyObject* Package_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
        PackageObject* self = (PackageObject *)type->tp_alloc(type, 0);
        if (self) {
+               self->ctx = NULL;
                self->package = NULL;
        }
 
@@ -57,6 +56,9 @@ static PyObject* Package_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
 static void Package_dealloc(PackageObject* self) {
        pakfire_package_unref(self->package);
 
+       if (self->ctx)
+               pakfire_ctx_unref(self->ctx);
+
        Py_TYPE(self)->tp_free((PyObject *)self);
 }
 
@@ -71,6 +73,9 @@ static int Package_init(PackageObject* self, PyObject* args, PyObject* kwds) {
                        &name, &evr, &arch))
                return -1;
 
+       // Store a reference to the context
+       self->ctx = pakfire_ctx_ref(pakfire->ctx);
+
        int r = pakfire_package_create(&self->package, pakfire->pakfire, repo->repo, name, evr, arch);
        if (r) {
                PyErr_SetFromErrno(PyExc_OSError);
@@ -555,7 +560,7 @@ static PyObject* Package_get_reverse_requires(PackageObject* self) {
        int r;
 
        // Create a new packagelist
-       r = pakfire_packagelist_create(&list, pakfire_ctx);
+       r = pakfire_packagelist_create(&list, self->ctx);
        if (r) {
                PyErr_SetFromErrno(PyExc_OSError);
                goto ERROR;
index e7942c8698354b70111ef7bf20ada48205bf5d50..dc4cddcd1e16d7d0addc8c4482be40eecf3d6175 100644 (file)
 
 #include <Python.h>
 
+#include <pakfire/ctx.h>
 #include <pakfire/package.h>
 
 #include "pakfire.h"
 
 typedef struct {
        PyObject_HEAD
+       struct pakfire_ctx* ctx;
        struct pakfire_package* package;
 } PackageObject;
 
index 944a38483a16ef65de2cf57c5c2ba2ba77dd539c..deb462669122de8024a553ebd688a7b546221cca 100644 (file)
 #include <pakfire/util.h>
 
 #include "archive.h"
+#include "ctx.h"
 #include "errors.h"
 #include "key.h"
 #include "pakfire.h"
 #include "repo.h"
 #include "util.h"
 
-extern struct pakfire_ctx* pakfire_ctx;
-
 static PyObject* Pakfire_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
        PakfireObject* self = (PakfireObject *)type->tp_alloc(type, 0);
-       if (self)
+       if (self) {
+               self->ctx = NULL;
                self->pakfire = NULL;
+       }
 
        return (PyObject *)self;
 }
 
 static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
        char* kwlist[] = {
+               "ctx",
                "path",
                "arch",
                "conf",
                NULL,
        };
+       CtxObject* ctx = NULL;
        const char* path = NULL;
        const char* arch = NULL;
        PyObject* conf = Py_None;
@@ -70,8 +73,8 @@ static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
 
        FILE* fconf = NULL;
 
-       if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzO", kwlist,
-                       &path, &arch, &conf))
+       if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|zzO", kwlist,
+                       &CtxType, &ctx, &path, &arch, &conf))
                goto ERROR;
 
        // Map the configuration
@@ -85,8 +88,11 @@ static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
 
        Py_BEGIN_ALLOW_THREADS
 
+       // Store a reference to the context
+       self->ctx = pakfire_ctx_ref(ctx->ctx);
+
        // Create a new Pakfire instance
-       r = pakfire_create(&self->pakfire, pakfire_ctx, path, arch, fconf, flags);
+       r = pakfire_create(&self->pakfire, self->ctx, path, arch, fconf, flags);
 
        Py_END_ALLOW_THREADS
 
@@ -123,6 +129,8 @@ static void Pakfire_dealloc(PakfireObject* self) {
 
                Py_END_ALLOW_THREADS
        }
+       if (self->ctx)
+               pakfire_ctx_unref(self->ctx);
 
        Py_TYPE(self)->tp_free((PyObject *)self);
 }
@@ -243,7 +251,7 @@ static PyObject* Pakfire_generate_key(PakfireObject* self, PyObject* args, PyObj
                return NULL;
 
        // Generate a new key
-       int r = pakfire_key_generate(&key, pakfire_ctx, algo, comment);
+       int r = pakfire_key_generate(&key, self->ctx, algo, comment);
        if (r) {
                PyErr_SetFromErrno(PyExc_OSError);
                return NULL;
@@ -274,7 +282,7 @@ static PyObject* Pakfire_import_key(PakfireObject* self, PyObject* args) {
                return NULL;
 
        // Import the key
-       r = pakfire_key_import(&key, pakfire_ctx, f);
+       r = pakfire_key_import(&key, self->ctx, f);
        if (r) {
                PyErr_SetFromErrno(PyExc_OSError);
                goto ERROR;
@@ -304,7 +312,7 @@ static PyObject* Pakfire_whatprovides(PakfireObject* self, PyObject* args) {
                return NULL;
 
        // Create a new list
-       r = pakfire_packagelist_create(&list, pakfire_ctx);
+       r = pakfire_packagelist_create(&list, self->ctx);
        if (r) {
                PyErr_SetFromErrno(PyExc_OSError);
                goto ERROR;
@@ -338,7 +346,7 @@ static PyObject* Pakfire_whatrequires(PakfireObject* self, PyObject* args) {
        Py_BEGIN_ALLOW_THREADS
 
        // Create a new list
-       r = pakfire_packagelist_create(&list, pakfire_ctx);
+       r = pakfire_packagelist_create(&list, self->ctx);
        if (r) {
                Py_BLOCK_THREADS
                PyErr_SetFromErrno(PyExc_OSError);
@@ -380,7 +388,7 @@ static PyObject* Pakfire_search(PakfireObject* self, PyObject* args, PyObject* k
        if (name_only)
                flags |= PAKFIRE_SEARCH_NAME_ONLY;
 
-       r = pakfire_packagelist_create(&list, pakfire_ctx);
+       r = pakfire_packagelist_create(&list, self->ctx);
        if (r) {
                PyErr_SetFromErrno(PyExc_OSError);
                goto ERROR;
index 5927e6aae3316bce1111f96d737be41920964cdd..31c14fe62bf1c0ce2141924fd3f46f8b80ef5be2 100644 (file)
@@ -27,6 +27,7 @@
 
 typedef struct {
        PyObject_HEAD
+       struct pakfire_ctx* ctx;
     struct pakfire* pakfire;
 
        // Callbacks