[evolution-data-server] Allow to load modules from custom prefixes
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Allow to load modules from custom prefixes
- Date: Thu, 25 Feb 2021 07:03:22 +0000 (UTC)
commit 4aff145a850b13232cae9958e1f409ae6e99f0cf
Author: Milan Crha <mcrha redhat com>
Date: Thu Feb 25 08:02:36 2021 +0100
Allow to load modules from custom prefixes
This change loads modules not only from the install prefix,
but tries to read it also from the ~/.local/share/evolution/modules
and from the directories listed in the EDS_EXTRA_PREFIXES, which
is a list of paths separated by colon (':').
src/camel/camel-provider.c | 100 +++++++++++------
src/camel/camel.c | 123 +++++++++++++++++++++
src/camel/camel.h | 4 +
src/libebackend/e-dbus-server.c | 2 +-
src/libedataserver/e-data-server-util.c | 35 ++++++
src/libedataserver/e-data-server-util.h | 3 +
src/libedataserver/e-module.c | 58 ++++++++++
src/libedataserver/e-module.h | 3 +
src/libedataserver/e-source-credentials-provider.c | 2 +-
src/libedataserverui/CMakeLists.txt | 1 +
src/libedataserverui/libedataserverui-private.c | 2 +-
11 files changed, 298 insertions(+), 35 deletions(-)
---
diff --git a/src/camel/camel-provider.c b/src/camel/camel-provider.c
index 8e4dad45a..915c65f87 100644
--- a/src/camel/camel-provider.c
+++ b/src/camel/camel-provider.c
@@ -37,6 +37,7 @@
#include "camel-string-utils.h"
#include "camel-vee-store.h"
#include "camel-win32.h"
+#include "camel.h"
/* table of CamelProviderModule's */
static GHashTable *module_table;
@@ -182,45 +183,22 @@ provider_setup (gpointer param)
return NULL;
}
-/**
- * camel_provider_init:
- *
- * Initialize the Camel provider system by reading in the .urls
- * files in the provider directory and creating a hash table mapping
- * URLs to module names.
- *
- * A .urls file has the same initial prefix as the shared library it
- * correspond to, and consists of a series of lines containing the URL
- * protocols that that library handles.
- *
- * TODO: This should be pathed?
- * TODO: This should be plugin-d?
- **/
-void
-camel_provider_init (void)
+static void
+camel_provider_traverse_directory (const gchar *provider_dir,
+ gboolean warn_failure)
{
GDir *dir;
const gchar *entry;
gchar *p, *name, buf[80];
- static gint loaded = 0;
- const gchar *provider_dir;
-
- provider_dir = g_getenv (EDS_CAMEL_PROVIDER_DIR);
- if (!provider_dir)
- provider_dir = CAMEL_PROVIDERDIR;
-
- g_once (&setup_once, provider_setup, NULL);
-
- if (loaded)
- return;
-
- loaded = 1;
dir = g_dir_open (provider_dir, 0, NULL);
if (!dir) {
- g_warning (
- "Could not open camel provider directory (%s): %s",
- provider_dir, g_strerror (errno));
+ if (warn_failure) {
+ g_warning (
+ "Could not open camel provider directory (%s): %s",
+ provider_dir, g_strerror (errno));
+ }
+
return;
}
@@ -273,6 +251,64 @@ camel_provider_init (void)
g_dir_close (dir);
}
+/**
+ * camel_provider_init:
+ *
+ * Initialize the Camel provider system by reading in the .urls
+ * files in the provider directory and creating a hash table mapping
+ * URLs to module names.
+ *
+ * A .urls file has the same initial prefix as the shared library it
+ * correspond to, and consists of a series of lines containing the URL
+ * protocols that that library handles.
+ *
+ * TODO: This should be pathed?
+ * TODO: This should be plugin-d?
+ **/
+void
+camel_provider_init (void)
+{
+ static gint loaded = 0;
+ const gchar *provider_dir;
+ gboolean is_default = FALSE;
+
+ provider_dir = g_getenv (EDS_CAMEL_PROVIDER_DIR);
+ if (!provider_dir) {
+ provider_dir = CAMEL_PROVIDERDIR;
+ is_default = TRUE;
+ }
+
+ g_once (&setup_once, provider_setup, NULL);
+
+ if (loaded)
+ return;
+
+ loaded = 1;
+
+ if (is_default) {
+ GPtrArray *variants;
+
+ variants = camel_util_get_directory_variants (provider_dir, E_DATA_SERVER_PREFIX, TRUE);
+
+ if (variants) {
+ guint ii;
+
+ for (ii = 0; ii < variants->len; ii++) {
+ const gchar *path = g_ptr_array_index (variants, ii);
+
+ if (path && *path)
+ camel_provider_traverse_directory (path, g_strcmp0 (provider_dir,
path) == 0);
+ }
+
+ g_ptr_array_unref (variants);
+ } else {
+ camel_provider_traverse_directory (provider_dir, TRUE);
+ }
+ } else {
+ camel_provider_traverse_directory (provider_dir, TRUE);
+ }
+}
+
/**
* camel_provider_load:
* @path: the path to a shared library
diff --git a/src/camel/camel.c b/src/camel/camel.c
index d2babff18..e10f9e463 100644
--- a/src/camel/camel.c
+++ b/src/camel/camel.c
@@ -392,3 +392,126 @@ camel_binding_bind_property_with_closures (gpointer source,
return binding;
}
+
+static gint
+sort_paths_by_index (gconstpointer aa,
+ gconstpointer bb,
+ gpointer user_data)
+{
+ GHashTable *paths_hash = user_data;
+ const gchar *path1 = *((gchar **) aa);
+ const gchar *path2 = *((gchar **) bb);
+ gint val1, val2;
+
+ val1 = GPOINTER_TO_INT (g_hash_table_lookup (paths_hash, path1));
+ val2 = GPOINTER_TO_INT (g_hash_table_lookup (paths_hash, path2));
+
+ return val1 - val2;
+}
+
+/**
+ * camel_util_get_directory_variants:
+ * @main_path: the main path to work with
+ * @replace_prefix: path prefix to replace
+ * @with_modules_dir: whether to add also the modules directory
+ *
+ * The @main_path is a directory, which will be always used. It
+ * should have as its prefix the @replace_prefix, otherwise
+ * the function returns only the @main_path in the paths array.
+ *
+ * When there's exported an environment variable EDS_EXTRA_PREFIXES,
+ * it is used as a list of alternative prefixes where to look for
+ * the @main_path (rest after the @replace_prefix).
+ *
+ * When the @with_modules_dir is %TRUE, there's also added
+ * g_get_user_data_dir() + "evolution/modules/", aka
+ * ~/.local/share/evolution/modules/, into the resulting array.
+ *
+ * Returns: (element-type utf8) (transfer container): a %GPtrArray
+ * with paths to use, including the @main_path. Free it with
+ * g_ptr_array_unref(), when no longer needed.
+ *
+ * Since: 3.40
+ **/
+GPtrArray *
+camel_util_get_directory_variants (const gchar *main_path,
+ const gchar *replace_prefix,
+ gboolean with_modules_dir)
+{
+ GPtrArray *paths;
+ GHashTable *paths_hash;
+ GHashTableIter iter;
+ gpointer key;
+ gint index = 0;
+
+ g_return_val_if_fail (main_path && *main_path, NULL);
+ g_return_val_if_fail (replace_prefix && *replace_prefix, NULL);
+
+ paths_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ g_hash_table_insert (paths_hash, g_strdup (main_path), GINT_TO_POINTER (index++));
+
+ if (g_str_has_prefix (main_path, replace_prefix)) {
+ const gchar *add_path;
+ guint len = strlen (replace_prefix);
+
+ if (replace_prefix[len - 1] == G_DIR_SEPARATOR)
+ len--;
+
+ add_path = main_path + len;
+
+ if (add_path[0] == G_DIR_SEPARATOR) {
+ const gchar *env = g_getenv ("EDS_EXTRA_PREFIXES");
+
+ /* Skip the directory separator */
+ add_path++;
+
+ if (env) {
+ gchar **strv;
+ guint ii;
+
+ strv = g_strsplit (env,
+ #ifdef G_OS_WIN32
+ ";",
+ #else
+ ":",
+ #endif
+ -1);
+
+ for (ii = 0; strv && strv[ii]; ii++) {
+ const gchar *prefix = strv[ii];
+
+ if (*prefix) {
+ gchar *path = g_build_filename (prefix, add_path, NULL);
+
+ if (!path || g_hash_table_contains (paths_hash, path))
+ g_free (path);
+ else
+ g_hash_table_insert (paths_hash, path,
GINT_TO_POINTER (index++));
+ }
+ }
+
+ g_strfreev (strv);
+ }
+
+ if (with_modules_dir) {
+ gchar *path = g_build_filename (g_get_user_data_dir (), "evolution",
"modules", add_path, NULL);
+
+ if (!path || g_hash_table_contains (paths_hash, path))
+ g_free (path);
+ else
+ g_hash_table_insert (paths_hash, path, GINT_TO_POINTER (index++));
+ }
+ }
+ }
+
+ paths = g_ptr_array_new_with_free_func (g_free);
+ g_hash_table_iter_init (&iter, paths_hash);
+
+ while (g_hash_table_iter_next (&iter, &key, NULL)) {
+ g_ptr_array_add (paths, key);
+ }
+
+ g_ptr_array_sort_with_data (paths, sort_paths_by_index, paths_hash);
+
+ return paths;
+}
diff --git a/src/camel/camel.h b/src/camel/camel.h
index 3ceba1bdb..6733085be 100644
--- a/src/camel/camel.h
+++ b/src/camel/camel.h
@@ -176,6 +176,10 @@ GBinding * camel_binding_bind_property_with_closures
GBindingFlags flags,
GClosure *transform_to,
GClosure *transform_from);
+GPtrArray * camel_util_get_directory_variants
+ (const gchar *main_path,
+ const gchar *replace_prefix,
+ gboolean with_modules_dir);
G_END_DECLS
diff --git a/src/libebackend/e-dbus-server.c b/src/libebackend/e-dbus-server.c
index cf265772b..3ce8cd2b9 100644
--- a/src/libebackend/e-dbus-server.c
+++ b/src/libebackend/e-dbus-server.c
@@ -702,7 +702,7 @@ e_dbus_server_load_modules (EDBusServer *server)
G_LOCK (loaded_modules);
- list = e_module_load_all_in_directory (class->module_directory);
+ list = e_module_load_all_in_directory_and_prefixes (class->module_directory, E_DATA_SERVER_PREFIX);
for (link = list; link; link = g_list_next (link)) {
EModule *module = link->data;
diff --git a/src/libedataserver/e-data-server-util.c b/src/libedataserver/e-data-server-util.c
index 401fb3388..eb762120f 100644
--- a/src/libedataserver/e-data-server-util.c
+++ b/src/libedataserver/e-data-server-util.c
@@ -3408,3 +3408,38 @@ e_util_source_compare_for_sort (ESource *source_a,
return e_source_compare_by_display_name (source_a, source_b);
}
+
+/**
+ * e_util_get_directory_variants:
+ * @main_path: the main path to work with
+ * @replace_prefix: path prefix to replace
+ * @with_modules_dir: whether to add also the modules directory
+ *
+ * The @main_path is a directory, which will be always used. It
+ * should have as its prefix the @replace_prefix, otherwise
+ * the function returns only the @main_path in the paths array.
+ *
+ * When there's exported an environment variable EDS_EXTRA_PREFIXES,
+ * it is used as a list of alternative prefixes where to look for
+ * the @main_path (rest after the @replace_prefix).
+ *
+ * When the @with_modules_dir is %TRUE, there's also added
+ * g_get_user_data_dir() + "evolution/modules/", aka
+ * ~/.local/share/evolution/modules/, into the resulting array.
+ *
+ * Returns: (element-type utf8) (transfer container): a %GPtrArray
+ * with paths to use, including the @main_path. Free it with
+ * g_ptr_array_unref(), when no longer needed.
+ *
+ * Since: 3.40
+ **/
+GPtrArray *
+e_util_get_directory_variants (const gchar *main_path,
+ const gchar *replace_prefix,
+ gboolean with_modules_dir)
+{
+ g_return_val_if_fail (main_path && *main_path, NULL);
+ g_return_val_if_fail (replace_prefix && *replace_prefix, NULL);
+
+ return camel_util_get_directory_variants (main_path, replace_prefix, with_modules_dir);
+}
diff --git a/src/libedataserver/e-data-server-util.h b/src/libedataserver/e-data-server-util.h
index 526d8a542..797760012 100644
--- a/src/libedataserver/e-data-server-util.h
+++ b/src/libedataserver/e-data-server-util.h
@@ -295,6 +295,9 @@ gboolean e_util_can_use_collection_as_credential_source
struct _ESource *child_source);
gint e_util_source_compare_for_sort (struct _ESource *source_a,
struct _ESource *source_b);
+GPtrArray * e_util_get_directory_variants (const gchar *main_path,
+ const gchar *replace_prefix,
+ gboolean with_modules_dir);
G_END_DECLS
diff --git a/src/libedataserver/e-module.c b/src/libedataserver/e-module.c
index 690156807..0ef8270e2 100644
--- a/src/libedataserver/e-module.c
+++ b/src/libedataserver/e-module.c
@@ -25,6 +25,7 @@
#include <glib.h>
+#include "e-data-server-util.h"
#include "e-module.h"
/* This is the symbol we call when loading a module. */
@@ -337,3 +338,60 @@ e_module_load_file (const gchar *filename)
return module;
}
+
+/**
+ * e_module_load_all_in_directory_and_prefixes:
+ * @dirname: pathname for a directory containing modules to load
+ * @dirprefix: (nullable): prefix of @dirname, which can be replaced by custom prefixes, or %NULL
+ *
+ * Loads all the modules in the specified directory into memory and the other
+ * custom prefixes returned by e_util_get_directory_variants(). If
+ * you want to unload them (enabling on-demand loading) you must call
+ * g_type_module_unuse() on all the modules. Free the returned list
+ * with g_list_free().
+ *
+ * When @dirprefix is %NULL, or not a prefix of @dirname, behaves
+ * the same as e_module_load_all_in_directory().
+ *
+ * Returns: (element-type EModule) (transfer container): a list of #EModules loaded
+ * from @dirname and any extra prefix directory.
+ *
+ * Since: 3.40
+ **/
+GList *
+e_module_load_all_in_directory_and_prefixes (const gchar *dirname,
+ const gchar *dirprefix)
+{
+ GList *list = NULL;
+ GPtrArray *variants;
+ guint ii;
+
+ g_return_val_if_fail (dirname != NULL, NULL);
+
+ if (!g_module_supported ())
+ return NULL;
+
+ if (!dirprefix || !*dirprefix || !g_str_has_prefix (dirname, dirprefix))
+ return e_module_load_all_in_directory (dirname);
+
+ variants = e_util_get_directory_variants (dirname, dirprefix, TRUE);
+ if (!variants)
+ return e_module_load_all_in_directory (dirname);
+
+ for (ii = 0; ii < variants->len; ii++) {
+ const gchar *path = g_ptr_array_index (variants, ii);
+
+ if (path && *path) {
+ GList *modules;
+
+ modules = e_module_load_all_in_directory (path);
+
+ if (modules)
+ list = g_list_concat (list, modules);
+ }
+ }
+
+ g_ptr_array_unref (variants);
+
+ return list;
+}
diff --git a/src/libedataserver/e-module.h b/src/libedataserver/e-module.h
index 5e69dd831..4774d556b 100644
--- a/src/libedataserver/e-module.h
+++ b/src/libedataserver/e-module.h
@@ -73,6 +73,9 @@ EModule * e_module_new (const gchar *filename);
const gchar * e_module_get_filename (EModule *module);
EModule * e_module_load_file (const gchar *filename);
GList * e_module_load_all_in_directory (const gchar *dirname);
+GList * e_module_load_all_in_directory_and_prefixes
+ (const gchar *dirname,
+ const gchar *dirprefix);
G_END_DECLS
diff --git a/src/libedataserver/e-source-credentials-provider.c
b/src/libedataserver/e-source-credentials-provider.c
index 739d4fd94..b1ead1440 100644
--- a/src/libedataserver/e-source-credentials-provider.c
+++ b/src/libedataserver/e-source-credentials-provider.c
@@ -133,7 +133,7 @@ source_credentials_provider_constructed (GObject *object)
modules_loaded = TRUE;
- module_types = e_module_load_all_in_directory (E_DATA_SERVER_CREDENTIALMODULEDIR);
+ module_types = e_module_load_all_in_directory_and_prefixes
(E_DATA_SERVER_CREDENTIALMODULEDIR, E_DATA_SERVER_PREFIX);
g_list_free_full (module_types, (GDestroyNotify) g_type_module_unuse);
}
diff --git a/src/libedataserverui/CMakeLists.txt b/src/libedataserverui/CMakeLists.txt
index 468730436..63f594fbe 100644
--- a/src/libedataserverui/CMakeLists.txt
+++ b/src/libedataserverui/CMakeLists.txt
@@ -51,6 +51,7 @@ set_target_properties(edataserverui PROPERTIES
target_compile_definitions(edataserverui PRIVATE
-DG_LOG_DOMAIN=\"e-data-server-ui\"
-DLIBEDATASERVERUI_COMPILATION
+ -DE_DATA_SERVER_PREFIX=\"${CMAKE_INSTALL_PREFIX}\"
-DE_DATA_SERVER_UIMODULEDIR=\"${uimoduledir}\"
)
diff --git a/src/libedataserverui/libedataserverui-private.c b/src/libedataserverui/libedataserverui-private.c
index 83cb41459..847d34e31 100644
--- a/src/libedataserverui/libedataserverui-private.c
+++ b/src/libedataserverui/libedataserverui-private.c
@@ -43,7 +43,7 @@ _libedataserverui_load_modules (void)
modules_loaded = TRUE;
- module_types = e_module_load_all_in_directory (E_DATA_SERVER_UIMODULEDIR);
+ module_types = e_module_load_all_in_directory_and_prefixes (E_DATA_SERVER_UIMODULEDIR,
E_DATA_SERVER_PREFIX);
g_list_free_full (module_types, (GDestroyNotify) g_type_module_unuse);
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]