diff options
author | Garrett Regier <garrettregier@gmail.com> | 2015-11-20 19:50:48 -0800 |
---|---|---|
committer | Garrett Regier <garrettregier@gmail.com> | 2015-12-15 16:57:46 -0800 |
commit | b19f1cea0fdc5b91ed6ef6d40ff67f9dcd217eda (patch) | |
tree | 2b3092d0588ca70c087795c3586fd27c5f62dba4 /libpeas | |
parent | 8327a10b367397462ba680bfa8c7bba334dfbd08 (diff) | |
download | libpeas-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.c | 78 | ||||
-rw-r--r-- | libpeas/peas-object-module.c | 122 | ||||
-rw-r--r-- | libpeas/peas-object-module.h | 3 | ||||
-rw-r--r-- | libpeas/peas-plugin-info-priv.h | 1 | ||||
-rw-r--r-- | libpeas/peas-plugin-info.c | 59 | ||||
-rw-r--r-- | libpeas/peas-plugin-loader-c.c | 22 |
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); |