254 lines
5.3 KiB
C
254 lines
5.3 KiB
C
|
/*
|
||
|
* moopython-loader.c
|
||
|
*
|
||
|
* Copyright (C) 2004-2006 by Yevgen Muntyan <muntyan@math.tamu.edu>
|
||
|
*
|
||
|
* This program is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* See COPYING file that comes with this distribution.
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
#include <Python.h>
|
||
|
#define NO_IMPORT_PYGOBJECT
|
||
|
#include "pygobject.h"
|
||
|
|
||
|
#include "moopython/moopython-loader.h"
|
||
|
#include "mooutils/mooutils-misc.h"
|
||
|
|
||
|
#define LIBDIR "lib"
|
||
|
|
||
|
|
||
|
static PyObject *sys_module;
|
||
|
|
||
|
|
||
|
static gboolean
|
||
|
sys_path_add_dir (const char *dir)
|
||
|
{
|
||
|
PyObject *path;
|
||
|
PyObject *s;
|
||
|
|
||
|
if (!sys_module)
|
||
|
sys_module = PyImport_ImportModule ((char*) "sys");
|
||
|
|
||
|
if (!sys_module)
|
||
|
{
|
||
|
PyErr_Print ();
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
path = PyObject_GetAttrString (sys_module, (char*) "path");
|
||
|
|
||
|
if (!path)
|
||
|
{
|
||
|
PyErr_Print ();
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (!PyList_Check (path))
|
||
|
{
|
||
|
g_critical ("sys.path is not a list");
|
||
|
Py_DECREF (path);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
s = PyString_FromString (dir);
|
||
|
PyList_Append (path, s);
|
||
|
|
||
|
Py_DECREF (s);
|
||
|
Py_DECREF (path);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
sys_path_remove_dir (const char *dir)
|
||
|
{
|
||
|
PyObject *path;
|
||
|
int i;
|
||
|
|
||
|
if (!sys_module)
|
||
|
return;
|
||
|
|
||
|
path = PyObject_GetAttrString (sys_module, (char*) "path");
|
||
|
|
||
|
if (!path || !PyList_Check (path))
|
||
|
return;
|
||
|
|
||
|
for (i = PyList_GET_SIZE (path) - 1; i >= 0; --i)
|
||
|
{
|
||
|
PyObject *item = PyList_GET_ITEM (path, i);
|
||
|
|
||
|
if (PyString_CheckExact (item) &&
|
||
|
!strcmp (PyString_AsString (item), dir))
|
||
|
{
|
||
|
if (PySequence_DelItem (path, i) != 0)
|
||
|
PyErr_Print ();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Py_DECREF (path);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
sys_path_add_plugin_dirs (void)
|
||
|
{
|
||
|
char **d;
|
||
|
char **dirs = moo_plugin_get_dirs ();
|
||
|
static gboolean been_here = FALSE;
|
||
|
|
||
|
if (been_here)
|
||
|
return;
|
||
|
|
||
|
been_here = TRUE;
|
||
|
|
||
|
for (d = dirs; d && *d; ++d)
|
||
|
{
|
||
|
char *libdir = g_build_filename (*d, LIBDIR, NULL);
|
||
|
sys_path_add_dir (libdir);
|
||
|
g_free (libdir);
|
||
|
}
|
||
|
|
||
|
g_strfreev (dirs);
|
||
|
}
|
||
|
|
||
|
|
||
|
static PyObject *
|
||
|
do_load_file (const char *path)
|
||
|
{
|
||
|
PyObject *mod = NULL;
|
||
|
PyObject *code;
|
||
|
char *modname = NULL, *content = NULL;
|
||
|
GError *error = NULL;
|
||
|
|
||
|
if (!g_file_get_contents (path, &content, NULL, &error))
|
||
|
{
|
||
|
g_warning ("could not read file '%s': %s", path, error->message);
|
||
|
g_error_free (error);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
modname = g_strdup_printf ("moo_module_%08x", g_random_int ());
|
||
|
code = Py_CompileString (content, path, Py_file_input);
|
||
|
|
||
|
if (!code)
|
||
|
{
|
||
|
PyErr_Print ();
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
mod = PyImport_ExecCodeModule (modname, code);
|
||
|
Py_DECREF (code);
|
||
|
|
||
|
if (!mod)
|
||
|
{
|
||
|
PyErr_Print ();
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
out:
|
||
|
g_free (content);
|
||
|
g_free (modname);
|
||
|
|
||
|
return mod;
|
||
|
}
|
||
|
|
||
|
|
||
|
static PyObject *
|
||
|
load_file (const char *path)
|
||
|
{
|
||
|
char *dirname;
|
||
|
gboolean dir_added;
|
||
|
PyObject *retval;
|
||
|
|
||
|
g_return_val_if_fail (path != NULL, NULL);
|
||
|
|
||
|
sys_path_add_plugin_dirs ();
|
||
|
|
||
|
dirname = g_path_get_dirname (path);
|
||
|
dir_added = sys_path_add_dir (dirname);
|
||
|
|
||
|
retval = do_load_file (path);
|
||
|
|
||
|
if (dir_added)
|
||
|
sys_path_remove_dir (dirname);
|
||
|
|
||
|
g_free (dirname);
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
load_python_module (const char *module_file,
|
||
|
G_GNUC_UNUSED const char *ini_file,
|
||
|
G_GNUC_UNUSED gpointer data)
|
||
|
{
|
||
|
Py_XDECREF (load_file (module_file));
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
load_python_plugin (const char *plugin_file,
|
||
|
const char *plugin_id,
|
||
|
MooPluginInfo *info,
|
||
|
MooPluginParams *params,
|
||
|
G_GNUC_UNUSED const char *ini_file,
|
||
|
G_GNUC_UNUSED gpointer data)
|
||
|
{
|
||
|
PyObject *mod;
|
||
|
PyObject *py_plugin_type;
|
||
|
GType plugin_type;
|
||
|
|
||
|
if (!(mod = load_file (plugin_file)))
|
||
|
return;
|
||
|
|
||
|
py_plugin_type = PyObject_GetAttrString (mod, (char*) "__plugin__");
|
||
|
|
||
|
if (!py_plugin_type)
|
||
|
{
|
||
|
g_warning ("file %s doesn't define __plugin__ attribute",
|
||
|
plugin_file);
|
||
|
}
|
||
|
else if (py_plugin_type == Py_None)
|
||
|
{
|
||
|
/* it's fine, ignore */
|
||
|
}
|
||
|
else if (!PyType_Check (py_plugin_type))
|
||
|
{
|
||
|
g_warning ("__plugin__ attribute in file %s is not a type",
|
||
|
plugin_file);
|
||
|
}
|
||
|
else if (!(plugin_type = pyg_type_from_object (py_plugin_type)))
|
||
|
{
|
||
|
g_warning ("__plugin__ attribute in file %s is not a valid type",
|
||
|
plugin_file);
|
||
|
PyErr_Clear ();
|
||
|
}
|
||
|
else if (!g_type_is_a (plugin_type, MOO_TYPE_PLUGIN))
|
||
|
{
|
||
|
g_warning ("__plugin__ attribute in file %s is not a MooPlugin subclass",
|
||
|
plugin_file);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
moo_plugin_register (plugin_id, plugin_type, info, params);
|
||
|
}
|
||
|
|
||
|
Py_XDECREF (py_plugin_type);
|
||
|
Py_XDECREF (mod);
|
||
|
}
|
||
|
|
||
|
|
||
|
MooPluginLoader *
|
||
|
_moo_python_get_plugin_loader (void)
|
||
|
{
|
||
|
MooPluginLoader *loader = g_new0 (MooPluginLoader, 1);
|
||
|
loader->load_module = load_python_module;
|
||
|
loader->load_plugin = load_python_plugin;
|
||
|
return loader;
|
||
|
}
|