summaryrefslogtreecommitdiff
path: root/gsettings/gsettings-data-convert.c
diff options
context:
space:
mode:
Diffstat (limited to 'gsettings/gsettings-data-convert.c')
-rw-r--r--gsettings/gsettings-data-convert.c435
1 files changed, 435 insertions, 0 deletions
diff --git a/gsettings/gsettings-data-convert.c b/gsettings/gsettings-data-convert.c
new file mode 100644
index 00000000..c7fb8668
--- /dev/null
+++ b/gsettings/gsettings-data-convert.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Matthias Clasen <mclasen@redhat.com>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <gconf/gconf-client.h>
+
+static const gchar convert_dir[] = "/usr/share/gsettings-data-convert";
+
+static gboolean verbose = FALSE;
+static gboolean dry_run = FALSE;
+
+static gboolean
+handle_file (const gchar *filename)
+{
+ GKeyFile *keyfile;
+ GConfClient *client;
+ GConfValue *value;
+ gint i, j;
+ gchar *gconf_key;
+ gchar **groups;
+ gchar **keys;
+ GConfValueType list_type;
+ GVariantBuilder *builder;
+ GVariant *v;
+ const gchar *s;
+ gchar *str;
+ gint ii;
+ GSList *list, *l;
+ GSettings *settings;
+ GError *error;
+
+ keyfile = g_key_file_new ();
+
+ error = NULL;
+ if (!g_key_file_load_from_file (keyfile, filename, 0, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+
+ g_key_file_free (keyfile);
+
+ return FALSE;
+ }
+
+ client = gconf_client_get_default ();
+
+ groups = g_key_file_get_groups (keyfile, NULL);
+ for (i = 0; groups[i]; i++)
+ {
+ if (verbose)
+ g_print ("collecting settings for schema '%s'\n", groups[i]);
+
+ settings = g_settings_new (groups[i]);
+ g_settings_delay (settings);
+
+ error = NULL;
+ if ((keys = g_key_file_get_keys (keyfile, groups[i], NULL, &error)) == NULL)
+ {
+ g_printerr ("%s", error->message);
+ g_error_free (error);
+
+ continue;
+ }
+
+ for (j = 0; keys[j]; j++)
+ {
+ error = NULL;
+ if ((gconf_key = g_key_file_get_string (keyfile, groups[i], keys[j], &error)) == NULL)
+ {
+ g_printerr ("%s", error->message);
+ g_error_free (error);
+
+ continue;
+ }
+
+ error = NULL;
+ if ((value = gconf_client_get_without_default (client, gconf_key, &error)) == NULL)
+ {
+ if (error)
+ {
+ g_printerr ("Failed to get GConf key '%s': %s\n", gconf_key, error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ if (verbose)
+ g_print ("Skipping GConf key '%s', no user value\n", gconf_key);
+ }
+
+ g_free (gconf_key);
+
+ continue;
+ }
+
+ switch (value->type)
+ {
+ case GCONF_VALUE_STRING:
+ if (dry_run)
+ g_print ("set key '%s' to string '%s'\n", keys[j], gconf_value_get_string (value));
+ else
+ g_settings_set (settings, keys[j], "s", gconf_value_get_string (value));
+ break;
+
+ case GCONF_VALUE_INT:
+ if (dry_run)
+ g_print ("set key '%s' to integer '%d'\n", keys[j], gconf_value_get_int (value));
+ else
+ g_settings_set (settings, keys[j], "i", gconf_value_get_int (value));
+ break;
+
+ case GCONF_VALUE_BOOL:
+ if (dry_run)
+ g_print ("set key '%s' to boolean '%d'\n", keys[j], gconf_value_get_bool (value));
+ else
+ g_settings_set (settings, keys[j], "b", gconf_value_get_bool (value));
+ break;
+
+ case GCONF_VALUE_FLOAT:
+ if (dry_run)
+ g_print ("set key '%s' to double '%g'\n", keys[j], gconf_value_get_float (value));
+ else
+ g_settings_set (settings, keys[j], "d", gconf_value_get_float (value));
+ break;
+
+ case GCONF_VALUE_LIST:
+ switch (gconf_value_get_list_type (value))
+ {
+ case GCONF_VALUE_STRING:
+ builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ list = gconf_value_get_list (value);
+ for (l = list; l; l = l->next)
+ {
+ GConfValue *lv = l->data;
+ s = gconf_value_get_string (lv);
+ g_variant_builder_add (builder, "s", s);
+ }
+ v = g_variant_new ("as", builder);
+
+ if (dry_run)
+ {
+ str = g_variant_print (v, FALSE);
+ g_print ("set key '%s' to a list of strings: %s\n", keys[j], str);
+ g_free (str);
+ }
+ else
+ g_settings_set_value (settings, keys[j], v);
+
+ g_variant_unref (v);
+ g_variant_builder_unref (builder);
+ break;
+
+ case GCONF_VALUE_INT:
+ builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ list = gconf_value_get_list (value);
+ for (l = list; l; l = l->next)
+ {
+ GConfValue *lv = l->data;
+ ii = gconf_value_get_int (lv);
+ g_variant_builder_add (builder, "i", ii);
+ }
+ v = g_variant_new ("ai", builder);
+
+ if (dry_run)
+ {
+ str = g_variant_print (v, FALSE);
+ g_print ("set key '%s' to a list of integers: %s\n", keys[j], str);
+ g_free (str);
+ }
+ else
+ g_settings_set_value (settings, keys[j], v);
+
+ g_variant_unref (v);
+ g_variant_builder_unref (builder);
+ break;
+
+ default:
+ g_printerr ("Keys of type 'list of %s' not handled yet\n", gconf_value_type_to_string (gconf_value_get_list_type (value)));
+ break;
+ }
+ break;
+
+ default:
+ g_printerr ("Keys of type %s not handled yet\n", gconf_value_type_to_string (value->type));
+ break;
+ }
+
+ gconf_value_free (value);
+ g_free (gconf_key);
+ }
+
+ g_strfreev (keys);
+
+ if (!dry_run)
+ g_settings_apply (settings);
+
+ g_object_unref (settings);
+ }
+
+ g_strfreev (groups);
+
+ g_object_unref (client);
+
+ return TRUE;
+}
+
+static void
+load_state (time_t *mtime,
+ gchar ***converted)
+{
+ gchar *filename;
+ GKeyFile *keyfile;
+ GError *error;
+ gchar *str;
+ gchar **list;
+
+ *mtime = 0;
+ *converted = g_new0 (gchar *, 1);
+
+ filename = g_build_filename (g_get_user_data_dir (), "gsettings-data-convert", NULL);
+ keyfile = g_key_file_new ();
+
+ error = NULL;
+ if (!g_key_file_load_from_file (keyfile, filename, 0, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ error = NULL;
+ if ((str = g_key_file_get_string (keyfile, "State", "timestamp", &error)) == NULL)
+ {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ *mtime = (time_t)g_ascii_strtoll (str, NULL, 0);
+ g_free (str);
+ }
+
+ error = NULL;
+ if ((list = g_key_file_get_string_list (keyfile, "State", "converted", NULL, &error)) == NULL)
+ {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ }
+ else
+ {
+ g_strfreev (*converted);
+ *converted = list;
+ }
+
+ g_key_file_free (keyfile);
+ g_free (filename);
+}
+
+static gboolean
+save_state (time_t mtime,
+ gchar **converted)
+{
+ gchar *filename;
+ GKeyFile *keyfile;
+ gchar *str;
+ GError *error;
+ gboolean result;
+
+ /* Make sure the state directory exists */
+ if (g_mkdir_with_parents (g_get_user_data_dir (), 0755))
+ {
+ g_printerr ("Failed to create directory %s: %s\n",
+ g_get_user_data_dir (), g_strerror (errno));
+ return FALSE;
+ }
+
+ filename = g_build_filename (g_get_user_data_dir (), "gsettings-data-convert", NULL);
+ keyfile = g_key_file_new ();
+
+ str = g_strdup_printf ("%ld", mtime);
+ g_key_file_set_string (keyfile,
+ "State", "timestamp", str);
+ g_free (str);
+
+ g_key_file_set_string_list (keyfile,
+ "State", "converted",
+ (const gchar * const *)converted, g_strv_length (converted));
+
+ str = g_key_file_to_data (keyfile, NULL, NULL);
+ g_key_file_free (keyfile);
+
+ error = NULL;
+ if (!g_file_set_contents (filename, str, -1, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+
+ result = FALSE;
+ }
+ else
+ result = TRUE;
+
+ g_free (filename);
+ g_free (str);
+
+ return result;
+}
+
+int
+main (int argc, char *argv[])
+{
+ gchar *state_filename;
+ time_t stored_mtime;
+ time_t dir_mtime;
+ struct stat statbuf;
+ gchar *contents;
+ GError *error;
+ gchar *converted_filename;
+ gchar **converted;
+ GConfClient *client;
+ GDir *dir;
+ const gchar *name;
+ gchar *filename;
+ GString *string;
+ gint i;
+ GOptionContext *context;
+ GOptionEntry entries[] = {
+ { "verbose", 0, 0, G_OPTION_ARG_NONE, &verbose, "show verbose messages", NULL },
+ { "dry-run", 0, 0, G_OPTION_ARG_NONE, &dry_run, "do not perform any changes", NULL },
+ { NULL }
+ };
+
+ context = g_option_context_new ("");
+
+ g_option_context_set_summary (context,
+ "Migrate settings from the users GConf database to GSettings.");
+
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ error = NULL;
+ if (!g_option_context_parse (context, &argc, &argv, &error))
+ {
+ g_printerr ("%s\n", error->message);
+ return 1;
+ }
+
+ load_state (&stored_mtime, &converted);
+
+ /* If the directory is not newer, exit */
+ if (stat (convert_dir, &statbuf) == 0)
+ dir_mtime = statbuf.st_mtime;
+ else
+ {
+ if (verbose)
+ g_print ("Directory '%s' does not exist, nothing to do\n", convert_dir);
+ return 0;
+ }
+
+ if (dir_mtime <= stored_mtime)
+ {
+ if (verbose)
+ g_print ("All uptodate, nothing to do\n");
+ return 0;
+ }
+
+ error = NULL;
+ dir = g_dir_open (convert_dir, 0, &error);
+ if (dir == NULL)
+ {
+ g_printerr ("Failed to open '%s': %s\n", error->message);
+ return 1;
+ }
+
+ while ((name = g_dir_read_name (dir)) != NULL)
+ {
+ for (i = 0; converted[i]; i++)
+ {
+ if (strcmp (name, converted[i]) == 0)
+ {
+ if (verbose)
+ g_print ("File '%s already converted, skipping\n", name);
+ goto next;
+ }
+ }
+
+ filename = g_build_filename (convert_dir, name, NULL);
+
+ if (handle_file (filename))
+ {
+ gint len;
+
+ /* Add the the file to the converted list */
+ len = g_strv_length (converted);
+ converted = g_realloc (converted, len + 1);
+ converted[len] = g_strdup (name);
+ converted[len + 1] = NULL;
+ }
+
+ g_free (filename);
+
+ next: ;
+ }
+
+ if (!dry_run)
+ {
+ if (!save_state (dir_mtime, converted))
+ return 1;
+ }
+
+ return 0;
+}
+