[devhelp/wip/devhelp-next: 1/2] gsettings: implement DhDconfMigration utility class
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [devhelp/wip/devhelp-next: 1/2] gsettings: implement DhDconfMigration utility class
- Date: Fri, 9 Mar 2018 11:54:40 +0000 (UTC)
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]