medit/moo/moopython/moopython-loader.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;
}