summaryrefslogtreecommitdiff
path: root/libpeas
diff options
context:
space:
mode:
authorGarrett Regier <garrettregier@gmail.com>2015-11-20 19:50:48 -0800
committerGarrett Regier <garrettregier@gmail.com>2015-12-15 16:57:46 -0800
commitb19f1cea0fdc5b91ed6ef6d40ff67f9dcd217eda (patch)
tree2b3092d0588ca70c087795c3586fd27c5f62dba4 /libpeas
parent8327a10b367397462ba680bfa8c7bba334dfbd08 (diff)
downloadlibpeas-b19f1cea0fdc5b91ed6ef6d40ff67f9dcd217eda.tar.gz
Add support for embedded C plugins
This adds the new key Embedded to the .plugin file which specifies the function to call instead of peas_register_types to perform that same job. https://bugzilla.gnome.org/show_bug.cgi?id=721693
Diffstat (limited to 'libpeas')
-rw-r--r--libpeas/peas-engine.c78
-rw-r--r--libpeas/peas-object-module.c122
-rw-r--r--libpeas/peas-object-module.h3
-rw-r--r--libpeas/peas-plugin-info-priv.h1
-rw-r--r--libpeas/peas-plugin-info.c59
-rw-r--r--libpeas/peas-plugin-loader-c.c22
6 files changed, 241 insertions, 44 deletions
diff --git a/libpeas/peas-engine.c b/libpeas/peas-engine.c
index 4a2782b..ccee8a6 100644
--- a/libpeas/peas-engine.c
+++ b/libpeas/peas-engine.c
@@ -161,10 +161,10 @@ load_plugin_info (PeasEngine *engine,
}
static void
-load_dir_real (PeasEngine *engine,
- const gchar *module_dir,
- const gchar *data_dir,
- guint recursions)
+load_file_dir_real (PeasEngine *engine,
+ const gchar *module_dir,
+ const gchar *data_dir,
+ guint recursions)
{
GError *error = NULL;
GDir *d;
@@ -188,7 +188,7 @@ load_dir_real (PeasEngine *engine,
if (g_file_test (filename, G_FILE_TEST_IS_DIR))
{
if (recursions > 0)
- load_dir_real (engine, filename, data_dir, recursions - 1);
+ load_file_dir_real (engine, filename, data_dir, recursions - 1);
}
else if (g_str_has_suffix (dirent, ".plugin"))
{
@@ -201,6 +201,67 @@ load_dir_real (PeasEngine *engine,
g_dir_close (d);
}
+static void
+load_resource_dir_real (PeasEngine *engine,
+ const gchar *module_dir,
+ const gchar *data_dir,
+ guint recursions)
+{
+ guint i;
+ const gchar *module_path;
+ gchar **children;
+ GError *error = NULL;
+
+ g_debug ("Loading %s/*.plugin...", module_dir);
+
+ module_path = module_dir + strlen ("resource://");
+ children = g_resources_enumerate_children (module_path,
+ G_RESOURCE_LOOKUP_FLAGS_NONE,
+ &error);
+
+ if (error != NULL)
+ {
+ g_debug ("%s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ for (i = 0; children[i] != NULL; ++i)
+ {
+ gboolean is_dir;
+ gchar *child;
+
+ is_dir = g_str_has_suffix (children[i], "/");
+
+ if (is_dir && recursions == 0)
+ continue;
+
+ if (!is_dir && !g_str_has_suffix (children[i], ".plugin"))
+ continue;
+
+ child = g_build_path ("/", module_dir, children[i], NULL);
+
+ if (is_dir)
+ load_resource_dir_real (engine, child, data_dir, recursions - 1);
+ else
+ load_plugin_info (engine, child, module_dir, data_dir);
+
+ g_free (child);
+ }
+
+ g_strfreev (children);
+}
+
+static void
+load_dir_real (PeasEngine *engine,
+ SearchPath *sp)
+{
+ if (!g_str_has_prefix (sp->module_dir, "resource://"))
+ load_file_dir_real (engine, sp->module_dir, sp->data_dir, 1);
+ else
+ load_resource_dir_real (engine, sp->module_dir, sp->data_dir, 1);
+}
+
/**
* peas_engine_rescan_plugins:
* @engine: A #PeasEngine.
@@ -229,10 +290,7 @@ peas_engine_rescan_plugins (PeasEngine *engine)
/* Go and read everything from the provided search paths */
for (item = priv->search_paths; item != NULL; item = item->next)
- {
- SearchPath *sp = (SearchPath *) item->data;
- load_dir_real (engine, sp->module_dir, sp->data_dir, 1);
- }
+ load_dir_real (engine, (SearchPath *) item->data);
g_object_thaw_notify (G_OBJECT (engine));
}
@@ -256,7 +314,7 @@ peas_engine_insert_search_path (PeasEngine *engine,
priv->search_paths = g_list_insert (priv->search_paths, sp, position);
g_object_freeze_notify (G_OBJECT (engine));
- load_dir_real (engine, sp->module_dir, sp->data_dir, 1);
+ load_dir_real (engine, sp);
g_object_thaw_notify (G_OBJECT (engine));
}
diff --git a/libpeas/peas-object-module.c b/libpeas/peas-object-module.c
index a6ae729..fbd81f2 100644
--- a/libpeas/peas-object-module.c
+++ b/libpeas/peas-object-module.c
@@ -48,6 +48,7 @@ enum {
PROP_0,
PROP_MODULE_NAME,
PROP_PATH,
+ PROP_SYMBOL,
PROP_RESIDENT,
PROP_LOCAL_LINKAGE,
N_PROPERTIES
@@ -70,6 +71,7 @@ struct _PeasObjectModulePrivate {
gchar *path;
gchar *module_name;
+ gchar *symbol;
guint resident : 1;
guint local_linkage : 1;
@@ -91,27 +93,39 @@ peas_object_module_load (GTypeModule *gmodule)
{
PeasObjectModule *module = PEAS_OBJECT_MODULE (gmodule);
PeasObjectModulePrivate *priv = GET_PRIV (module);
- GModuleFlags flags = 0;
- gchar *path;
-
- if (priv->local_linkage)
- flags = G_MODULE_BIND_LOCAL;
- path = g_module_build_path (priv->path, priv->module_name);
- g_return_val_if_fail (path != NULL, FALSE);
+ g_return_val_if_fail (priv->module_name != NULL, FALSE);
- /* g_module_build_path() will add G_MODULE_SUFFIX to the path,
- * however g_module_open() will only try to load the libtool archive
- * if there is no suffix specified. So we remove G_MODULE_SUFFIX here
- * which allows uninstalled builds to load plugins as well, as there
- * is only the .la file in the build directory.
- */
- if (G_MODULE_SUFFIX[0] != '\0' && g_str_has_suffix (path, "." G_MODULE_SUFFIX))
- path[strlen (path) - strlen (G_MODULE_SUFFIX) - 1] = '\0';
+ if (priv->path == NULL)
+ {
+ g_return_val_if_fail (priv->resident, FALSE);
+ g_return_val_if_fail (!priv->local_linkage, FALSE);
- /* Bind symbols immediately to avoid errors long after loading */
- priv->library = g_module_open (path, flags);
- g_free (path);
+ priv->library = g_module_open (NULL, 0);
+ }
+ else
+ {
+ gchar *path;
+ GModuleFlags flags = 0;
+
+ path = g_module_build_path (priv->path, priv->module_name);
+
+ /* g_module_build_path() will add G_MODULE_SUFFIX to the path,
+ * however g_module_open() will only try to load the libtool archive
+ * if there is no suffix specified. So we remove G_MODULE_SUFFIX here
+ * which allows uninstalled builds to load plugins as well, as there
+ * is only the .la file in the build directory.
+ */
+ if (G_MODULE_SUFFIX[0] != '\0' && g_str_has_suffix (path, "." G_MODULE_SUFFIX))
+ path[strlen (path) - strlen (G_MODULE_SUFFIX) - 1] = '\0';
+
+ if (priv->local_linkage)
+ flags = G_MODULE_BIND_LOCAL;
+
+ /* Bind symbols immediately to avoid errors long after loading */
+ priv->library = g_module_open (path, flags);
+ g_free (path);
+ }
if (priv->library == NULL)
{
@@ -122,12 +136,11 @@ peas_object_module_load (GTypeModule *gmodule)
}
/* Extract the required symbol from the library */
- if (!g_module_symbol (priv->library,
- "peas_register_types",
+ if (!g_module_symbol (priv->library, priv->symbol,
(gpointer) &priv->register_func))
{
- g_warning ("Failed to get 'peas_register_types' for module '%s': %s",
- priv->module_name, g_module_error ());
+ g_warning ("Failed to get '%s' for module '%s': %s",
+ priv->symbol, priv->module_name, g_module_error ());
g_module_close (priv->library);
return FALSE;
@@ -138,8 +151,8 @@ peas_object_module_load (GTypeModule *gmodule)
*/
if (priv->register_func == NULL)
{
- g_warning ("Invalid 'peas_register_types' in module '%s'",
- priv->module_name);
+ g_warning ("Invalid '%s' in module '%s'",
+ priv->symbol, priv->module_name);
g_module_close (priv->library);
return FALSE;
@@ -194,6 +207,7 @@ peas_object_module_finalize (GObject *object)
g_free (priv->path);
g_free (priv->module_name);
+ g_free (priv->symbol);
g_array_unref (priv->implementations);
G_OBJECT_CLASS (peas_object_module_parent_class)->finalize (object);
@@ -216,6 +230,9 @@ peas_object_module_get_property (GObject *object,
case PROP_PATH:
g_value_set_string (value, priv->path);
break;
+ case PROP_SYMBOL:
+ g_value_set_string (value, priv->symbol);
+ break;
case PROP_RESIDENT:
g_value_set_boolean (value, priv->resident);
break;
@@ -247,6 +264,9 @@ peas_object_module_set_property (GObject *object,
case PROP_PATH:
priv->path = g_value_dup_string (value);
break;
+ case PROP_SYMBOL:
+ priv->symbol = g_value_dup_string (value);
+ break;
case PROP_RESIDENT:
priv->resident = g_value_get_boolean (value);
break;
@@ -292,6 +312,15 @@ peas_object_module_class_init (PeasObjectModuleClass *klass)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
+ properties[PROP_SYMBOL] =
+ g_param_spec_string ("symbol",
+ "Symbol",
+ "The registration symbol to use for this module",
+ "peas_register_types",
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
properties[PROP_RESIDENT] =
g_param_spec_boolean ("resident",
"Resident",
@@ -377,6 +406,31 @@ peas_object_module_new_full (const gchar *module_name,
}
/**
+ * peas_object_module_new_embedded: (skip)
+ * @module_name: The module name.
+ *
+ * Creates a new #PeasObjectModule for an embedded plugin.
+ *
+ * Return value: a new #PeasObjectModule.
+ *
+ * Since: 1.18
+ */
+PeasObjectModule *
+peas_object_module_new_embedded (const gchar *module_name,
+ const gchar *symbol)
+{
+ g_return_val_if_fail (module_name != NULL && *module_name != '\0', NULL);
+ g_return_val_if_fail (symbol != NULL && *symbol != '\0', NULL);
+
+ return PEAS_OBJECT_MODULE (g_object_new (PEAS_TYPE_OBJECT_MODULE,
+ "module-name", module_name,
+ "symbol", symbol,
+ "resident", TRUE,
+ "local-linkage", FALSE,
+ NULL));
+}
+
+/**
* peas_object_module_create_object: (skip)
* @module: A #PeasObjectModule.
* @interface: The #GType of the extension interface.
@@ -484,6 +538,26 @@ peas_object_module_get_module_name (PeasObjectModule *module)
}
/**
+ * peas_object_module_get_symbol: (skip)
+ * @module: A #PeasObjectModule.
+ *
+ * Gets the symbol name used to register extension implementations.
+ *
+ * Return value: the symbol name.
+ *
+ * Since: 1.18
+ */
+const gchar *
+peas_object_module_get_symbol (PeasObjectModule *module)
+{
+ PeasObjectModulePrivate *priv = GET_PRIV (module);
+
+ g_return_val_if_fail (PEAS_IS_OBJECT_MODULE (module), NULL);
+
+ return priv->symbol;
+}
+
+/**
* peas_object_module_get_library: (skip)
* @module: A #PeasObjectModule.
*
diff --git a/libpeas/peas-object-module.h b/libpeas/peas-object-module.h
index 9f7e164..70a0265 100644
--- a/libpeas/peas-object-module.h
+++ b/libpeas/peas-object-module.h
@@ -91,6 +91,8 @@ PeasObjectModule *peas_object_module_new_full (const gchar
const gchar *path,
gboolean resident,
gboolean local_linkage);
+PeasObjectModule *peas_object_module_new_embedded (const gchar *module_name,
+ const gchar *symbol);
GObject *peas_object_module_create_object (PeasObjectModule *module,
GType interface,
@@ -101,6 +103,7 @@ gboolean peas_object_module_provides_object (PeasObjectModule
const gchar *peas_object_module_get_path (PeasObjectModule *module);
const gchar *peas_object_module_get_module_name (PeasObjectModule *module);
+const gchar *peas_object_module_get_symbol (PeasObjectModule *module);
GModule *peas_object_module_get_library (PeasObjectModule *module);
diff --git a/libpeas/peas-plugin-info-priv.h b/libpeas/peas-plugin-info-priv.h
index e4b2fd3..2359df5 100644
--- a/libpeas/peas-plugin-info-priv.h
+++ b/libpeas/peas-plugin-info-priv.h
@@ -37,6 +37,7 @@ struct _PeasPluginInfo {
gchar *data_dir;
gint loader_id;
+ gchar *embedded;
gchar *module_name;
gchar **dependencies;
diff --git a/libpeas/peas-plugin-info.c b/libpeas/peas-plugin-info.c
index b30e82b..6fb7ce6 100644
--- a/libpeas/peas-plugin-info.c
+++ b/libpeas/peas-plugin-info.c
@@ -85,6 +85,7 @@ _peas_plugin_info_unref (PeasPluginInfo *info)
g_free (info->filename);
g_free (info->module_dir);
g_free (info->data_dir);
+ g_free (info->embedded);
g_free (info->module_name);
g_strfreev (info->dependencies);
g_free (info->name);
@@ -124,19 +125,42 @@ _peas_plugin_info_new (const gchar *filename,
const gchar *data_dir)
{
gsize i;
+ gboolean is_resource;
gchar *loader = NULL;
gchar **strv, **keys;
PeasPluginInfo *info;
GKeyFile *plugin_file;
+ GBytes *bytes = NULL;
GError *error = NULL;
g_return_val_if_fail (filename != NULL, NULL);
+ is_resource = g_str_has_prefix (filename, "resource://");
+
info = g_new0 (PeasPluginInfo, 1);
info->refcount = 1;
plugin_file = g_key_file_new ();
- if (!g_key_file_load_from_file (plugin_file, filename,
+
+ if (is_resource)
+ {
+ bytes = g_resources_lookup_data (filename + strlen ("resource://"),
+ G_RESOURCE_LOOKUP_FLAGS_NONE,
+ &error);
+ }
+ else
+ {
+ gchar *content;
+ gsize length;
+
+ if (g_file_get_contents (filename, &content, &length, &error))
+ bytes = g_bytes_new_take (content, length);
+ }
+
+ if (bytes == NULL ||
+ !g_key_file_load_from_data (plugin_file,
+ g_bytes_get_data (bytes, NULL),
+ g_bytes_get_size (bytes),
G_KEY_FILE_NONE, &error))
{
g_warning ("Bad plugin file '%s': %s", filename, error->message);
@@ -183,7 +207,31 @@ _peas_plugin_info_new (const gchar *filename,
}
}
- g_free (loader);
+ /* Get Embedded */
+ info->embedded = g_key_file_get_string (plugin_file, "Plugin",
+ "Embedded", NULL);
+ if (info->embedded != NULL)
+ {
+ if (info->loader_id != PEAS_UTILS_C_LOADER_ID)
+ {
+ g_warning ("Bad plugin file '%s': embedded plugins "
+ "must use the C plugin loader", filename);
+ goto error;
+ }
+
+ if (!is_resource)
+ {
+ g_warning ("Bad plugin file '%s': embedded plugins "
+ "must be a resource", filename);
+ goto error;
+ }
+ }
+ else if (is_resource)
+ {
+ g_warning ("Bad plugin file '%s': resource plugins must be embedded",
+ filename);
+ goto error;
+ }
/* Get the dependency list */
info->dependencies = g_key_file_get_string_list (plugin_file,
@@ -259,11 +307,14 @@ _peas_plugin_info_new (const gchar *filename,
g_strfreev (keys);
+ g_free (loader);
+ g_bytes_unref (bytes);
g_key_file_free (plugin_file);
info->filename = g_strdup (filename);
info->module_dir = g_strdup (module_dir);
- info->data_dir = g_build_filename (data_dir, info->module_name, NULL);
+ info->data_dir = g_build_path (is_resource ? "/" : G_DIR_SEPARATOR_S,
+ data_dir, info->module_name, NULL);
/* If we know nothing about the availability of the plugin,
set it as available */
@@ -273,10 +324,12 @@ _peas_plugin_info_new (const gchar *filename,
error:
+ g_free (info->embedded);
g_free (loader);
g_free (info->module_name);
g_free (info->name);
g_free (info);
+ g_clear_pointer (&bytes, g_bytes_unref);
g_key_file_free (plugin_file);
return NULL;
diff --git a/libpeas/peas-plugin-loader-c.c b/libpeas/peas-plugin-loader-c.c
index 59942d0..a476eb4 100644
--- a/libpeas/peas-plugin-loader-c.c
+++ b/libpeas/peas-plugin-loader-c.c
@@ -65,13 +65,21 @@ peas_plugin_loader_c_load (PeasPluginLoader *loader,
module_name = peas_plugin_info_get_module_name (info);
module_dir = peas_plugin_info_get_module_dir (info);
- /* Force all C modules to be resident in case they
- * use libraries that do not deal well with reloading.
- * Furthermore, we use local linkage to improve module isolation.
- */
- info->loader_data = peas_object_module_new_full (module_name,
- module_dir,
- TRUE, TRUE);
+ if (info->embedded != NULL)
+ {
+ info->loader_data = peas_object_module_new_embedded (module_name,
+ info->embedded);
+ }
+ else
+ {
+ /* Force all C modules to be resident in case they
+ * use libraries that do not deal well with reloading.
+ * Furthermore, we use local linkage to improve module isolation.
+ */
+ info->loader_data = peas_object_module_new_full (module_name,
+ module_dir,
+ TRUE, TRUE);
+ }
if (!g_type_module_use (G_TYPE_MODULE (info->loader_data)))
g_clear_object (&info->loader_data);