[devhelp/wip/devhelp-next: 1/2] gsettings: implement DhDconfMigration utility class



commit bceb2907398241af6e90ad8fa8fa729310f7fe68
Author: Sébastien Wilmet <swilmet gnome org>
Date:   Fri Mar 9 12:32:38 2018 +0100

    gsettings: implement DhDconfMigration utility class
    
    I was interested to know how to best handle GSettings in a library
    (especially in a library which often bumps its major version). Even if
    in the end that utility class won't be used in libdevhelp directly,
    it'll anyway be useful for the LaTeXila -> GNOME LaTeX project rename.

 devhelp/future/README               |    4 +
 devhelp/future/dh-dconf-migration.c |  140 +++++++++++++++++++++++++++++++++++
 devhelp/future/dh-dconf-migration.h |   42 +++++++++++
 docs/reference/Makefile.am          |    1 +
 4 files changed, 187 insertions(+), 0 deletions(-)
---
diff --git a/devhelp/future/README b/devhelp/future/README
new file mode 100644
index 0000000..55a6d14
--- /dev/null
+++ b/devhelp/future/README
@@ -0,0 +1,4 @@
+For the future. The code in this directory is not compiled (but has been tested
+when written of course). Instead of the code bit-rotting in a forgotten branch,
+have the code on git master to ensure to have a backup. And elsewhere in the
+git repo, be able to make references to the experiments done here.
diff --git a/devhelp/future/dh-dconf-migration.c b/devhelp/future/dh-dconf-migration.c
new file mode 100644
index 0000000..fae9bfa
--- /dev/null
+++ b/devhelp/future/dh-dconf-migration.c
@@ -0,0 +1,140 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2018 Sébastien Wilmet <swilmet gnome org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dh-dconf-migration.h"
+#include <dconf.h>
+
+/* #DhDconfMigration is a utility class to copy the value of dconf keys from old
+ * paths to new paths.
+ *
+ * You'll probably need to add a "migration-done" #GSettings key to know if the
+ * migration has already been done or not (either with a boolean, or an integer
+ * if you plan to have other migrations in the future).
+ *
+ * Use-case examples:
+ * - When a project is renamed. The old #GSettings schema may no longer be
+ *   installed, so it is not possible to use the #GSettings API to retrieve the
+ *   values at the old locations. But the values are still stored in the dconf
+ *   database.
+ * - Be able to do refactorings in the #GSettings schema without users losing
+ *   their settings when *upgrading* to a new version (doesn't work when
+ *   downgrading).
+ * - When a library uses #GSettings, with parallel-installability for different
+ *   major versions, each major version provides a different #GSettings schema,
+ *   but when upgrading to a new major version we don't want all the users to
+ *   lose their settings. An alternative is for the library to install only
+ *   relocatable schemas, relocated to an old common path (if all the keys of
+ *   that schema are still compatible). When a schema (or sub-schema) becomes
+ *   incompatible, the compatible keys can be migrated individually with
+ *   #DhDconfMigration.
+ */
+
+/* Tested inside a Flatpak sandbox, works fine. */
+
+struct _DhDconfMigration {
+        DConfClient *client;
+};
+
+DhDconfMigration *
+_dh_dconf_migration_new (void)
+{
+        DhDconfMigration *migration;
+
+        migration = g_new0 (DhDconfMigration, 1);
+        migration->client = dconf_client_new ();
+
+        return migration;
+}
+
+void
+_dh_dconf_migration_free (DhDconfMigration *migration)
+{
+        if (migration == NULL)
+                return;
+
+        dconf_client_sync (migration->client);
+
+        g_object_unref (migration->client);
+        g_free (migration);
+}
+
+/*
+ * _dh_dconf_migration_migrate_key:
+ * @migration: a #DhDconfMigration.
+ * @new_key_path: the dconf path to the new key.
+ * @first_old_key_path: the dconf path to the first old key.
+ * @...: %NULL-terminated list of strings containing the dconf paths to the old
+ *   keys (usually from most recent to the oldest).
+ *
+ * Copies a value from an old path to a new path. The values on the old paths
+ * are not reset, it is just a copy.
+ *
+ * The function loops on the old key paths, in the same order as provided; as
+ * soon as an old key contains a value, that value is copied to @new_key_path
+ * and the function returns. Which means that, usually, all the keys must be
+ * provided in reverse chronological order.
+ */
+void
+_dh_dconf_migration_migrate_key (DhDconfMigration *migration,
+                                 const gchar      *new_key_path,
+                                 const gchar      *first_old_key_path,
+                                 ...)
+{
+        va_list old_key_paths;
+        GVariant *value;
+
+        g_return_if_fail (migration != NULL);
+        g_return_if_fail (new_key_path != NULL);
+        g_return_if_fail (first_old_key_path != NULL);
+
+        va_start (old_key_paths, first_old_key_path);
+
+        value = dconf_client_read (migration->client, first_old_key_path);
+
+        while (value == NULL) {
+                const gchar *next_old_key_path;
+
+                next_old_key_path = va_arg (old_key_paths, const gchar *);
+                if (next_old_key_path == NULL)
+                        break;
+
+                value = dconf_client_read (migration->client, next_old_key_path);
+        }
+
+        if (value != NULL) {
+                GError *error = NULL;
+
+                /* The GVariant type is not checked against the new GSettings
+                 * schema. If we write a value with an incompatible type by
+                 * mistake, no problem, GSettings will take the default value
+                 * from the schema (without printing a warning).
+                 */
+                dconf_client_write_fast (migration->client, new_key_path, value, &error);
+
+                if (error != NULL) {
+                        g_warning ("Error when migrating dconf key %s: %s",
+                                   new_key_path,
+                                   error->message);
+                        g_clear_error (&error);
+                }
+
+                g_variant_unref (value);
+        }
+
+        va_end (old_key_paths);
+}
diff --git a/devhelp/future/dh-dconf-migration.h b/devhelp/future/dh-dconf-migration.h
new file mode 100644
index 0000000..4bcfdcd
--- /dev/null
+++ b/devhelp/future/dh-dconf-migration.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2018 Sébastien Wilmet <swilmet gnome org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DH_DCONF_MIGRATION_H
+#define DH_DCONF_MIGRATION_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _DhDconfMigration DhDconfMigration;
+
+G_GNUC_INTERNAL
+DhDconfMigration *      _dh_dconf_migration_new         (void);
+
+G_GNUC_INTERNAL
+void                    _dh_dconf_migration_free        (DhDconfMigration *migration);
+
+G_GNUC_INTERNAL
+void                    _dh_dconf_migration_migrate_key (DhDconfMigration *migration,
+                                                         const gchar      *new_key_path,
+                                                         const gchar      *first_old_key_path,
+                                                         ...);
+
+G_END_DECLS
+
+#endif /* DH_DCONF_MIGRATION_H */
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 9a7db47..a515f71 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -47,6 +47,7 @@ EXTRA_HFILES = \
 # Header files or dirs to ignore when scanning. Use base file/dir names
 # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
 IGNORE_HFILES = \
+       dh-dconf-migration.h \
        dh-error.h \
        dh-parser.h \
        dh-search-context.h \


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