gcontenttype: Add g_content_type_{get,set}_mime_dirs() API

This allows the list of directories which contain MIME data to be set,
separately from the list of directories returned by
g_get_user_data_home() and g_get_system_data_dirs().

While the latter are overridden for a unit test, we don’t have access to
the system MIME registry, which can sometimes be useful for tests which
need to know about standard MIME associations from shared-mime-info.

Allow g_content_type_set_mime_dirs() to be used from unit tests to allow
them to use the system MIME registry again, or to allow them to be
pointed to another custom registry.

Signed-off-by: Philip Withnall <withnall@endlessm.com>
This commit is contained in:
Philip Withnall 2018-12-13 16:55:48 +00:00
parent df2f13f89b
commit b06fa34bb1
2 changed files with 129 additions and 30 deletions

View File

@ -55,6 +55,8 @@
#define XDG_PREFIX _gio_xdg
#include "xdgmime/xdgmime.h"
static void tree_magic_schedule_reload (void);
/* We lock this mutex whenever we modify global state in this module. */
G_LOCK_DEFINE_STATIC (gio_xdgmime);
@ -111,6 +113,106 @@ _g_unix_content_type_get_parents (const gchar *type)
return (gchar **)g_ptr_array_free (array, FALSE);
}
G_LOCK_DEFINE_STATIC (global_mime_dirs);
static gchar **global_mime_dirs = NULL;
static void
_g_content_type_set_mime_dirs_locked (const char * const *dirs)
{
g_clear_pointer (&global_mime_dirs, g_strfreev);
if (dirs != NULL)
{
global_mime_dirs = g_strdupv ((gchar **) dirs);
}
else
{
GPtrArray *mime_dirs = g_ptr_array_new_with_free_func (g_free);
const gchar * const *system_dirs = g_get_system_data_dirs ();
g_ptr_array_add (mime_dirs, g_build_filename (g_get_user_data_dir (), "mime", NULL));
for (; *system_dirs != NULL; system_dirs++)
g_ptr_array_add (mime_dirs, g_build_filename (*system_dirs, "mime", NULL));
g_ptr_array_add (mime_dirs, NULL); /* NULL terminator */
global_mime_dirs = (gchar **) g_ptr_array_free (mime_dirs, FALSE);
}
xdg_mime_set_dirs ((const gchar * const *) global_mime_dirs);
tree_magic_schedule_reload ();
}
/**
* g_content_type_set_mime_dirs:
* @dirs: (array zero-terminated=1) (nullable): %NULL-terminated list of
* directories to load MIME data from, including any `mime/` subdirectory,
* and with the first directory to try listed first
*
* Set the list of directories used by GIO to load the MIME database.
* If @dirs is %NULL, the directories used are the default:
*
* - the `mime` subdirectory of the directory in `$XDG_DATA_HOME`
* - the `mime` subdirectory of every directory in `$XDG_DATA_DIRS`
*
* This function is intended to be used when writing tests that depend on
* information stored in the MIME database, in order to control the data.
*
* Typically, in case your tests use %G_TEST_OPTION_ISOLATE_DIRS, but they
* depend on the systems MIME database, you should call this function
* with @dirs set to %NULL before calling g_test_init(), for instance:
*
* |[<!-- language="C" -->
* // Load MIME data from the system
* g_content_type_set_mime_dirs (NULL);
* // Isolate the environment
* g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
*
*
*
* return g_test_run ();
* ]|
*
* Since: 2.60
*/
/*< private >*/
void
g_content_type_set_mime_dirs (const gchar * const *dirs)
{
G_LOCK (global_mime_dirs);
_g_content_type_set_mime_dirs_locked (dirs);
G_UNLOCK (global_mime_dirs);
}
/**
* g_content_type_get_mime_dirs:
*
* Get the list of directories which MIME data is loaded from. See
* g_content_type_set_mime_dirs() for details.
*
* Returns: (transfer none) (array zero-terminated=1): %NULL-terminated list of
* directories to load MIME data from, including any `mime/` subdirectory,
* and with the first directory to try listed first
* Since: 2.60
*/
/*< private >*/
const gchar * const *
g_content_type_get_mime_dirs (void)
{
const gchar * const *mime_dirs;
G_LOCK (global_mime_dirs);
if (global_mime_dirs == NULL)
_g_content_type_set_mime_dirs_locked (NULL);
mime_dirs = (const gchar * const *) global_mime_dirs;
G_UNLOCK (global_mime_dirs);
g_assert (mime_dirs != NULL);
return mime_dirs;
}
/**
* g_content_type_equals:
* @type1: a content type string
@ -306,7 +408,7 @@ load_comment_for_mime_helper (const char *dir,
mime_info_text
};
filename = g_build_filename (dir, "mime", basename, NULL);
filename = g_build_filename (dir, basename, NULL);
res = g_file_get_contents (filename, &data, &len, NULL);
g_free (filename);
@ -328,22 +430,14 @@ load_comment_for_mime_helper (const char *dir,
static char *
load_comment_for_mime (const char *mimetype)
{
const char * const* dirs;
const char * const *dirs;
char *basename;
char *comment;
int i;
gsize i;
basename = g_strdup_printf ("%s.xml", mimetype);
comment = load_comment_for_mime_helper (g_get_user_data_dir (), basename);
if (comment)
{
g_free (basename);
return comment;
}
dirs = g_get_system_data_dirs ();
dirs = g_content_type_get_mime_dirs ();
for (i = 0; dirs[i] != NULL; i++)
{
comment = load_comment_for_mime_helper (dirs[i], basename);
@ -780,10 +874,10 @@ enumerate_mimetypes_dir (const char *dir,
{
DIR *d;
struct dirent *ent;
char *mimedir;
const char *mimedir;
char *name;
mimedir = g_build_filename (dir, "mime", NULL);
mimedir = dir;
d = opendir (mimedir);
if (d)
@ -800,8 +894,6 @@ enumerate_mimetypes_dir (const char *dir,
}
closedir (d);
}
g_free (mimedir);
}
/**
@ -817,18 +909,16 @@ enumerate_mimetypes_dir (const char *dir,
GList *
g_content_types_get_registered (void)
{
const char * const* dirs;
const char * const *dirs;
GHashTable *mimetypes;
GHashTableIter iter;
gpointer key;
int i;
gsize i;
GList *l;
mimetypes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
enumerate_mimetypes_dir (g_get_user_data_dir (), mimetypes);
dirs = g_get_system_data_dirs ();
dirs = g_content_type_get_mime_dirs ();
for (i = 0; dirs[i] != NULL; i++)
enumerate_mimetypes_dir (dirs[i], mimetypes);
@ -1030,7 +1120,7 @@ read_tree_magic_from_directory (const gchar *prefix)
TreeMatchlet *matchlet;
gint depth;
filename = g_build_filename (prefix, "mime", "treemagic", NULL);
filename = g_build_filename (prefix, "treemagic", NULL);
if (g_file_get_contents (filename, &text, &len, NULL))
{
@ -1068,11 +1158,16 @@ read_tree_magic_from_directory (const gchar *prefix)
g_free (filename);
}
static void
tree_magic_schedule_reload (void)
{
need_reload = TRUE;
}
static void
xdg_mime_reload (void *user_data)
{
need_reload = TRUE;
tree_magic_schedule_reload ();
}
static void
@ -1086,9 +1181,7 @@ static void
tree_magic_init (void)
{
static gboolean initialized = FALSE;
const gchar *dir;
const gchar * const * dirs;
int i;
gsize i;
if (!initialized)
{
@ -1100,14 +1193,14 @@ tree_magic_init (void)
if (need_reload)
{
const char * const *dirs;
need_reload = FALSE;
tree_magic_shutdown ();
dir = g_get_user_data_dir ();
read_tree_magic_from_directory (dir);
dirs = g_get_system_data_dirs ();
for (i = 0; dirs[i]; i++)
dirs = g_content_type_get_mime_dirs ();
for (i = 0; dirs[i] != NULL; i++)
read_tree_magic_from_directory (dirs[i]);
}
}

View File

@ -69,6 +69,12 @@ gchar ** g_content_type_guess_for_tree (GFile *root);
GLIB_AVAILABLE_IN_ALL
GList * g_content_types_get_registered (void);
/*< private >*/
GLIB_AVAILABLE_IN_2_60
const gchar * const *g_content_type_get_mime_dirs (void);
GLIB_AVAILABLE_IN_2_60
void g_content_type_set_mime_dirs (const gchar * const *dirs);
G_END_DECLS
#endif /* __G_CONTENT_TYPE_H__ */