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



commit 643224f937395db0133cb17b8f38fa9428c46f5e
Author: Milan Crha <mcrha redhat com>
Date:   Tue Jun 15 12:21:45 2021 +0200

    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

 src/modules/backup-restore/evolution-backup-tool.c | 283 +++++++++++++++++++--
 1 file 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;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]