#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <errno.h>
+#include <syslog.h>
#include <pakfire/archive.h>
#include <pakfire/build.h>
#include <pakfire/constants.h>
+#include <pakfire/ctx.h>
#include <pakfire/dist.h>
#include <pakfire/jail.h>
#include <pakfire/logging.h>
#include <pakfire/util.h>
#include "archive.h"
+#include "ctx.h"
#include "errors.h"
#include "key.h"
#include "pakfire.h"
static PyObject* Pakfire_new(PyTypeObject* type, PyObject* args, PyObject* kwds) {
PakfireObject* self = (PakfireObject *)type->tp_alloc(type, 0);
if (self) {
+ self->ctx = NULL;
self->pakfire = NULL;
-
- // Callbacks
- self->callbacks.log = NULL;
- self->callbacks.confirm = NULL;
}
return (PyObject *)self;
}
-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;
- PyObject* exception = NULL;
- PyObject* type = NULL;
- PyObject* value = NULL;
- PyObject* traceback = NULL;
-
- // Do nothing if callback isn't set
- if (!callback)
- return;
-
- PyGILState_STATE state = PyGILState_Ensure();
-
- // Translate priority to Python logging priorities
- switch (priority) {
- case LOG_DEBUG:
- priority = 10;
- break;
-
- case LOG_INFO:
- priority = 20;
- break;
-
- case LOG_ERR:
- priority = 40;
- break;
-
- // Drop messages of an unknown priority
- default:
- return;
- }
-
- PyObject* tuple = NULL;
- PyObject* result = NULL;
- char* buffer = NULL;
-
- // Make line
- int r = vasprintf(&buffer, format, args);
- if (r < 0)
- goto ERROR;
-
- // Build a tuple with the priority and the log message
- tuple = Py_BuildValue("(is)", priority, buffer);
- if (!tuple)
- goto ERROR;
-
- // Call the callback
- result = PyObject_CallObject(callback, tuple);
-
-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(tuple);
- Py_XDECREF(result);
-
- // Release the GIL
- PyGILState_Release(state);
-}
-
-static int Pakfire_confirm_callback(struct pakfire* pakfire, void* data,
- const char* message, const char* question) {
- PyObject* callback = (PyObject*)data;
- PyObject* result = NULL;
- int r = 0;
-
- // Do nothing if callback isn't set
- if (!callback)
- return 0;
-
- // Acquire GIL
- PyGILState_STATE state = PyGILState_Ensure();
-
- PyObject* args = Py_BuildValue("(ss)", message, question);
- if (!args) {
- r = -1;
- goto ERROR;
- }
-
- result = PyObject_CallObject(callback, args);
-
- // If the callback raised an exception, we will ignore it and indicate
- // that an error happened, but we cannot re-raise the exception
- if (!result) {
- r = -1;
- goto ERROR;
- }
-
- // Set the return code
- if (result == Py_True)
- r = 0;
- else
- r = 1;
-
-ERROR:
- Py_DECREF(args);
- Py_DECREF(result);
-
- // Release the GIL
- PyGILState_Release(state);
-
- return r;
-}
-
static int Pakfire_init(PakfireObject* self, PyObject* args, PyObject* kwds) {
char* kwlist[] = {
+ "ctx",
"path",
"arch",
- "logger",
- "offline",
"conf",
- "confirm_callback",
NULL,
};
+ CtxObject* ctx = NULL;
const char* path = NULL;
const char* arch = NULL;
PyObject* conf = Py_None;
- int offline = 0;
int r = 1;
FILE* fconf = NULL;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|zzOpOO", kwlist,
- &path, &arch, &self->callbacks.log, &offline, &conf, &self->callbacks.confirm))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|zzO", kwlist,
+ &CtxType, &ctx, &path, &arch, &conf))
goto ERROR;
- // Check if log callback is callable
- if (self->callbacks.log && !PyCallable_Check(self->callbacks.log)) {
- PyErr_SetString(PyExc_TypeError, "logger must be callable\n");
- goto ERROR;
- }
-
- // Check if confirm callback is callable
- if (self->callbacks.confirm && !PyCallable_Check(self->callbacks.confirm)) {
- PyErr_SetString(PyExc_TypeError, "Confirm callback is not callable");
- goto ERROR;
- }
-
// Map the configuration
if (conf != Py_None) {
fconf = PyObject_AsFileHandle(conf, "r");
goto ERROR;
}
- int flags = PAKFIRE_FLAGS_DEBUG;
-
- // Enable offline mode
- if (offline)
- flags |= PAKFIRE_FLAGS_OFFLINE;
-
- // Configure callbacks
- if (self->callbacks.log)
- Py_INCREF(self->callbacks.log);
+ int flags = 0;
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, path, arch, fconf, flags,
- Pakfire_log_callback, self->callbacks.log);
+ r = pakfire_create(&self->pakfire, self->ctx, path, arch, fconf, flags);
Py_END_ALLOW_THREADS
goto ERROR;
}
- // Configure confirm callback
- if (self->callbacks.confirm) {
- pakfire_set_confirm_callback(self->pakfire,
- Pakfire_confirm_callback, self->callbacks.confirm);
-
- Py_INCREF(self->callbacks.confirm);
- }
-
ERROR:
if (fconf)
fclose(fconf);
static void Pakfire_dealloc(PakfireObject* self) {
if (self->pakfire) {
- // Reset log callback
- if (self->callbacks.log) {
- pakfire_set_log_callback(self->pakfire, NULL, NULL);
- Py_DECREF(self->callbacks.log);
- }
-
- // Reset confirm callback
- if (self->callbacks.confirm) {
- pakfire_set_confirm_callback(self->pakfire, NULL, NULL);
- Py_DECREF(self->callbacks.confirm);
- }
-
Py_BEGIN_ALLOW_THREADS
pakfire_unref(self->pakfire);
Py_END_ALLOW_THREADS
}
+ if (self->ctx)
+ pakfire_ctx_unref(self->ctx);
Py_TYPE(self)->tp_free((PyObject *)self);
}
return 0;
}
+/*
+ XXX This could be moved out of here as this no longer depends on Pakfire
+*/
static PyObject* Pakfire_generate_key(PakfireObject* self, PyObject* args, PyObject* kwds) {
char* kwlist[] = { "algorithm", "comment", NULL };
struct pakfire_key* key = NULL;
return NULL;
// Generate a new key
- int r = pakfire_key_generate(&key, self->pakfire, algo, comment);
+ int r = pakfire_key_generate(&key, self->ctx, algo, comment);
if (r) {
PyErr_SetFromErrno(PyExc_OSError);
return NULL;
return object;
}
-
+/*
+ XXX This could be moved out of here as this no longer depends on Pakfire
+*/
static PyObject* Pakfire_import_key(PakfireObject* self, PyObject* args) {
struct pakfire_key* key = NULL;
PyObject* object = NULL;
return NULL;
// Import the key
- r = pakfire_key_import(&key, self->pakfire, f);
+ r = pakfire_key_import(&key, self->ctx, f);
if (r) {
PyErr_SetFromErrno(PyExc_OSError);
goto ERROR;
return NULL;
// Create a new list
- r = pakfire_packagelist_create(&list, self->pakfire);
+ r = pakfire_packagelist_create(&list, self->ctx);
if (r) {
PyErr_SetFromErrno(PyExc_OSError);
goto ERROR;
Py_BEGIN_ALLOW_THREADS
// Create a new list
- r = pakfire_packagelist_create(&list, self->pakfire);
+ r = pakfire_packagelist_create(&list, self->ctx);
if (r) {
Py_BLOCK_THREADS
PyErr_SetFromErrno(PyExc_OSError);
if (name_only)
flags |= PAKFIRE_SEARCH_NAME_ONLY;
- r = pakfire_packagelist_create(&list, self->pakfire);
+ r = pakfire_packagelist_create(&list, self->ctx);
if (r) {
PyErr_SetFromErrno(PyExc_OSError);
goto ERROR;
return PyLong_FromLong(cmp);
}
-static int Pakfire_execute_output_callback(struct pakfire* pakfire, void* data,
- int priority, const char* line, size_t length) {
+static int Pakfire_execute_output_callback(struct pakfire_ctx* ctx, struct pakfire_jail* jail,
+ void* data, const char* line, size_t length) {
PyObject* callback = (PyObject*)data;
- int r = 0;
+ PyObject* args = NULL;
+ PyObject* result = NULL;
+ int r = 1;
// Do nothing if callback isn't set
if (!callback)
return 0;
- // Translate priority to Python logging priorities
- switch (priority) {
- case LOG_INFO:
- priority = 20;
- break;
-
- case LOG_ERR:
- priority = 40;
- break;
- }
-
// Remove the trailing newline
- if (line && line[length - 1] == '\n')
+ if (line && length && line[length - 1] == '\n')
length--;
+ // Get the GIL
+ PyGILState_STATE state = PyGILState_Ensure();
+
// Create tuple with arguments for the callback function
- PyObject* args = Py_BuildValue("(is#)", priority, line, (Py_ssize_t)length);
+ args = Py_BuildValue("(is#)", LOG_INFO, line, (Py_ssize_t)length);
if (!args)
- return 1;
+ goto ERROR;
- PyObject* result = PyObject_CallObject(callback, args);
+ // Call the callback method
+ result = PyObject_CallObject(callback, args);
if (result && PyLong_Check(result)) {
r = PyLong_AsLong(result);
}
+ERROR:
Py_XDECREF(args);
Py_XDECREF(result);
+ // Release the GIL
+ PyGILState_Release(state);
+
return r;
}
if (!PyUnicode_Check(item)) {
PyErr_Format(PyExc_TypeError, "Item %u in command is not a string", i);
- return NULL;
+ goto ERROR;
}
// Copy to argv
goto ERROR;
}
- // Check callback
- if (callback && !PyCallable_Check(callback)) {
- PyErr_SetString(PyExc_TypeError, "callback must be callable\n");
- goto ERROR;
- }
-
// Set nice
if (nice) {
r = pakfire_jail_nice(jail, nice);
}
}
- const Py_ssize_t num_bind = PySequence_Length(bind);
-
// Bind
- for (unsigned int i = 0; i < num_bind; i++) {
- PyObject* b = PySequence_ITEM(bind, i);
- if (!b)
- goto ERROR;
+ if (bind && PySequence_Check(bind)) {
+ const Py_ssize_t num_bind = PySequence_Length(bind);
- // Check if this is a Unicode object
- if (!PyUnicode_Check(b)) {
- PyErr_SetString(PyExc_ValueError, "bind contains a non-Unicode object");
- Py_DECREF(b);
- goto ERROR;
- }
+ for (unsigned int i = 0; i < num_bind; i++) {
+ PyObject* b = PySequence_ITEM(bind, i);
+ if (!b)
+ goto ERROR;
- const char* path = PyUnicode_AsUTF8(b);
+ // Check if this is a Unicode object
+ if (!PyUnicode_Check(b)) {
+ PyErr_SetString(PyExc_ValueError, "bind contains a non-Unicode object");
+ Py_DECREF(b);
+ goto ERROR;
+ }
+
+ const char* path = PyUnicode_AsUTF8(b);
+
+ // Perform bind
+ r = pakfire_jail_bind(jail, path, path, 0);
+ if (r) {
+ PyErr_SetFromErrno(PyExc_OSError);
+ Py_DECREF(b);
+ goto ERROR;
+ }
- // Perform bind
- r = pakfire_jail_bind(jail, path, path, 0);
- if (r) {
- PyErr_SetFromErrno(PyExc_OSError);
Py_DECREF(b);
- goto ERROR;
}
-
- Py_DECREF(b);
}
Py_BEGIN_ALLOW_THREADS
+ // Set callback
+ pakfire_jail_set_stdout_callback(jail, Pakfire_execute_output_callback, callback);
+
// Execute command
- r = pakfire_jail_exec(jail, argv,
- NULL, Pakfire_execute_output_callback, callback, 0);
+ r = pakfire_jail_exec(jail, argv, 0);
Py_END_ALLOW_THREADS