diff options
author | Richard Hughes <richard@hughsie.com> | 2014-06-17 11:52:49 +0100 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2014-06-17 12:01:32 +0100 |
commit | 1284b3fa0addf21070c6d9ce697623a04862cdde (patch) | |
tree | a9ecf1b4d984e41e56179ebd6453288dd712843e /libappstream-builder/asb-plugin-loader.c | |
parent | 0ec1dd10ee2281d4f6e102e4e8da8365332540b1 (diff) | |
download | appstream-glib-1284b3fa0addf21070c6d9ce697623a04862cdde.tar.gz |
Add libappstream-builder from the createrepo_as project
Diffstat (limited to 'libappstream-builder/asb-plugin-loader.c')
-rw-r--r-- | libappstream-builder/asb-plugin-loader.c | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/libappstream-builder/asb-plugin-loader.c b/libappstream-builder/asb-plugin-loader.c new file mode 100644 index 0000000..1f4eb13 --- /dev/null +++ b/libappstream-builder/asb-plugin-loader.c @@ -0,0 +1,383 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2014 Richard Hughes <richard@hughsie.com> + * + * Licensed under the GNU Lesser General Public License Version 2.1 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * SECTION:asb-plugin-loader + * @short_description: Plugin loader. + * @stability: Unstable + * + * This module provides an array of plugins which can operate on an exploded + * package tree. + */ + +#include "config.h" + +#include <glib.h> + +#include "as-cleanup.h" +#include "asb-plugin.h" +#include "asb-plugin-loader.h" + +/** + * asb_plugin_loader_plugin_free: + **/ +static void +asb_plugin_loader_plugin_free (AsbPlugin *plugin) +{ + g_free (plugin->priv); + g_free (plugin->name); + g_module_close (plugin->module); + g_slice_free (AsbPlugin, plugin); +} + +/** + * asb_plugin_loader_match_fn: + * @plugins: (element-type AsbPlugin): An array of plugins + * @filename: filename + * + * Processes the list of plugins finding a plugin that can process the filename. + * + * Returns: (transfer none): a plugin, or %NULL + * + * Since: 0.1.0 + **/ +AsbPlugin * +asb_plugin_loader_match_fn (GPtrArray *plugins, const gchar *filename) +{ + gboolean ret; + AsbPluginCheckFilenameFunc plugin_func = NULL; + AsbPlugin *plugin; + guint i; + + /* run each plugin */ + for (i = 0; i < plugins->len; i++) { + plugin = g_ptr_array_index (plugins, i); + ret = g_module_symbol (plugin->module, + "asb_plugin_check_filename", + (gpointer *) &plugin_func); + if (!ret) + continue; + if (plugin_func (plugin, filename)) + return plugin; + } + return NULL; +} + +/** + * asb_plugin_loader_process_app: + * @plugins: (element-type AsbPlugin): An array of plugins + * @pkg: The #AsbPackage + * @app: The #AsbApp to refine + * @tmpdir: A temporary location to use + * @error: A #GError or %NULL + * + * Processes an application object, refining any available data. + * + * Returns: %TRUE for success, %FALSE otherwise + * + * Since: 0.1.0 + **/ +gboolean +asb_plugin_loader_process_app (GPtrArray *plugins, + AsbPackage *pkg, + AsbApp *app, + const gchar *tmpdir, + GError **error) +{ + gboolean ret; + AsbPluginProcessAppFunc plugin_func = NULL; + AsbPlugin *plugin; + guint i; + + /* run each plugin */ + for (i = 0; i < plugins->len; i++) { + plugin = g_ptr_array_index (plugins, i); + ret = g_module_symbol (plugin->module, + "asb_plugin_process_app", + (gpointer *) &plugin_func); + if (!ret) + continue; + asb_package_log (pkg, + ASB_PACKAGE_LOG_LEVEL_DEBUG, + "Running asb_plugin_process_app() from %s", + plugin->name); + if (!plugin_func (plugin, pkg, app, tmpdir, error)) + return FALSE; + } + return TRUE; +} + +/** + * asb_plugin_loader_run: + **/ +static void +asb_plugin_loader_run (GPtrArray *plugins, const gchar *function_name) +{ + gboolean ret; + AsbPluginFunc plugin_func = NULL; + AsbPlugin *plugin; + guint i; + + /* run each plugin */ + for (i = 0; i < plugins->len; i++) { + plugin = g_ptr_array_index (plugins, i); + ret = g_module_symbol (plugin->module, + function_name, + (gpointer *) &plugin_func); + if (!ret) + continue; + plugin_func (plugin); + } +} + +/** + * asb_plugin_loader_get_globs: + * @plugins: (element-type AsbPlugin): An array of plugins + * + * Gets the list of globs. + * + * Returns: (transfer container) (element-type utf8): globs + * + * Since: 0.1.0 + **/ +GPtrArray * +asb_plugin_loader_get_globs (GPtrArray *plugins) +{ + gboolean ret; + AsbPluginGetGlobsFunc plugin_func = NULL; + AsbPlugin *plugin; + guint i; + GPtrArray *globs; + + /* run each plugin */ + globs = asb_glob_value_array_new (); + for (i = 0; i < plugins->len; i++) { + plugin = g_ptr_array_index (plugins, i); + ret = g_module_symbol (plugin->module, + "asb_plugin_add_globs", + (gpointer *) &plugin_func); + if (!ret) + continue; + plugin_func (plugin, globs); + } + return globs; +} + +/** + * asb_plugin_loader_merge: + * @plugins: (element-type AsbPlugin): An array of plugins + * @apps: (element-type AsbApp): a list of applications that need merging + * + * Merge the list of applications using the plugins. + * + * Since: 0.1.0 + **/ +void +asb_plugin_loader_merge (GPtrArray *plugins, GList **apps) +{ + const gchar *key; + const gchar *tmp; + AsbApp *app; + AsbApp *found; + AsbPluginMergeFunc plugin_func = NULL; + AsbPlugin *plugin; + gboolean ret; + GList *l; + guint i; + _cleanup_hashtable_unref_ GHashTable *hash; + + /* run each plugin */ + for (i = 0; i < plugins->len; i++) { + plugin = g_ptr_array_index (plugins, i); + ret = g_module_symbol (plugin->module, + "asb_plugin_merge", + (gpointer *) &plugin_func); + if (!ret) + continue; + plugin_func (plugin, apps); + } + + /* FIXME: move to font plugin */ + for (l = *apps; l != NULL; l = l->next) { + if (!ASB_IS_APP (l->data)) + continue; + app = ASB_APP (l->data); + as_app_remove_metadata (AS_APP (app), "FontFamily"); + as_app_remove_metadata (AS_APP (app), "FontFullName"); + as_app_remove_metadata (AS_APP (app), "FontIconText"); + as_app_remove_metadata (AS_APP (app), "FontParent"); + as_app_remove_metadata (AS_APP (app), "FontSampleText"); + as_app_remove_metadata (AS_APP (app), "FontSubFamily"); + as_app_remove_metadata (AS_APP (app), "FontClassifier"); + } + + /* deduplicate */ + hash = g_hash_table_new (g_str_hash, g_str_equal); + for (l = *apps; l != NULL; l = l->next) { + if (!ASB_IS_APP (l->data)) + continue; + app = ASB_APP (l->data); + key = as_app_get_id_full (AS_APP (app)); + found = g_hash_table_lookup (hash, key); + if (found == NULL) { + g_hash_table_insert (hash, + (gpointer) key, + (gpointer) app); + continue; + } + tmp = asb_package_get_nevr (asb_app_get_package (found)); + asb_app_add_veto (app, "duplicate of %s", tmp); + asb_package_log (asb_app_get_package (app), + ASB_PACKAGE_LOG_LEVEL_WARNING, + "duplicate %s not included as added from %s", + key, tmp); + } +} + +/** + * asb_plugin_loader_open_plugin: + **/ +static AsbPlugin * +asb_plugin_loader_open_plugin (GPtrArray *plugins, + const gchar *filename) +{ + gboolean ret; + GModule *module; + AsbPluginGetNameFunc plugin_name = NULL; + AsbPlugin *plugin = NULL; + + module = g_module_open (filename, 0); + if (module == NULL) { + g_warning ("failed to open plugin %s: %s", + filename, g_module_error ()); + return NULL; + } + + /* get description */ + ret = g_module_symbol (module, + "asb_plugin_get_name", + (gpointer *) &plugin_name); + if (!ret) { + g_warning ("Plugin %s requires name", filename); + g_module_close (module); + return NULL; + } + + /* print what we know */ + plugin = g_slice_new0 (AsbPlugin); + plugin->enabled = TRUE; + plugin->module = module; + plugin->name = g_strdup (plugin_name ()); + g_debug ("opened plugin %s: %s", filename, plugin->name); + + /* add to array */ + g_ptr_array_add (plugins, plugin); + return plugin; +} + +/** + * asb_plugin_loader_sort_cb: + **/ +static gint +asb_plugin_loader_sort_cb (gconstpointer a, gconstpointer b) +{ + AsbPlugin **plugin_a = (AsbPlugin **) a; + AsbPlugin **plugin_b = (AsbPlugin **) b; + return -g_strcmp0 ((*plugin_a)->name, (*plugin_b)->name); +} + +/** + * asb_plugin_loader_setup: + * @plugins: (element-type AsbPlugin): An array of plugins + * @error: A #GError or %NULL + * + * Set up the plugin loader. + * + * Returns: %TRUE for success, %FALSE otherwise + * + * Since: 0.1.0 + **/ +gboolean +asb_plugin_loader_setup (GPtrArray *plugins, GError **error) +{ + const gchar *filename_tmp; + const gchar *location = "./plugins/.libs/"; + _cleanup_dir_close_ GDir *dir; + + /* search system-wide if not found locally */ + if (!g_file_test (location, G_FILE_TEST_EXISTS)) + location = ASB_PLUGIN_DIR; + + /* search in the plugin directory for plugins */ + dir = g_dir_open (location, 0, error); + if (dir == NULL) + return FALSE; + + /* try to open each plugin */ + g_debug ("searching for plugins in %s", location); + do { + _cleanup_free_ gchar *filename_plugin = NULL; + filename_tmp = g_dir_read_name (dir); + if (filename_tmp == NULL) + break; + if (!g_str_has_suffix (filename_tmp, ".so")) + continue; + filename_plugin = g_build_filename (location, + filename_tmp, + NULL); + asb_plugin_loader_open_plugin (plugins, filename_plugin); + } while (TRUE); + + /* run the plugins */ + asb_plugin_loader_run (plugins, "asb_plugin_initialize"); + g_ptr_array_sort (plugins, asb_plugin_loader_sort_cb); + return TRUE; +} + +/** + * asb_plugin_loader_new: + * + * Creates a new plugin loader interface. + * + * Returns: (transfer container) (element-type AsbPlugin): state + * + * Since: 0.1.0 + **/ +GPtrArray * +asb_plugin_loader_new (void) +{ + return g_ptr_array_new_with_free_func ((GDestroyNotify) asb_plugin_loader_plugin_free); +} + +/** + * asb_plugin_loader_free: + * @plugins: (element-type AsbPlugin): An array of plugins + * + * Destroy the plugin state. + * + * Since: 0.1.0 + **/ +void +asb_plugin_loader_free (GPtrArray *plugins) +{ + asb_plugin_loader_run (plugins, "asb_plugin_destroy"); + g_ptr_array_unref (plugins); +} |