From: Michael Tremer Date: Wed, 1 Nov 2023 12:16:32 +0000 (+0000) Subject: _pakfire: Remove the default context and require manual setup X-Git-Tag: 0.9.30~1350 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3dd7ad1e829524d9874d09b81807a756e3a72af8;p=pakfire.git _pakfire: Remove the default context and require manual setup Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/_pakfiremodule.c b/src/_pakfire/_pakfiremodule.c index fd56a95a2..e28595a14 100644 --- a/src/_pakfire/_pakfiremodule.c +++ b/src/_pakfire/_pakfiremodule.c @@ -21,7 +21,6 @@ #define PY_SSIZE_T_CLEAN #include #include -#include #include #include @@ -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: diff --git a/src/_pakfire/buildservice.c b/src/_pakfire/buildservice.c index 67a401be0..7772df460 100644 --- a/src/_pakfire/buildservice.c +++ b/src/_pakfire/buildservice.c @@ -24,8 +24,7 @@ #include #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; diff --git a/src/_pakfire/ctx.c b/src/_pakfire/ctx.c index d1463619b..e8fd927bf 100644 --- a/src/_pakfire/ctx.c +++ b/src/_pakfire/ctx.c @@ -18,7 +18,9 @@ # # #############################################################################*/ +#define PY_SSIZE_T_CLEAN #include +#include #include @@ -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 }, }; diff --git a/src/_pakfire/ctx.h b/src/_pakfire/ctx.h index 8c3177442..7ff1b0dca 100644 --- a/src/_pakfire/ctx.h +++ b/src/_pakfire/ctx.h @@ -28,6 +28,8 @@ typedef struct { PyObject_HEAD struct pakfire_ctx* ctx; + + PyObject* logger; } CtxObject; extern PyTypeObject CtxType; diff --git a/src/_pakfire/package.c b/src/_pakfire/package.c index a0ca9702e..a28bca09d 100644 --- a/src/_pakfire/package.c +++ b/src/_pakfire/package.c @@ -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; diff --git a/src/_pakfire/package.h b/src/_pakfire/package.h index e7942c869..dc4cddcd1 100644 --- a/src/_pakfire/package.h +++ b/src/_pakfire/package.h @@ -23,12 +23,14 @@ #include +#include #include #include "pakfire.h" typedef struct { PyObject_HEAD + struct pakfire_ctx* ctx; struct pakfire_package* package; } PackageObject; diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 944a38483..deb462669 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -40,29 +40,32 @@ #include #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; diff --git a/src/_pakfire/pakfire.h b/src/_pakfire/pakfire.h index 5927e6aae..31c14fe62 100644 --- a/src/_pakfire/pakfire.h +++ b/src/_pakfire/pakfire.h @@ -27,6 +27,7 @@ typedef struct { PyObject_HEAD + struct pakfire_ctx* ctx; struct pakfire* pakfire; // Callbacks