diff options
author | Milan Crha <mcrha@redhat.com> | 2021-06-15 12:21:45 +0200 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2021-06-15 12:26:24 +0200 |
commit | bd7521bdde6a3428d492514f6482fcd9ba2812d9 (patch) | |
tree | 7e6c27b714d347cfa5aeb1882e135ee91f1c490e | |
parent | 8fe6b91030715c05afdf0b46526ad659cdfbc06c (diff) | |
download | evolution-bd7521bdde6a3428d492514f6482fcd9ba2812d9.tar.gz |
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
-rw-r--r-- | src/modules/backup-restore/evolution-backup-tool.c | 283 |
1 files changed, 260 insertions, 23 deletions
diff --git a/src/modules/backup-restore/evolution-backup-tool.c b/src/modules/backup-restore/evolution-backup-tool.c index f490790de3..4ae4c366d0 100644 --- a/src/modules/backup-restore/evolution-backup-tool.c +++ b/src/modules/backup-restore/evolution-backup-tool.c @@ -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); - - replace_in_file ( - EVOLUTION_DIR DCONF_DUMP_FILE_EDS, - e_get_user_data_dir (), EVOUSERDATADIR_MAGIC); + 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_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); - - 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); + if (file) + g_string_free (file, TRUE); + + 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; |