mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 23:16:14 +01:00
gutils: Add internal API to override XDG directories
Add a new internal function, g_set_user_dirs(), which will safely override the values returned by g_get_user_data_dir() and friends, and the value returned by g_get_home_dir(). This is intended to be used by unit tests, and will be hooked up to them in a following commit. This can be called as many times as needed by the current process. It’s thread-safe. It does not modify the environment, so none of the changes are propagated to any subsequently spawned subprocesses. Signed-off-by: Philip Withnall <withnall@endlessm.com> https://gitlab.gnome.org/GNOME/glib/issues/538
This commit is contained in:
parent
b87dfb4960
commit
91defdb34e
@ -64,6 +64,7 @@ IGNORE_HFILES = \
|
|||||||
glib-init.h \
|
glib-init.h \
|
||||||
gconstructor.h \
|
gconstructor.h \
|
||||||
valgrind.h \
|
valgrind.h \
|
||||||
|
gutilsprivate.h \
|
||||||
gvalgrind.h \
|
gvalgrind.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ if get_option('gtk_doc')
|
|||||||
'glib-init.h',
|
'glib-init.h',
|
||||||
'gconstructor.h',
|
'gconstructor.h',
|
||||||
'valgrind.h',
|
'valgrind.h',
|
||||||
|
'gutilsprivate.h',
|
||||||
'gvalgrind.h',
|
'gvalgrind.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
20
glib.supp
20
glib.supp
@ -544,6 +544,26 @@
|
|||||||
fun:g_object_new_valist
|
fun:g_object_new_valist
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# g_set_user_dirs() deliberately leaks the previous cached g_get_user_*() values.
|
||||||
|
{
|
||||||
|
g_set_user_dirs_str
|
||||||
|
Memcheck:Leak
|
||||||
|
fun:malloc
|
||||||
|
...
|
||||||
|
fun:set_str_if_different
|
||||||
|
fun:g_set_user_dirs
|
||||||
|
}
|
||||||
|
|
||||||
|
# g_set_user_dirs() deliberately leaks the previous cached g_get_user_*() values.
|
||||||
|
{
|
||||||
|
g_set_user_dirs_strv
|
||||||
|
Memcheck:Leak
|
||||||
|
fun:malloc
|
||||||
|
...
|
||||||
|
fun:set_strv_if_different
|
||||||
|
fun:g_set_user_dirs
|
||||||
|
}
|
||||||
|
|
||||||
# g_get_system_data_dirs() caches a one-time allocation
|
# g_get_system_data_dirs() caches a one-time allocation
|
||||||
{
|
{
|
||||||
g_get_system_data_dirs
|
g_get_system_data_dirs
|
||||||
|
@ -191,6 +191,7 @@ libglib_2_0_la_SOURCES = \
|
|||||||
gunicodeprivate.h \
|
gunicodeprivate.h \
|
||||||
gurifuncs.c \
|
gurifuncs.c \
|
||||||
gutils.c \
|
gutils.c \
|
||||||
|
gutilsprivate.h \
|
||||||
guuid.c \
|
guuid.c \
|
||||||
gvalgrind.h \
|
gvalgrind.h \
|
||||||
gvariant.h \
|
gvariant.h \
|
||||||
|
108
glib/gutils.c
108
glib/gutils.c
@ -29,6 +29,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "gutils.h"
|
#include "gutils.h"
|
||||||
|
#include "gutilsprivate.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -1177,6 +1178,113 @@ g_set_application_name (const gchar *application_name)
|
|||||||
g_warning ("g_set_application_name() called multiple times");
|
g_warning ("g_set_application_name() called multiple times");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set @global_str to a copy of @new_value if it’s currently unset or has a
|
||||||
|
* different value. If its current value matches @new_value, do nothing. If
|
||||||
|
* replaced, we have to leak the old value as client code could still have
|
||||||
|
* pointers to it. */
|
||||||
|
static void
|
||||||
|
set_str_if_different (gchar **global_str,
|
||||||
|
const gchar *type,
|
||||||
|
const gchar *new_value)
|
||||||
|
{
|
||||||
|
if (*global_str == NULL ||
|
||||||
|
!g_str_equal (new_value, *global_str))
|
||||||
|
{
|
||||||
|
g_debug ("g_set_user_dirs: Setting %s to %s", type, new_value);
|
||||||
|
|
||||||
|
/* We have to leak the old value, as user code could be retaining pointers
|
||||||
|
* to it. */
|
||||||
|
*global_str = g_strdup (new_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_strv_if_different (gchar ***global_strv,
|
||||||
|
const gchar *type,
|
||||||
|
const gchar * const *new_value)
|
||||||
|
{
|
||||||
|
if (*global_strv == NULL ||
|
||||||
|
!g_strv_equal (new_value, (const gchar * const *) *global_strv))
|
||||||
|
{
|
||||||
|
gchar *new_value_str = g_strjoinv (":", (gchar **) new_value);
|
||||||
|
g_debug ("g_set_user_dirs: Setting %s to %s", type, new_value_str);
|
||||||
|
g_free (new_value_str);
|
||||||
|
|
||||||
|
/* We have to leak the old value, as user code could be retaining pointers
|
||||||
|
* to it. */
|
||||||
|
*global_strv = g_strdupv ((gchar **) new_value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* g_set_user_dirs:
|
||||||
|
* @first_dir_type: Type of the first directory to set
|
||||||
|
* @...: Value to set the first directory to, followed by additional type/value
|
||||||
|
* pairs, followed by %NULL
|
||||||
|
*
|
||||||
|
* Set one or more ‘user’ directories to custom values. This is intended to be
|
||||||
|
* used by test code (particularly with the %G_TEST_OPTION_ISOLATE_DIRS option)
|
||||||
|
* to override the values returned by the following functions, so that test
|
||||||
|
* code can be run without touching an installed system and user data:
|
||||||
|
*
|
||||||
|
* - g_get_home_dir() — use type `HOME`, pass a string
|
||||||
|
* - g_get_user_cache_dir() — use type `XDG_CACHE_HOME`, pass a string
|
||||||
|
* - g_get_system_config_dirs() — use type `XDG_CONFIG_DIRS`, pass a
|
||||||
|
* %NULL-terminated string array
|
||||||
|
* - g_get_user_config_dir() — use type `XDG_CONFIG_HOME`, pass a string
|
||||||
|
* - g_get_system_data_dirs() — use type `XDG_DATA_DIRS`, pass a
|
||||||
|
* %NULL-terminated string array
|
||||||
|
* - g_get_user_data_dir() — use type `XDG_DATA_HOME`, pass a string
|
||||||
|
* - g_get_user_runtime_dir() — use type `XDG_RUNTIME_DIR`, pass a string
|
||||||
|
*
|
||||||
|
* The list must be terminated with a %NULL type. All of the values must be
|
||||||
|
* non-%NULL — passing %NULL as a value won’t reset a directory. If a reference
|
||||||
|
* to a directory from the calling environment needs to be kept, copy it before
|
||||||
|
* the first call to g_set_user_dirs(). g_set_user_dirs() can be called multiple
|
||||||
|
* times.
|
||||||
|
*
|
||||||
|
* Since: 2.60
|
||||||
|
*/
|
||||||
|
/*< private > */
|
||||||
|
void
|
||||||
|
g_set_user_dirs (const gchar *first_dir_type,
|
||||||
|
...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
const gchar *dir_type;
|
||||||
|
|
||||||
|
G_LOCK (g_utils_global);
|
||||||
|
|
||||||
|
va_start (args, first_dir_type);
|
||||||
|
|
||||||
|
for (dir_type = first_dir_type; dir_type != NULL; dir_type = va_arg (args, const gchar *))
|
||||||
|
{
|
||||||
|
gconstpointer dir_value = va_arg (args, gconstpointer);
|
||||||
|
g_assert (dir_value != NULL);
|
||||||
|
|
||||||
|
if (g_str_equal (dir_type, "HOME"))
|
||||||
|
set_str_if_different (&g_home_dir, dir_type, dir_value);
|
||||||
|
else if (g_str_equal (dir_type, "XDG_CACHE_HOME"))
|
||||||
|
set_str_if_different (&g_user_cache_dir, dir_type, dir_value);
|
||||||
|
else if (g_str_equal (dir_type, "XDG_CONFIG_DIRS"))
|
||||||
|
set_strv_if_different (&g_system_config_dirs, dir_type, dir_value);
|
||||||
|
else if (g_str_equal (dir_type, "XDG_CONFIG_HOME"))
|
||||||
|
set_str_if_different (&g_user_config_dir, dir_type, dir_value);
|
||||||
|
else if (g_str_equal (dir_type, "XDG_DATA_DIRS"))
|
||||||
|
set_strv_if_different (&g_system_data_dirs, dir_type, dir_value);
|
||||||
|
else if (g_str_equal (dir_type, "XDG_DATA_HOME"))
|
||||||
|
set_str_if_different (&g_user_data_dir, dir_type, dir_value);
|
||||||
|
else if (g_str_equal (dir_type, "XDG_RUNTIME_DIR"))
|
||||||
|
set_str_if_different (&g_user_runtime_dir, dir_type, dir_value);
|
||||||
|
else
|
||||||
|
g_assert_not_reached ();
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end (args);
|
||||||
|
|
||||||
|
G_UNLOCK (g_utils_global);
|
||||||
|
}
|
||||||
|
|
||||||
static gchar *
|
static gchar *
|
||||||
g_build_user_data_dir (void)
|
g_build_user_data_dir (void)
|
||||||
{
|
{
|
||||||
|
33
glib/gutilsprivate.h
Normal file
33
glib/gutilsprivate.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2018 Endless Mobile, Inc.
|
||||||
|
*
|
||||||
|
* 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, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Author: Philip Withnall <withnall@endlessm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __G_UTILS_PRIVATE_H__
|
||||||
|
#define __G_UTILS_PRIVATE_H__
|
||||||
|
|
||||||
|
#include "gtypes.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
GLIB_AVAILABLE_IN_2_60
|
||||||
|
void g_set_user_dirs (const gchar *first_dir_type,
|
||||||
|
...) G_GNUC_NULL_TERMINATED;
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __G_UTILS_PRIVATE_H__ */
|
@ -199,6 +199,7 @@ glib_sources = files(
|
|||||||
'gunidecomp.c',
|
'gunidecomp.c',
|
||||||
'gurifuncs.c',
|
'gurifuncs.c',
|
||||||
'gutils.c',
|
'gutils.c',
|
||||||
|
'gutilsprivate.h',
|
||||||
'guuid.c',
|
'guuid.c',
|
||||||
'gvariant.c',
|
'gvariant.c',
|
||||||
'gvariant-core.c',
|
'gvariant-core.c',
|
||||||
|
Loading…
Reference in New Issue
Block a user