I#1307 - backup-restore: Handle user settings through GSettings, not DConf

This helps to save user settings when running as Flatpak, where the `dconf`
command line tool is not available (and where the GSettings can work with
any backend, not only with the DConf backend).

Closes https://gitlab.gnome.org/GNOME/evolution/-/issues/1307
This commit is contained in:
Milan Crha
2021-06-15 12:21:45 +02:00
parent 474e562155
commit 643224f937

View File

@ -45,11 +45,13 @@
#define ANCIENT_GCONF_DUMP_FILE "backup-restore-gconf.xml"
#define DCONF_DUMP_FILE_EDS "backup-restore-dconf-eds.ini"
#define DCONF_DUMP_FILE_EVO "backup-restore-dconf-evo.ini"
#define ANCIENT_DCONF_DUMP_FILE_EDS "backup-restore-dconf-eds.ini"
#define ANCIENT_DCONF_DUMP_FILE_EVO "backup-restore-dconf-evo.ini"
#define DCONF_PATH_EDS "/org/gnome/evolution-data-server/"
#define DCONF_PATH_EVO "/org/gnome/evolution/"
#define ANCIENT_DCONF_PATH_EDS "/org/gnome/evolution-data-server/"
#define ANCIENT_DCONF_PATH_EVO "/org/gnome/evolution/"
#define GSETTINGS_DUMP_FILE "backup-restore-gsettings.ini"
#define KEY_FILE_GROUP "Evolution Backup"
@ -277,6 +279,226 @@ get_filename_is_xz (const gchar *filename)
return g_ascii_strcasecmp (filename + len - 3, ".xz") == 0;
}
typedef gboolean (* SettingsFunc) (GSettings *settings,
GSettingsSchema *schema,
const gchar *group,
const gchar *key,
GKeyFile *keyfile);
static gboolean
settings_foreach_schema_traverse (GSettings *settings,
SettingsFunc func,
GKeyFile *keyfile)
{
GSettingsSchema *schema = NULL;
const gchar *group;
gchar *schema_id = NULL, *path = NULL, *group_tmp = NULL;
gchar **strv;
gint ii;
gboolean need_sync = FALSE;
g_object_get (G_OBJECT (settings),
"settings-schema", &schema,
"schema-id", &schema_id,
"path", &path,
NULL);
if (!g_settings_schema_get_path (schema)) {
group_tmp = g_strconcat (schema_id, ":", path, NULL);
group = group_tmp;
} else {
group = schema_id;
}
strv = g_settings_schema_list_keys (schema);
for (ii = 0; strv && strv[ii]; ii++) {
need_sync = func (settings, schema, group, strv[ii], keyfile) || need_sync;
}
g_strfreev (strv);
strv = g_settings_schema_list_children (schema);
for (ii = 0; strv && strv[ii]; ii++) {
GSettings *child;
child = g_settings_get_child (settings, strv[ii]);
if (child) {
if (settings_foreach_schema_traverse (child, func, keyfile))
g_settings_sync ();
g_object_unref (child);
}
}
g_strfreev (strv);
g_settings_schema_unref (schema);
g_free (group_tmp);
g_free (schema_id);
g_free (path);
return need_sync;
}
static gboolean
settings_foreach_schema (SettingsFunc func,
GKeyFile *keyfile,
GError **error)
{
GSettingsSchemaSource *schema_source;
gchar **non_relocatable = NULL, **relocatable = NULL;
gint ii;
schema_source = g_settings_schema_source_get_default ();
if (!schema_source) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No GSettings schema found");
return FALSE;
}
g_settings_schema_source_list_schemas (schema_source, TRUE, &non_relocatable, &relocatable);
for (ii = 0; non_relocatable && non_relocatable[ii]; ii++) {
if (g_str_has_prefix (non_relocatable[ii], "org.gnome.evolution")) {
GSettings *settings;
settings = g_settings_new (non_relocatable[ii]);
if (settings_foreach_schema_traverse (settings, func, keyfile))
g_settings_sync ();
g_object_unref (settings);
}
}
g_strfreev (non_relocatable);
g_strfreev (relocatable);
return TRUE;
}
static gboolean
backup_settings_foreach_cb (GSettings *settings,
GSettingsSchema *schema,
const gchar *group,
const gchar *key,
GKeyFile *keyfile)
{
GVariant *variant;
variant = g_settings_get_user_value (settings, key);
if (variant) {
gchar *tmp;
tmp = g_variant_print (variant, TRUE);
g_key_file_set_string (keyfile, group, key, tmp);
g_free (tmp);
g_variant_unref (variant);
}
return FALSE;
}
static gboolean
backup_settings (const gchar *to_filename,
GError **error)
{
GKeyFile *keyfile;
GString *filename;
gboolean success;
filename = replace_variables (to_filename, TRUE);
if (!filename) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to construct file name");
return FALSE;
}
keyfile = g_key_file_new ();
if (!settings_foreach_schema (backup_settings_foreach_cb, keyfile, error)) {
g_string_free (filename, TRUE);
g_key_file_free (keyfile);
return FALSE;
}
success = g_key_file_save_to_file (keyfile, filename->str, error);
g_string_free (filename, TRUE);
g_key_file_free (keyfile);
return success;
}
static gboolean
restore_settings_foreach_cb (GSettings *settings,
GSettingsSchema *schema,
const gchar *group,
const gchar *key,
GKeyFile *keyfile)
{
gchar *value;
if (!g_settings_is_writable (settings, key))
return FALSE;
value = g_key_file_get_string (keyfile, group, key, NULL);
if (value) {
GVariant *variant;
variant = g_variant_parse (NULL, value, NULL, NULL, NULL);
if (variant) {
GSettingsSchemaKey *schema_key;
schema_key = g_settings_schema_get_key (schema, key);
if (g_settings_schema_key_range_check (schema_key, variant))
g_settings_set_value (settings, key, variant);
g_settings_schema_key_unref (schema_key);
g_variant_unref (variant);
}
g_free (value);
} else {
g_settings_reset (settings, key);
}
return TRUE;
}
static gboolean
restore_settings (const gchar *from_filename,
GError **error)
{
GKeyFile *keyfile;
GString *filename;
gboolean success;
filename = replace_variables (from_filename, TRUE);
if (!filename) {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to construct file name");
return FALSE;
}
keyfile = g_key_file_new ();
if (!g_key_file_load_from_file (keyfile, filename->str, G_KEY_FILE_NONE, error)) {
g_string_free (filename, TRUE);
g_key_file_free (keyfile);
return FALSE;
}
success = settings_foreach_schema (restore_settings_foreach_cb, keyfile, error);
g_string_free (filename, TRUE);
g_key_file_free (keyfile);
return success;
}
static void
backup (const gchar *filename,
GCancellable *cancellable)
@ -284,6 +506,7 @@ backup (const gchar *filename,
gchar *command;
gchar *quotedfname;
gboolean use_xz;
GError *error = NULL;
g_return_if_fail (filename && *filename);
@ -300,15 +523,13 @@ backup (const gchar *filename,
return;
txt = _("Backing Evolution accounts and settings");
run_cmd ("dconf dump " DCONF_PATH_EDS " >" EVOLUTION_DIR DCONF_DUMP_FILE_EDS);
run_cmd ("dconf dump " DCONF_PATH_EVO " >" EVOLUTION_DIR DCONF_DUMP_FILE_EVO);
if (!backup_settings (EVOLUTION_DIR GSETTINGS_DUMP_FILE, &error)) {
g_warning ("Failed to backup settings: %s", error ? error->message : "Unknown error");
g_clear_error (&error);
}
replace_in_file (
EVOLUTION_DIR DCONF_DUMP_FILE_EDS,
e_get_user_data_dir (), EVOUSERDATADIR_MAGIC);
replace_in_file (
EVOLUTION_DIR DCONF_DUMP_FILE_EVO,
EVOLUTION_DIR GSETTINGS_DUMP_FILE,
e_get_user_data_dir (), EVOUSERDATADIR_MAGIC);
write_dir_file ();
@ -677,20 +898,36 @@ restore (const gchar *filename,
run_cmd ("gsettings-data-convert");
run_cmd ("rm " EVOLUTION_DIR ANCIENT_GCONF_DUMP_FILE);
} else {
replace_in_file (
EVOLUTION_DIR DCONF_DUMP_FILE_EDS,
EVOUSERDATADIR_MAGIC, e_get_user_data_dir ());
run_cmd ("cat " EVOLUTION_DIR DCONF_DUMP_FILE_EDS " | dconf load " DCONF_PATH_EDS);
run_cmd ("rm " EVOLUTION_DIR DCONF_DUMP_FILE_EDS);
if (file)
g_string_free (file, TRUE);
replace_in_file (
EVOLUTION_DIR DCONF_DUMP_FILE_EVO,
EVOUSERDATADIR_MAGIC, e_get_user_data_dir ());
run_cmd ("cat " EVOLUTION_DIR DCONF_DUMP_FILE_EVO " | dconf load " DCONF_PATH_EVO);
run_cmd ("rm " EVOLUTION_DIR DCONF_DUMP_FILE_EVO);
file = replace_variables (EVOLUTION_DIR ANCIENT_DCONF_DUMP_FILE_EDS, TRUE);
if (file && g_file_test (file->str, G_FILE_TEST_EXISTS)) {
replace_in_file (
EVOLUTION_DIR ANCIENT_DCONF_DUMP_FILE_EDS,
EVOUSERDATADIR_MAGIC, e_get_user_data_dir ());
run_cmd ("cat " EVOLUTION_DIR ANCIENT_DCONF_DUMP_FILE_EDS " | dconf load " ANCIENT_DCONF_PATH_EDS);
run_cmd ("rm " EVOLUTION_DIR ANCIENT_DCONF_DUMP_FILE_EDS);
replace_in_file (
EVOLUTION_DIR ANCIENT_DCONF_DUMP_FILE_EVO,
EVOUSERDATADIR_MAGIC, e_get_user_data_dir ());
run_cmd ("cat " EVOLUTION_DIR ANCIENT_DCONF_DUMP_FILE_EVO " | dconf load " ANCIENT_DCONF_PATH_EVO);
run_cmd ("rm " EVOLUTION_DIR ANCIENT_DCONF_DUMP_FILE_EVO);
} else {
GError *error = NULL;
if (!restore_settings (EVOLUTION_DIR GSETTINGS_DUMP_FILE, &error)) {
g_warning ("Failed to restore settings: %s", error ? error->message : "Unknown error");
g_clear_error (&error);
}
run_cmd ("rm " EVOLUTION_DIR GSETTINGS_DUMP_FILE);
}
}
g_string_free (file, TRUE);
if (file)
g_string_free (file, TRUE);
} else {
gchar *gconf_dump_file;