diff options
26 files changed, 1241 insertions, 11 deletions
@@ -78,6 +78,7 @@ Makefile.in /tests/*/vgdump-* /tests/libpeas/engine /tests/libpeas/extension-c +/tests/libpeas/extension-lua51 /tests/libpeas/extension-python /tests/libpeas/extension-python3 /tests/libpeas/extension-set @@ -20,11 +20,11 @@ GInterfaces the plugin writer will be able to implement as his plugin requires. On-demand programming language support -------------------------------------- -libpeas comes with a set of supported languages (currently, C, Python 2 and -Python 3). Those languages are supported through “loaders” which are loaded -on demand. What it means is that you only pay for what you use: if you have no -Python plugin, the Python interpreter won't be loaded in memory. Of course, the -same goes for the C loader. +libpeas comes with a set of supported languages (currently, C, Lua 5.1, +Python 2 and Python 3). Those languages are supported through “loaders” which +are loaded on demand. What it means is that you only pay for what you use: if +you have no Python plugin, the Python interpreter won't be loaded in memory. +Of course, the same goes for the C loader. Damn simple to use (or at least we try hard) -------------------------------------------- @@ -82,7 +82,7 @@ Sample code ----------- The libpeas package contains a sample application called peas-demo, and sample -plugins written in C and Python. +plugins written in C, Lua and Python. The global idea is this one: you create a new PeasEngine instance and give it the information needed for it to find your plugins. Then you load some plugins diff --git a/configure.ac b/configure.ac index bcd3d33..1786f09 100644 --- a/configure.ac +++ b/configure.ac @@ -232,6 +232,130 @@ fi AM_CONDITIONAL([ENABLE_GLADE_CATALOG],[test "x$found_glade_catalog" = "xyes"]) dnl ================================================================ +dnl Lua +dnl ================================================================ + +LUA51_REQUIRED=5.1.0 +LUAJIT_REQUIRED=2.0 + +LGI_MAJOR_VERSION=0 +LGI_MINOR_VERSION=8 +LGI_MICRO_VERSION=0 +LGI_REQUIRED=$LGI_MAJOR_VERSION.$LGI_MINOR_VERSION.$LGI_MICRO_VERSION +AC_DEFINE_UNQUOTED(LGI_MAJOR_VERSION, [$LGI_MAJOR_VERSION], [LGI major version.]) +AC_DEFINE_UNQUOTED(LGI_MINOR_VERSION, [$LGI_MINOR_VERSION], [LGI minor version.]) +AC_DEFINE_UNQUOTED(LGI_MICRO_VERSION, [$LGI_MICRO_VERSION], [LGI micro version.]) + +dnl +dnl Test program for LGI version +dnl +m4_define([peas_lgi_version_test], [ +#include <lauxlib.h> +#include <lualib.h> + +#include "peas-plugin-loader-lua-utils.c" + +int main(int argc, char **argv) +{ + lua_State *L; + gboolean success; + + L = luaL_newstate (); + luaL_openlibs (L); + + success = (peas_lua_utils_require (L, "lgi") && + peas_lua_utils_check_version (L, + LGI_MAJOR_VERSION, + LGI_MINOR_VERSION, + LGI_MICRO_VERSION)); + + lua_close (L); + return success ? 0 : 1; +}]) + +AC_ARG_ENABLE(lua5.1, + AS_HELP_STRING([--enable-lua5.1],[Enable Lua 5.1 support]), + [enable_lua51=$enableval], + [enable_lua51=auto]) + +AC_ARG_ENABLE(luajit, + AS_HELP_STRING([--enable-luajit],[Enable LuaJIT for Lua 5.1 support]), + [enable_luajit=$enableval], + [enable_luajit=auto]) + +AC_MSG_CHECKING([for Lua 5.1 availability.]) + +if test "x$enable_lua51" = "xno"; then + found_lua51="no (disabled, use --enable-lua5.1 to enable)" + AC_MSG_RESULT([$found_lua51]) +else + if test "x$enable_luajit" != "xno"; then + PKG_CHECK_EXISTS([luajit >= $LUAJIT_REQUIRED], [ + found_lua51=yes + with_lua51=luajit + ], [ + found_lua51=no + ]) + + if test "x$enable_luajit" = "xyes" -a "x$found_lua51" = "xno"; then + AC_MSG_ERROR([You need to have LuaJIT >= $LUAJIT_REQUIRED + installed to build libpeas]) + fi + fi + + if test "x$found_lua51" != "xyes"; then + PKG_CHECK_EXISTS([lua5.1 >= $LUA51_REQUIRED], [ + found_lua51=yes + with_lua51=lua5.1 + ], [ + found_lua51=no + ]) + + if test "x$enable_lua51" = "xyes" -a "x$found_lua51" = "xno"; then + AC_MSG_ERROR([You need to have Lua 5.1 >= $LUA51_REQUIRED + installed to build libpeas]) + fi + fi + + if test "x$found_lua51" != "xyes"; then + AC_MSG_RESULT([$found_lua51]) + else + AC_MSG_RESULT([$found_lua51 ($with_lua51)]) + + LUA51_CFLAGS=`$PKG_CONFIG --cflags $with_lua51` + LUA51_LIBS=`$PKG_CONFIG --libs $with_lua51` + AC_SUBST(LUA51_CFLAGS) + AC_SUBST(LUA51_LIBS) + + AC_MSG_CHECKING(for LGI availability in Lua 5.1.) + + peas_save_CFLAGS="$CFLAGS" + peas_save_LIBS="$LIBS" + CFLAGS="$PEAS_CFLAGS $LUA51_CFLAGS -Iloaders/lua5.1" + LIBS="$PEAS_LIBS $LUA51_LIBS" + AC_TRY_RUN(peas_lgi_version_test(0), + found_lua51=yes, + found_lua51=no, + found_lua51=yes) + CFLAGS="$peas_save_CFLAGS" + LIBS="$peas_save_LIBS" + + if test "x$enable_lua51" = "xyes" -a "x$found_lua51" = "xno"; then + AC_MSG_ERROR([You need to have LGI >= $LGI_REQUIRED + installed to build libpeas]) + fi + + if test "x$found_lua51" = "xyes"; then + AC_DEFINE(ENABLE_LUA51, 1, [Define to compile with Lua support]) + fi + + AC_MSG_RESULT([$found_lua51]) + fi +fi + +AM_CONDITIONAL([ENABLE_LUA51], [test "x$found_lua51" = "xyes"]) + +dnl ================================================================ dnl Python dnl ================================================================ @@ -290,7 +414,7 @@ else fi if test "x$enable_python2" = "xyes" -a "x$found_python2" != "xyes"; then - AC_MSG_ERROR([You need to have Python 2 and PyGobject installed to build libpeas]) + AC_MSG_ERROR([You need to have Python 2 and PyGObject installed to build libpeas]) fi AC_MSG_RESULT([$found_python2]) @@ -393,6 +517,7 @@ docs/reference/version.xml libpeas/Makefile libpeas-gtk/Makefile loaders/Makefile +loaders/lua5.1/Makefile loaders/python/Makefile loaders/python3/Makefile data/Makefile @@ -403,6 +528,7 @@ data/libpeas-gtk-1.0.pc peas-demo/Makefile peas-demo/plugins/Makefile peas-demo/plugins/helloworld/Makefile +peas-demo/plugins/luahello/Makefile peas-demo/plugins/pythonhello/Makefile peas-demo/plugins/secondtime/Makefile po/Makefile.in @@ -410,6 +536,7 @@ tests/Makefile tests/libpeas/Makefile tests/libpeas/plugins/Makefile tests/libpeas/plugins/extension-c/Makefile +tests/libpeas/plugins/extension-lua/Makefile tests/libpeas/plugins/extension-python/Makefile tests/libpeas/introspection/Makefile tests/libpeas/testing/Makefile @@ -443,6 +570,7 @@ Configuration: Languages support: + Lua 5.1 support : ${found_lua51} Python 2 support : ${found_python2} Python 3 support : ${found_python3} " diff --git a/libpeas/peas-engine.c b/libpeas/peas-engine.c index 249b357..c6b7043 100644 --- a/libpeas/peas-engine.c +++ b/libpeas/peas-engine.c @@ -589,6 +589,7 @@ static PeasPluginLoader * get_plugin_loader (PeasEngine *engine, gint loader_id) { + gint i, j; LoaderInfo *loader_info; const gchar *loader_name; gchar *module_name, *module_dir; @@ -615,6 +616,15 @@ get_plugin_loader (PeasEngine *engine, module_name = g_strconcat (loader_name, "loader", NULL); module_dir = peas_dirs_get_plugin_loaders_dir (); + /* Remove '.'s from the module name */ + for (i = 0, j = 0; module_name[i] != '\0'; ++i) + { + if (module_name[i] != '.') + module_name[j++] = module_name[i]; + } + + module_name[j] = '\0'; + loader_info->module = load_module (module_name, module_dir); if (loader_info->module == NULL) @@ -667,7 +677,7 @@ get_plugin_loader (PeasEngine *engine, * * Enable a loader, enables a loader for plugins. * The C plugin loader is always enabled. The other plugin - * loaders are: python and python3. + * loaders are: lua5.1 and python and python3. * * For instance, the following code will enable python plugins * to be loaded: diff --git a/libpeas/peas-utils.c b/libpeas/peas-utils.c index 21668f8..a2adb52 100644 --- a/libpeas/peas-utils.c +++ b/libpeas/peas-utils.c @@ -29,7 +29,8 @@ #include "peas-utils.h" -static const gchar *all_plugin_loaders[] = {"c", "python", "python3"}; +static const gchar *all_plugin_loaders[] = {"c", "lua5.1", + "python", "python3"}; G_STATIC_ASSERT (G_N_ELEMENTS (all_plugin_loaders) == PEAS_UTILS_N_LOADERS); static void diff --git a/libpeas/peas-utils.h b/libpeas/peas-utils.h index e7f55de..024d369 100644 --- a/libpeas/peas-utils.h +++ b/libpeas/peas-utils.h @@ -24,7 +24,7 @@ #include <glib-object.h> -#define PEAS_UTILS_N_LOADERS 3 +#define PEAS_UTILS_N_LOADERS 4 gboolean peas_utils_valist_to_parameter_list (GType iface_type, const gchar *first_property, diff --git a/loaders/Makefile.am b/loaders/Makefile.am index 5868750..c7c050b 100644 --- a/loaders/Makefile.am +++ b/loaders/Makefile.am @@ -1,5 +1,9 @@ SUBDIRS = +if ENABLE_LUA51 +SUBDIRS += lua5.1 +endif + if ENABLE_PYTHON2 SUBDIRS += python endif diff --git a/loaders/lua5.1/Makefile.am b/loaders/lua5.1/Makefile.am new file mode 100644 index 0000000..c49aa76 --- /dev/null +++ b/loaders/lua5.1/Makefile.am @@ -0,0 +1,31 @@ +# Lua 5.1 plugin loader + +loaderdir = $(libdir)/libpeas-1.0/loaders + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + $(PEAS_CFLAGS) \ + $(GCOV_CFLAGS) \ + $(WARN_CFLAGS) \ + $(DISABLE_DEPRECATED) \ + $(LUA51_CFLAGS) + +loader_LTLIBRARIES = liblua51loader.la + +liblua51loader_la_SOURCES = \ + peas-plugin-loader-lua.c \ + peas-plugin-loader-lua.h \ + peas-plugin-loader-lua-utils.c \ + peas-plugin-loader-lua-utils.h + +liblua51loader_la_LDFLAGS = \ + $(LOADER_LIBTOOL_FLAGS) \ + $(GCOV_LDFLAGS) + +liblua51loader_la_LIBADD = \ + $(top_builddir)/libpeas/libpeas-1.0.la \ + $(PEAS_LIBS) \ + $(LUA51_LIBS) + +gcov_sources = $(liblua51loader_la_SOURCES) +include $(top_srcdir)/Makefile.gcov diff --git a/loaders/lua5.1/peas-plugin-loader-lua-utils.c b/loaders/lua5.1/peas-plugin-loader-lua-utils.c new file mode 100644 index 0000000..fb043fb --- /dev/null +++ b/loaders/lua5.1/peas-plugin-loader-lua-utils.c @@ -0,0 +1,122 @@ +/* + * peas-plugin-loader-lua-utils.c + * This file is part of libpeas + * + * Copyright (C) 2014 - Garrett Regier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "peas-plugin-loader-lua-utils.h" + +#include <string.h> + +#include <lauxlib.h> +#include <lualib.h> + + +gboolean +peas_lua_utils_require (lua_State *L, + const gchar *name) +{ + luaL_checkstack (L, 2, ""); + + lua_getglobal (L, "require"); + lua_pushstring (L, name); + + if (lua_pcall (L, 1, 1, 0) != 0) + { + g_warning ("Error failed to load Lua module '%s': %s", + name, lua_tostring (L, -1)); + + /* Pop error */ + lua_pop (L, 1); + return FALSE; + } + + if (!lua_istable (L, -1)) + { + g_warning ("Error invalid Lua module for '%s': " + "expected table, got: %s", + name, lua_tostring (L, -1)); + + /* Pop the module's table */ + lua_pop (L, 1); + return FALSE; + } + + return TRUE; +} + +gboolean +peas_lua_utils_check_version (lua_State *L, + guint req_major, + guint req_minor, + guint req_micro) +{ + const gchar *version_str; + gchar **version_str_parts; + gint n_version_parts; + gint *version_parts; + gint i; + gboolean success = FALSE; + + lua_getfield (L, -1, "_VERSION"); + version_str = lua_tostring (L, -1); + + version_str_parts = g_strsplit (version_str, ".", 0); + + n_version_parts = g_strv_length (version_str_parts); + version_parts = g_newa (gint, n_version_parts); + + for (i = 0; i < n_version_parts; ++i) + { + gchar *end; + + version_parts[i] = g_ascii_strtoll (version_str_parts[i], &end, 10); + + if (*end != '\0' || + version_parts[i] < 0 || + version_parts[i] == G_MAXINT64) + { + g_warning ("Invalid version string: %s", version_str); + goto error; + } + } + + if (n_version_parts < 3 || + version_parts[0] != req_major || + version_parts[1] < req_minor || + (version_parts[1] == req_minor && version_parts[2] < req_micro)) + { + g_warning ("Version mismatch %d.%d.%d is required, found %s", + req_major, req_minor, req_micro, version_str); + goto error; + } + + success = TRUE; + +error: + + /* Pop _VERSION */ + lua_pop (L, 1); + + g_strfreev (version_str_parts); + return success; +} diff --git a/loaders/lua5.1/peas-plugin-loader-lua-utils.h b/loaders/lua5.1/peas-plugin-loader-lua-utils.h new file mode 100644 index 0000000..dafe94f --- /dev/null +++ b/loaders/lua5.1/peas-plugin-loader-lua-utils.h @@ -0,0 +1,42 @@ +/* + * peas-plugin-loader-lua-utils.h + * This file is part of libpeas + * + * Copyright (C) 2014 - Garrett Regier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __PEAS_PLUGIN_LOADER_LUA_UTILS_H__ +#define __PEAS_PLUGIN_LOADER_LUA_UTILS_H__ + +#include <glib.h> +#include <lua.h> + +G_BEGIN_DECLS + + +gboolean peas_lua_utils_require (lua_State *L, + const gchar *name); + +gboolean peas_lua_utils_check_version (lua_State *L, + guint req_major, + guint req_minor, + guint req_micro); + +G_END_DECLS + +#endif /* __PEAS_PLUGIN_LOADER_LUA_UTILS_H__ */ + diff --git a/loaders/lua5.1/peas-plugin-loader-lua.c b/loaders/lua5.1/peas-plugin-loader-lua.c new file mode 100644 index 0000000..ccc0ad0 --- /dev/null +++ b/loaders/lua5.1/peas-plugin-loader-lua.c @@ -0,0 +1,404 @@ +/* + * peas-plugin-loader-lua.c + * This file is part of libpeas + * + * Copyright (C) 2014 - Garrett Regier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "peas-plugin-loader-lua.h" + +#include <string.h> + +#include <lua.h> +#include <lauxlib.h> +#include <lualib.h> + +#include "peas-plugin-loader-lua-utils.h" + + +struct _PeasPluginLoaderLuaPrivate { + lua_State *L; +}; + +G_DEFINE_TYPE (PeasPluginLoaderLua, peas_plugin_loader_lua, PEAS_TYPE_PLUGIN_LOADER) + +G_MODULE_EXPORT void +peas_register_types (PeasObjectModule *module) +{ + peas_object_module_register_extension_type (module, + PEAS_TYPE_PLUGIN_LOADER, + PEAS_TYPE_PLUGIN_LOADER_LUA); +} + +static gboolean +_lua_add_package_path (lua_State *L, + const gchar *package_path) +{ + luaL_checkstack (L, 3, ""); + + lua_getglobal (L, "package"); + lua_getfield (L, -1, "path"); + + if (!lua_isstring (L, -1)) + { + g_warning ("Invalid Lua package.path: %s", lua_tostring (L, -1)); + + /* Pop path and package */ + lua_pop (L, 2); + return FALSE; + } + + /* ";package_path/?.lua;package_path/?/init.lua" */ + lua_pushliteral (L, ";"); + lua_pushstring (L, package_path); + lua_pushliteral (L, G_DIR_SEPARATOR_S "?.lua;"); + lua_pushstring (L, package_path); + lua_pushliteral (L, G_DIR_SEPARATOR_S "?" G_DIR_SEPARATOR_S "init.lua"); + lua_concat (L, 5); + + if (strstr (lua_tostring (L, -2), lua_tostring (L, -1)) != NULL) + { + /* Pop new path and path */ + lua_pop (L, 2); + } + else + { + /* Update package.path */ + lua_concat (L, 2); + lua_setfield (L, -2, "path"); + } + + /* Pop package */ + lua_pop (L, 1); + return TRUE; +} + +static gboolean +_lua_pushinstance (lua_State *L, + const gchar *namespace_, + const gchar *name, + GType gtype, + gpointer instance) +{ + luaL_checkstack (L, 3, ""); + + if (!peas_lua_utils_require (L, "lgi")) + return FALSE; + + lua_getfield (L, -1, namespace_); + lua_getfield (L, -1, name); + + /* Remove the namespace and lgi's module table */ + lua_replace (L, -2); + lua_replace (L, -2); + + lua_pushlightuserdata (L, instance); + lua_pushboolean (L, FALSE); + + /* new(addr[, already_own[, no_sink]]) */ + if (lua_pcall (L, 2, 1, 0) != 0) + { + g_warning ("Failed to create Lua object of type '%s': %s", + g_type_name (gtype), lua_tostring (L, -1)); + + /* Pop the error */ + lua_pop (L, 1); + return FALSE; + } + + /* Check that the Lua object was created correctly */ + lua_getfield (L, -1, "_native"); + g_assert (lua_islightuserdata (L, -1)); + g_assert (lua_touserdata (L, -1) == instance); + lua_pop (L, 1); + + return TRUE; +} + +static GType +_lua_get_gtype (lua_State *L, + int index) +{ + GType gtype = G_TYPE_INVALID; + + luaL_checkstack (L, 1, ""); + + lua_getfield (L, index, "_gtype"); + + if (lua_type (L, -1) == LUA_TLIGHTUSERDATA) + gtype = (GType) lua_touserdata (L, -1); + + /* Pop _gtype */ + lua_pop (L, 1); + return gtype; +} + +static GType +_lua_find_extension_type (lua_State *L, + PeasPluginInfo *info, + GType exten_type) +{ + GType found_type = G_TYPE_INVALID; + + luaL_checkstack (L, 3, ""); + + /* Get the module's table */ + lua_pushlightuserdata (L, info); + lua_rawget (L, LUA_REGISTRYINDEX); + + /* Must always have a valid key */ + lua_pushnil (L); + while (lua_next (L, -2) != 0 && found_type == G_TYPE_INVALID) + { + if (lua_istable (L, -1)) + { + found_type = _lua_get_gtype (L, -1); + + if (found_type != G_TYPE_INVALID && + !g_type_is_a (found_type, exten_type)) + { + found_type = G_TYPE_INVALID; + } + } + + /* Pop the value but keep the key for the next iteration */ + lua_pop (L, 1); + } + + /* Pop the module's table */ + lua_pop (L, 1); + return found_type; +} + +static gboolean +peas_plugin_loader_lua_provides_extension (PeasPluginLoader *loader, + PeasPluginInfo *info, + GType exten_type) +{ + PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader); + lua_State *L = lua_loader->priv->L; + GType extension_type; + + extension_type = _lua_find_extension_type (L, info, exten_type); + + return extension_type != G_TYPE_INVALID; +} + +static PeasExtension * +peas_plugin_loader_lua_create_extension (PeasPluginLoader *loader, + PeasPluginInfo *info, + GType exten_type, + guint n_parameters, + GParameter *parameters) +{ + PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader); + lua_State *L = lua_loader->priv->L; + GType the_type; + GObject *object; + + the_type = _lua_find_extension_type (L, info, exten_type); + if (the_type == G_TYPE_INVALID) + return NULL; + + if (!g_type_is_a (the_type, exten_type)) + { + g_warn_if_fail (g_type_is_a (the_type, exten_type)); + return NULL; + } + + object = g_object_newv (the_type, n_parameters, parameters); + if (object == NULL) + return NULL; + + /* As we do not instantiate a PeasExtensionWrapper, we have to remember + * somehow which interface we are instantiating, to make it possible to use + * the deprecated peas_extension_get_extension_type() method. + */ + g_object_set_data (object, "peas-extension-type", + GUINT_TO_POINTER (exten_type)); + + luaL_checkstack (L, 3, ""); + + if (!_lua_pushinstance (L, "GObject", "Object", the_type, object)) + { + g_clear_object (&object); + return NULL; + } + + lua_getfield (L, -1, "priv"); + + if (!_lua_pushinstance (L, "Peas", "PluginInfo", + PEAS_TYPE_PLUGIN_INFO, info)) + { + g_clear_object (&object); + } + else + { + /* Set the plugin info as self.priv.plugin_info */ + lua_setfield (L, -2, "plugin_info"); + } + + /* Pop priv and object */ + lua_pop (L, 2); + + return object; +} + +static gboolean +peas_plugin_loader_lua_load (PeasPluginLoader *loader, + PeasPluginInfo *info) +{ + PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader); + lua_State *L = lua_loader->priv->L; + gboolean success; + + luaL_checkstack (L, 2, ""); + + /* Get the module's table */ + lua_pushlightuserdata (L, info); + lua_rawget (L, LUA_REGISTRYINDEX); + + if (!lua_isnil (L, -1)) + { + success = lua_istable (L, -1); + } + else + { + const gchar *module_dir, *module_name; + + module_dir = peas_plugin_info_get_module_dir (info); + module_name = peas_plugin_info_get_module_name (info); + + /* Must push the key back onto the stack */ + lua_pushlightuserdata (L, info); + + if (!_lua_add_package_path (L, module_dir) || + !peas_lua_utils_require (L, module_name)) + { + /* Push something that isn't a table */ + lua_pushboolean (L, FALSE); + } + + success = lua_istable (L, -1); + lua_rawset (L, LUA_REGISTRYINDEX); + } + + /* Pop the module's table */ + lua_pop (L, 1); + + return success; +} + +static void +peas_plugin_loader_lua_unload (PeasPluginLoader *loader, + PeasPluginInfo *info) +{ + /* Lua always keeps a reference anyways */ +} + +static void +peas_plugin_loader_lua_garbage_collect (PeasPluginLoader *loader) +{ + PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader); + + lua_gc (lua_loader->priv->L, LUA_GCCOLLECT, 0); +} + +static int +atpanic_handler (lua_State *L) +{ + G_BREAKPOINT (); + return 0; +} + +static gboolean +peas_plugin_loader_lua_initialize (PeasPluginLoader *loader) +{ + PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader); + lua_State *L; + + L = luaL_newstate (); + if (L == NULL) + { + g_critical ("Failed to allocate lua_State"); + return FALSE; + } + + luaL_openlibs (L); + + if (!peas_lua_utils_require (L, "lgi") || + !peas_lua_utils_check_version (L, + LGI_MAJOR_VERSION, + LGI_MINOR_VERSION, + LGI_MICRO_VERSION)) + { + /* Already warned */ + lua_close (L); + return FALSE; + } + + /* Pop lgi's module table */ + lua_pop (L, 1); + + if (g_getenv ("PEAS_LUA_DEBUG") != NULL) + { + lua_atpanic (L, atpanic_handler); + } + + lua_loader->priv->L = L; + return TRUE; +} + +static void +peas_plugin_loader_lua_init (PeasPluginLoaderLua *lua_loader) +{ + lua_loader->priv = G_TYPE_INSTANCE_GET_PRIVATE (lua_loader, + PEAS_TYPE_PLUGIN_LOADER_LUA, + PeasPluginLoaderLuaPrivate); +} + +static void +peas_plugin_loader_lua_finalize (GObject *object) +{ + PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (object); + + g_clear_pointer (&lua_loader->priv->L, (GDestroyNotify) lua_close); + + G_OBJECT_CLASS (peas_plugin_loader_lua_parent_class)->finalize (object); +} + +static void +peas_plugin_loader_lua_class_init (PeasPluginLoaderLuaClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + PeasPluginLoaderClass *loader_class = PEAS_PLUGIN_LOADER_CLASS (klass); + + object_class->finalize = peas_plugin_loader_lua_finalize; + + loader_class->initialize = peas_plugin_loader_lua_initialize; + loader_class->load = peas_plugin_loader_lua_load; + loader_class->unload = peas_plugin_loader_lua_unload; + loader_class->create_extension = peas_plugin_loader_lua_create_extension; + loader_class->provides_extension = peas_plugin_loader_lua_provides_extension; + loader_class->garbage_collect = peas_plugin_loader_lua_garbage_collect; + + g_type_class_add_private (object_class, sizeof (PeasPluginLoaderLuaPrivate)); +} diff --git a/loaders/lua5.1/peas-plugin-loader-lua.h b/loaders/lua5.1/peas-plugin-loader-lua.h new file mode 100644 index 0000000..efb64a1 --- /dev/null +++ b/loaders/lua5.1/peas-plugin-loader-lua.h @@ -0,0 +1,60 @@ +/* + * peas-plugin-loader-lua.h + * This file is part of libpeas + * + * Copyright (C) 2014 - Garrett Regier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __PEAS_PLUGIN_LOADER_LUA_H__ +#define __PEAS_PLUGIN_LOADER_LUA_H__ + +#include <libpeas/peas-plugin-loader.h> +#include <libpeas/peas-object-module.h> + +G_BEGIN_DECLS + +#define PEAS_TYPE_PLUGIN_LOADER_LUA (peas_plugin_loader_lua_get_type ()) +#define PEAS_PLUGIN_LOADER_LUA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PEAS_TYPE_PLUGIN_LOADER_LUA, PeasPluginLoaderLua)) +#define PEAS_PLUGIN_LOADER_LUA_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PEAS_TYPE_PLUGIN_LOADER_LUA, PeasPluginLoaderLua const)) +#define PEAS_PLUGIN_LOADER_LUA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PEAS_TYPE_PLUGIN_LOADER_LUA, PeasPluginLoaderLuaClass)) +#define PEAS_IS_PLUGIN_LOADER_LUA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PEAS_TYPE_PLUGIN_LOADER_LUA)) +#define PEAS_IS_PLUGIN_LOADER_LUA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PEAS_TYPE_PLUGIN_LOADER_LUA)) +#define PEAS_PLUGIN_LOADER_LUA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PEAS_TYPE_PLUGIN_LOADER_LUA, PeasPluginLoaderLuaClass)) + +typedef struct _PeasPluginLoaderLua PeasPluginLoaderLua; +typedef struct _PeasPluginLoaderLuaClass PeasPluginLoaderLuaClass; +typedef struct _PeasPluginLoaderLuaPrivate PeasPluginLoaderLuaPrivate; + +struct _PeasPluginLoaderLua { + PeasPluginLoader parent; + + PeasPluginLoaderLuaPrivate *priv; +}; + +struct _PeasPluginLoaderLuaClass { + PeasPluginLoaderClass parent_class; +}; + +GType peas_plugin_loader_lua_get_type (void) G_GNUC_CONST; + +/* All the loaders must implement this function */ +G_MODULE_EXPORT void peas_register_types (PeasObjectModule *module); + +G_END_DECLS + +#endif /* __PEAS_PLUGIN_LOADER_LUA_H__ */ + diff --git a/peas-demo/peas-demo.c b/peas-demo/peas-demo.c index b1154f7..6a91eaf 100644 --- a/peas-demo/peas-demo.c +++ b/peas-demo/peas-demo.c @@ -128,6 +128,7 @@ main (int argc, /* We don't care about leaking memory */ g_setenv ("PEAS_ALLOW_ALL_LOADERS", "1", TRUE); + peas_engine_enable_loader (engine, "lua5.1"); peas_engine_enable_loader (engine, "python3"); if (run_from_build_dir) diff --git a/peas-demo/plugins/Makefile.am b/peas-demo/plugins/Makefile.am index 273b32b..3c5d222 100644 --- a/peas-demo/plugins/Makefile.am +++ b/peas-demo/plugins/Makefile.am @@ -1,5 +1,9 @@ SUBDIRS = helloworld secondtime +if ENABLE_LUA51 +SUBDIRS += luahello +endif + if ENABLE_PYTHON3 SUBDIRS += pythonhello endif diff --git a/peas-demo/plugins/luahello/Makefile.am b/peas-demo/plugins/luahello/Makefile.am new file mode 100644 index 0000000..e6aef72 --- /dev/null +++ b/peas-demo/plugins/luahello/Makefile.am @@ -0,0 +1,8 @@ +plugindir = $(libdir)/peas-demo/plugins/luahello + +plugin_lua = \ + luahello.py + +plugin_DATA = luahello.plugin + +EXTRA_DIST = $(plugin_DATA) diff --git a/peas-demo/plugins/luahello/luahello.lua b/peas-demo/plugins/luahello/luahello.lua new file mode 100644 index 0000000..8d50bc9 --- /dev/null +++ b/peas-demo/plugins/luahello/luahello.lua @@ -0,0 +1,50 @@ +local lgi = require 'lgi' + +local GObject = lgi.GObject +local Gtk = lgi.Gtk +local Peas = lgi.Peas +local PeasGtk = lgi.PeasGtk + + +LuaHelloPlugin = GObject.Object:derive('LuaHelloPlugin', { + Peas.Activatable +}) + +LuaHelloPlugin._property.object = + GObject.ParamSpecObject('object', 'object', 'object', + GObject.Object._gtype, + { GObject.ParamFlags.READABLE, + GObject.ParamFlags.WRITABLE }) + +function LuaHelloPlugin:do_activate() + window = self.priv.object + print('LuaHelloPlugin:do_activate', tostring(window)) + self.priv.label = Gtk.Label.new('Lua Says Hello!') + self.priv.label:show() + window:get_child():pack_start(self.priv.label, true, true, 0) +end + +function LuaHelloPlugin:do_deactivate() + window = self.priv.object + print('LuaHelloPlugin:do_deactivate', tostring(window)) + window:get_child():remove(self.priv.label) + self.priv.label:destroy() +end + +function LuaHelloPlugin:do_update_state() + window = self.priv.object + print('LuaHelloPlugin:do_update_state', tostring(window)) +end + + +LuaHelloConfigurable = GObject.Object:derive('LuaHelloConfigurable', { + PeasGtk.Configurable +}) + +function LuaHelloConfigurable:do_create_configure_widget() + return Gtk.Label.new('Lua Hello configure widget') +end + +return { LuaHelloPlugin, LuaHelloConfigurable } + +-- ex:set ts=4 et sw=4 ai: diff --git a/peas-demo/plugins/luahello/luahello.plugin b/peas-demo/plugins/luahello/luahello.plugin new file mode 100644 index 0000000..dddfe21 --- /dev/null +++ b/peas-demo/plugins/luahello/luahello.plugin @@ -0,0 +1,7 @@ +[Plugin] +Module=luahello +Loader=lua5.1 +Name=Lua Says Hello +Description=Inserts a box containing "Lua Says Hello" in every windows. +Authors=Garrett Regier <garrettregier@gmail.com> +Copyright=Copyright © 2014 Garrett Regier diff --git a/tests/libpeas/Makefile.am b/tests/libpeas/Makefile.am index 0015ff0..6d6696f 100644 --- a/tests/libpeas/Makefile.am +++ b/tests/libpeas/Makefile.am @@ -25,6 +25,13 @@ TEST_PROGS += \ extension-set \ plugin-info +if ENABLE_LUA51 +TEST_PROGS += extension-lua51 +extension_lua51_SOURCES = extension-lua.c +extension_lua51_CFLAGS = $(LUA51_CFLAGS) +extension_lua51_LDADD = $(LDADD) $(LUA51_LIBS) +endif + if ENABLE_PYTHON2 TEST_PROGS += extension-python extension_python_SOURCES = extension-py.c diff --git a/tests/libpeas/extension-lua.c b/tests/libpeas/extension-lua.c new file mode 100644 index 0000000..6cfd97a --- /dev/null +++ b/tests/libpeas/extension-lua.c @@ -0,0 +1,213 @@ +/* + * extension-lua.c + * This file is part of libpeas + * + * Copyright (C) 2014 - Garrett Regier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <lua.h> +#include <lauxlib.h> + +#include <libpeas/peas-activatable.h> +#include "libpeas/peas-engine-priv.h" + +#include "testing/testing-extension.h" +#include "introspection/introspection-base.h" + + +/* We must stop and start the garbage collector + * when testing reference counts otherwise issues + * will occur if the garbage collector runs preemptively. + */ +static void +set_garbage_collector_state (PeasEngine *engine, + PeasPluginInfo *info, + gboolean running) +{ + PeasExtension *extension; + + extension = peas_engine_create_extension (engine, info, + PEAS_TYPE_ACTIVATABLE, + NULL); + + if (running) + { + /* collectgarbage('restart') */ + peas_activatable_activate (PEAS_ACTIVATABLE (extension)); + } + else + { + /* collectgarbage('stop') */ + peas_activatable_deactivate (PEAS_ACTIVATABLE (extension)); + } + + g_object_unref (extension); +} + +static void +test_extension_lua_instance_refcount (PeasEngine *engine, + PeasPluginInfo *info) +{ + PeasExtension *extension; + + set_garbage_collector_state (engine, info, FALSE); + + extension = peas_engine_create_extension (engine, info, + PEAS_TYPE_ACTIVATABLE, + NULL); + g_object_add_weak_pointer (extension, (gpointer *) &extension); + + g_assert (PEAS_IS_EXTENSION (extension)); + + /* The Lua wrapper created around the extension + * object should have increased its refcount by 1. + */ + g_assert_cmpint (extension->ref_count, ==, 2); + + /* The Lua wrapper around the extension has been garbage collected */ + peas_engine_garbage_collect (engine); + g_assert_cmpint (G_OBJECT (extension)->ref_count, ==, 1); + + /* Create a new Lua wrapper around the extension */ + peas_activatable_update_state (PEAS_ACTIVATABLE (extension)); + g_assert_cmpint (G_OBJECT (extension)->ref_count, ==, 2); + + /* The Lua wrapper still exists */ + g_object_unref (extension); + g_assert_cmpint (extension->ref_count, ==, 1); + + /* The Lua wrapper around the extension has been garbage collected */ + peas_engine_garbage_collect (engine); + g_assert (extension == NULL); + + set_garbage_collector_state (engine, info, TRUE); +} + +static void +test_extension_lua_activatable_subject_refcount (PeasEngine *engine, + PeasPluginInfo *info) +{ + PeasExtension *extension; + GObject *object; + + set_garbage_collector_state (engine, info, FALSE); + + /* Create the 'object' property value, to be similar to a GtkWindow + * instance: a sunk GInitiallyUnowned object. + */ + object = g_object_new (G_TYPE_INITIALLY_UNOWNED, NULL); + g_object_add_weak_pointer (object, (gpointer *) &object); + g_object_ref_sink (object); + g_assert_cmpint (object->ref_count, ==, 1); + + /* We pre-create the wrapper to make it easier to check reference count */ + extension = peas_engine_create_extension (engine, info, + PEAS_TYPE_ACTIVATABLE, + "object", object, + NULL); + g_object_add_weak_pointer (extension, (gpointer *) &extension); + + g_assert (PEAS_IS_EXTENSION (extension)); + + /* The Lua wrapper created around our dummy + * object should have increased its refcount by 1. + */ + peas_engine_garbage_collect (engine); + g_assert_cmpint (object->ref_count, ==, 2); + + g_object_unref (extension); + g_assert (extension == NULL); + + /* We unreffed the extension, so it should have been + * destroyed and our dummy object's refcount should be back to 1. + */ + peas_engine_garbage_collect (engine); + g_assert_cmpint (object->ref_count, ==, 1); + + g_object_unref (object); + g_assert (object == NULL); + + set_garbage_collector_state (engine, info, TRUE); +} + +#if GLIB_CHECK_VERSION (2, 38, 0) +static void +test_extension_lua_nonexistent (void) +{ + g_test_trap_subprocess (EXTENSION_TEST_NAME (lua5.1, + "nonexistent/subprocess"), + 0, G_TEST_SUBPROCESS_INHERIT_STDERR); + g_test_trap_assert_passed (); + g_test_trap_assert_stderr (""); +} + +static void +test_extension_lua_nonexistent_subprocess (PeasEngine *engine) +{ + PeasPluginInfo *info; + + testing_util_push_log_hook ("Error failed to load Lua module " + "'extension-lua51-nonexistent'*"); + testing_util_push_log_hook ("Error loading plugin " + "'extension-lua51-nonexistent'"); + + info = peas_engine_get_plugin_info (engine, "extension-lua51-nonexistent"); + + g_assert (!peas_engine_load_plugin (engine, info)); +} +#endif + +int +main (int argc, + char *argv[]) +{ + testing_init (&argc, &argv); + + /* Only test the basics */ + testing_extension_basic ("lua5.1"); + + /* We still need to add the callable tests + * because of peas_extension_call() + */ + testing_extension_callable ("lua5.1"); + +#undef EXTENSION_TEST +#undef EXTENSION_TEST_FUNC + +#define EXTENSION_TEST(loader, path, func) \ + testing_extension_add (EXTENSION_TEST_NAME (loader, path), \ + (gpointer) test_extension_lua_##func) + +#define EXTENSION_TEST_FUNC(loader, path, func) \ + g_test_add_func (EXTENSION_TEST_NAME (loader, path), \ + (gpointer) test_extension_lua_##func) + + EXTENSION_TEST (lua5.1, "instance-refcount", instance_refcount); + EXTENSION_TEST (lua5.1, "activatable-subject-refcount", + activatable_subject_refcount); + +#if GLIB_CHECK_VERSION (2, 38, 0) + EXTENSION_TEST_FUNC (lua5.1, "nonexistent", nonexistent); + EXTENSION_TEST (lua5.1, "nonexistent/subprocess", nonexistent_subprocess); +#endif + + return testing_extension_run_tests (); +} diff --git a/tests/libpeas/plugins/Makefile.am b/tests/libpeas/plugins/Makefile.am index db49e17..2dfddb2 100644 --- a/tests/libpeas/plugins/Makefile.am +++ b/tests/libpeas/plugins/Makefile.am @@ -2,6 +2,10 @@ include $(top_srcdir)/tests/Makefile.plugin SUBDIRS = extension-c +if ENABLE_LUA51 +SUBDIRS += extension-lua +endif + if ENABLE_PYTHON3 SUBDIRS += extension-python else @@ -12,6 +16,7 @@ endif noinst_PLUGIN = \ extension-c-nonexistent.plugin \ + extension-lua51-nonexistent.plugin \ extension-python-nonexistent.plugin \ extension-python3-nonexistent.plugin \ info-missing-module.plugin \ diff --git a/tests/libpeas/plugins/extension-lua/Makefile.am b/tests/libpeas/plugins/extension-lua/Makefile.am new file mode 100644 index 0000000..722ba7e --- /dev/null +++ b/tests/libpeas/plugins/extension-lua/Makefile.am @@ -0,0 +1,7 @@ +include $(top_srcdir)/tests/Makefile.plugin + +noinst_DATA = \ + extension-lua51.gschema.xml \ + extension-lua51.plugin \ + extension-lua51.lua + diff --git a/tests/libpeas/plugins/extension-lua/extension-lua51.gschema.xml b/tests/libpeas/plugins/extension-lua/extension-lua51.gschema.xml new file mode 100644 index 0000000..d6e9a76 --- /dev/null +++ b/tests/libpeas/plugins/extension-lua/extension-lua51.gschema.xml @@ -0,0 +1,9 @@ +<schemalist> + <schema id="extension-lua51" path="/org/gnome/libpeas/tests/extension-lua51/"> + <key name="a-setting" type="s"> + <default>'Blah'</default> + <summary>Just a setting.</summary> + <description>Just a setting.</description> + </key> + </schema> +</schemalist> diff --git a/tests/libpeas/plugins/extension-lua/extension-lua51.lua b/tests/libpeas/plugins/extension-lua/extension-lua51.lua new file mode 100644 index 0000000..3bb6acf --- /dev/null +++ b/tests/libpeas/plugins/extension-lua/extension-lua51.lua @@ -0,0 +1,91 @@ +local lgi = require 'lgi' + +local GObject = lgi.GObject +local Introspection = lgi.Introspection +local Peas = lgi.Peas + + +local ExtensionLuaPlugin = GObject.Object:derive('ExtensionLuaPlugin', { + Peas.Activatable, + Introspection.Base, + Introspection.Callable, + Introspection.HasPrerequisite, + Introspection.PropertiesPrerequisite, + Introspection.Properties +}) + +ExtensionLuaPlugin._property.object = + GObject.ParamSpecObject('object', 'object', 'object', + GObject.Object._gtype, + { GObject.ParamFlags.READABLE, + GObject.ParamFlags.WRITABLE }) + +ExtensionLuaPlugin._property.construct_only = + GObject.ParamSpecString('construct-only', 'construct-only', + 'construct-only', + '', + { GObject.ParamFlags.CONSTRUCT_ONLY, + GObject.ParamFlags.READABLE, + GObject.ParamFlags.WRITABLE }) + +ExtensionLuaPlugin._property.read_only = + GObject.ParamSpecString('read-only', 'read-only', 'read-only', + '', + { GObject.ParamFlags.READABLE }) + +ExtensionLuaPlugin._property.write_only = + GObject.ParamSpecString('write-only', 'write-only', 'write-only', + '', + { GObject.ParamFlags.WRITABLE }) + +ExtensionLuaPlugin._property.readwrite = + GObject.ParamSpecString('readwrite', 'readwrite', 'readwrite', + '', + { GObject.ParamFlags.READABLE, + GObject.ParamFlags.WRITABLE }) + +ExtensionLuaPlugin._property.prerequisite = + GObject.ParamSpecString('prerequisite', 'prerequisite', 'prerequisite', + '', + { GObject.ParamFlags.CONSTRUCT_ONLY, + GObject.ParamFlags.READABLE, + GObject.ParamFlags.WRITABLE }) + +function ExtensionLuaPlugin:do_activate() + collectgarbage('restart') +end + +function ExtensionLuaPlugin:do_deactivate() + collectgarbage('stop') +end + +function ExtensionLuaPlugin:do_update_state() +end + +function ExtensionLuaPlugin:do_get_plugin_info() + return self.priv.plugin_info +end + +function ExtensionLuaPlugin:do_get_settings() + return self.priv.plugin_info:get_settings(nil) +end + +function ExtensionLuaPlugin:do_call_no_args() +end + +function ExtensionLuaPlugin:do_call_with_return() + return 'Hello, World!' +end + +function ExtensionLuaPlugin:do_call_single_arg() + return true +end + +function ExtensionLuaPlugin:do_call_multi_args(in_, inout) + return inout, in_ +end + +ExtensionLuaPlugin() +return { ExtensionLuaPlugin } + +-- ex:set ts=4 et sw=4 ai: diff --git a/tests/libpeas/plugins/extension-lua/extension-lua51.plugin b/tests/libpeas/plugins/extension-lua/extension-lua51.plugin new file mode 100644 index 0000000..ff4b51a --- /dev/null +++ b/tests/libpeas/plugins/extension-lua/extension-lua51.plugin @@ -0,0 +1,7 @@ +[Plugin] +Module=extension-lua51 +Loader=lua5.1 +Name=Extension lua5.1 +Description=This plugin is for the lua5.1 PeasExtension tests. +Authors=Garrett Regier +Copyright=Copyright © 2014 Garrett Regier diff --git a/tests/libpeas/plugins/extension-lua51-nonexistent.plugin b/tests/libpeas/plugins/extension-lua51-nonexistent.plugin new file mode 100644 index 0000000..0294240 --- /dev/null +++ b/tests/libpeas/plugins/extension-lua51-nonexistent.plugin @@ -0,0 +1,7 @@ +[Plugin] +Module=extension-lua51-nonexistent +Loader=lua5.1 +Name=Extension lua5.1 Nonexistent +Description=This plugin is nonexistent. +Authors=Garrett Regier +Copyright=Copyright © 2014 Garrett Regier diff --git a/tests/libpeas/testing/testing-extension.c b/tests/libpeas/testing/testing-extension.c index 12f1db3..e1f6a59 100644 --- a/tests/libpeas/testing/testing-extension.c +++ b/tests/libpeas/testing/testing-extension.c @@ -171,6 +171,7 @@ test_extension_create_invalid (PeasEngine *engine, /* This cannot be tested in PyGI and Seed's log handler messes this up */ if (g_strcmp0 (extension_plugin, "extension-c") != 0 && + g_strcmp0 (extension_plugin, "extension-lua51") != 0 && g_strcmp0 (extension_plugin, "extension-python") != 0 && g_strcmp0 (extension_plugin, "extension-python3") != 0) { @@ -387,9 +388,19 @@ test_extension_call_multi_args (PeasEngine *engine, void testing_extension_basic (const gchar *loader) { + gint i, j; + gchar *loader_name; PeasEngine *engine; - extension_plugin = g_strdup_printf ("extension-%s", loader); + loader_name = g_new0 (gchar, strlen (loader)); + for (i = 0, j = 0; loader[i] != '\0'; ++i) + { + if (loader[i] != '.') + loader_name[j++] = loader[i]; + } + + extension_plugin = g_strdup_printf ("extension-%s", loader_name); + g_free (loader_name); engine = testing_engine_new (); peas_engine_enable_loader (engine, loader); |