[gnome-builder] libide: move language defaults into libide and allow migrations
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] libide: move language defaults into libide and allow migrations
- Date: Tue, 24 Mar 2015 00:22:27 +0000 (UTC)
commit 0745a5d51ed0a97c84f0dfa8b0bc5c458f7206d1
Author: Christian Hergert <christian hergert me>
Date: Mon Mar 16 16:54:39 2015 -0700
libide: move language defaults into libide and allow migrations
Bump the version number when you add a new default value. We can't overwrite
previously overridden values, but we can add new ones.
data/file-settings/defaults.ini | 85 +++++
libide/Makefile.am | 2 +
libide/gsettings/ide-gsettings-file-settings.c | 65 +++-
libide/gsettings/ide-language-defaults.c | 411 ++++++++++++++++++++++++
libide/gsettings/ide-language-defaults.h | 34 ++
libide/resources/libide.gresource.xml | 2 +
tests/test-ide-source-view.c | 1 +
7 files changed, 584 insertions(+), 16 deletions(-)
---
diff --git a/data/file-settings/defaults.ini b/data/file-settings/defaults.ini
new file mode 100644
index 0000000..fb6663c
--- /dev/null
+++ b/data/file-settings/defaults.ini
@@ -0,0 +1,85 @@
+# The [global] group is used to track the version of these defaults. Every
+# time you change something in this file, bump this value. We will reinstall
+# the defaults the next time Builder starts so that untouched settings are
+# changed to reflect this files changes. This is performed by checking that
+# the current value is equal to the default value. Of course, there is the
+# obvious side effect here that people that wanted the value changed to the
+# "all languages" default value will get that setting overridden. A potential
+# alternative is to layer backends, which is out of scope at the moment.
+[global]
+version = 1
+
+[automake]
+insert-spaces-instead-of-tabs = false
+tab-width = 8
+
+[c]
+insert-spaces-instead-of-tabs = true
+tab-width = 2
+auto-indent = true
+insert-matching-brace = true
+overwrite-braces = true
+
+[chdr]
+insert-spaces-instead-of-tabs = true
+tab-width = 2
+auto-indent = true
+insert-matching-brace = true
+overwrite-braces = true
+
+[cpp]
+insert-spaces-instead-of-tabs = true
+tab-width = 4
+auto-indent = true
+insert-matching-brace = true
+overwrite-braces = true
+
+[c-sharp]
+# http://www.mono-project.com/community/contributing/coding-guidelines/
+insert-spaces-instead-of-tabs = false
+tab-width = 8
+insert-matching-brace = true
+overwrite-braces = true
+
+[css]
+insert-spaces-instead-of-tabs = true
+tab-width = 4
+
+[js]
+insert-spaces-instead-of-tabs = true
+tab-width = 4
+insert-matching-brace = true
+overwrite-braces = true
+
+[makefile]
+insert-spaces-instead-of-tabs = false
+tab-width = 8
+
+[python]
+insert-spaces-instead-of-tabs = true
+tab-width = 4
+insert-matching-brace = true
+overwrite-braces = true
+
+[python3]
+insert-spaces-instead-of-tabs = true
+tab-width = 4
+insert-matching-brace = true
+overwrite-braces = true
+
+[ruby]
+insert-spaces-instead-of-tabs = true
+tab-width = 2
+insert-matching-brace = true
+overwrite-braces = true
+
+[vala]
+insert-spaces-instead-of-tabs = true
+tab-width = 4
+insert-matching-brace = true
+overwrite-braces = true
+
+[xml]
+insert-spaces-instead-of-tabs = true
+tab-width = 2
+auto-indent = true
diff --git a/libide/Makefile.am b/libide/Makefile.am
index 3753bf3..ee7eec0 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -211,6 +211,8 @@ libide_1_0_la_SOURCES = \
libide/git/ide-git-buffer-change-monitor.h \
libide/git/ide-git-search-index.c \
libide/git/ide-git-search-index.h \
+ libide/gsettings/ide-language-defaults.c \
+ libide/gsettings/ide-language-defaults.h \
libide/ide-async-helper.c \
libide/ide-async-helper.h \
libide/ide-battery-monitor.c \
diff --git a/libide/gsettings/ide-gsettings-file-settings.c b/libide/gsettings/ide-gsettings-file-settings.c
index 01c762d..71703ee 100644
--- a/libide/gsettings/ide-gsettings-file-settings.c
+++ b/libide/gsettings/ide-gsettings-file-settings.c
@@ -22,6 +22,7 @@
#include "ide-file.h"
#include "ide-gsettings-file-settings.h"
#include "ide-language.h"
+#include "ide-language-defaults.h"
struct _IdeGsettingsFileSettings
{
@@ -76,6 +77,50 @@ indent_style_get (GValue *value,
}
static void
+ide_gsettings_file_settings__init_defaults_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ IdeGsettingsFileSettings *self;
+ g_autoptr(GTask) task = user_data;
+ GSettings *settings;
+ GError *error = NULL;
+
+ g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (G_IS_TASK (task));
+
+ if (!ide_language_defaults_init_finish (result, &error))
+ {
+ g_warning ("%s", error->message);
+ g_clear_error (&error);
+ }
+
+ self = g_task_get_source_object (task);
+ g_assert (IDE_IS_GSETTINGS_FILE_SETTINGS (self));
+
+ settings = g_task_get_task_data (task);
+ g_assert (G_IS_SETTINGS (settings));
+
+ self->settings = g_object_ref (settings);
+
+ g_settings_bind (self->settings, "indent-width", self, "indent-width",
+ G_SETTINGS_BIND_GET);
+ g_settings_bind (self->settings, "tab-width", self, "tab-width",
+ G_SETTINGS_BIND_GET);
+ g_settings_bind_with_mapping (self->settings, "insert-spaces-instead-of-tabs",
+ self, "indent-style", G_SETTINGS_BIND_GET,
+ indent_style_get, NULL, NULL, NULL);
+ g_settings_bind (self->settings, "right-margin-position",
+ self, "right-margin-position",
+ G_SETTINGS_BIND_GET);
+ g_settings_bind (self->settings, "trim-trailing-whitespace",
+ self, "trim-trailing-whitespace",
+ G_SETTINGS_BIND_GET);
+
+ g_task_return_boolean (task, TRUE);
+}
+
+static void
ide_gsettings_file_settings_init_async (GAsyncInitable *initable,
gint io_priority,
GCancellable *cancellable,
@@ -121,23 +166,11 @@ ide_gsettings_file_settings_init_async (GAsyncInitable *initable,
path = g_strdup_printf ("/org/gnome/builder/editor/language/%s/", lang_id);
settings = g_settings_new_with_path ("org.gnome.builder.editor.language", path);
- self->settings = g_object_ref (settings);
-
- g_settings_bind (self->settings, "indent-width", self, "indent-width",
- G_SETTINGS_BIND_GET);
- g_settings_bind (self->settings, "tab-width", self, "tab-width",
- G_SETTINGS_BIND_GET);
- g_settings_bind_with_mapping (self->settings, "insert-spaces-instead-of-tabs",
- self, "indent-style", G_SETTINGS_BIND_GET,
- indent_style_get, NULL, NULL, NULL);
- g_settings_bind (self->settings, "right-margin-position",
- self, "right-margin-position",
- G_SETTINGS_BIND_GET);
- g_settings_bind (self->settings, "trim-trailing-whitespace",
- self, "trim-trailing-whitespace",
- G_SETTINGS_BIND_GET);
+ g_task_set_task_data (task, g_object_ref (settings), g_object_unref);
- g_task_return_boolean (task, TRUE);
+ ide_language_defaults_init_async (cancellable,
+ ide_gsettings_file_settings__init_defaults_cb,
+ g_object_ref (task));
}
static gboolean
diff --git a/libide/gsettings/ide-language-defaults.c b/libide/gsettings/ide-language-defaults.c
new file mode 100644
index 0000000..3d0bde2
--- /dev/null
+++ b/libide/gsettings/ide-language-defaults.c
@@ -0,0 +1,411 @@
+/* ide-language-defaults.c
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-language-defaults"
+
+#include <errno.h>
+#include <glib/gi18n.h>
+
+#include "ide-debug.h"
+#include "ide-global.h"
+#include "ide-language-defaults.h"
+
+#define SCHEMA_ID "org.gnome.builder.editor.language"
+#define PATH_BASE "/org/gnome/builder/editor/language/"
+
+static gboolean gInitialized;
+static gboolean gInitializing;
+static GList *gTasks;
+
+G_LOCK_DEFINE (lock);
+
+static gboolean
+ide_language_defaults_migrate (GKeyFile *key_file,
+ gint current_version,
+ gint new_version,
+ GError **error)
+{
+ gchar **groups;
+ gsize i;
+
+ g_assert (key_file);
+ g_assert_cmpint (current_version, >=, 0);
+ g_assert_cmpint (current_version, >=, 0);
+ g_assert_cmpint (new_version, >, current_version);
+
+ groups = g_key_file_get_groups (key_file, NULL);
+
+ for (i = 0; groups [i]; i++)
+ {
+ const gchar *group = groups [i];
+ g_autoptr(GSettings) settings = NULL;
+ g_autofree gchar *lang_path = NULL;
+ gchar **keys;
+ gsize j;
+
+ g_assert (group != NULL);
+
+ if (g_str_equal (group, "global"))
+ continue;
+
+ lang_path = g_strdup_printf (PATH_BASE"%s/", group);
+ g_assert(lang_path);
+
+ settings = g_settings_new_with_path (SCHEMA_ID, lang_path);
+ g_assert (G_IS_SETTINGS (settings));
+
+ keys = g_key_file_get_keys (key_file, group, NULL, NULL);
+ g_assert (keys);
+
+ for (j = 0; keys [j]; j++)
+ {
+ const gchar *key = keys [j];
+ g_autoptr(GVariant) default_value = NULL;
+
+ g_assert (key);
+
+ default_value = g_settings_get_default_value (settings, key);
+ g_assert (default_value);
+
+ /*
+ * For all of the variant types we support, check to see if the value
+ * is matching the default schema value. If so, update the key to the
+ * new override value.
+ *
+ * This will not overwrite any change settings for files that the
+ * user has previously loaded, but will for others. Overriding things
+ * we have overriden gets pretty nasty, since we change things out
+ * from under the user.
+ *
+ * That may change in the future, but not today.
+ */
+
+ if (g_variant_is_of_type (default_value, G_VARIANT_TYPE_STRING))
+ {
+ g_autofree gchar *current_str = NULL;
+ g_autofree gchar *override_str = NULL;
+ const gchar *default_str;
+
+ default_str = g_variant_get_string (default_value, NULL);
+ current_str = g_settings_get_string (settings, key);
+ override_str = g_key_file_get_string (key_file, group, key, NULL);
+
+ if (0 == g_strcmp0 (default_str, current_str))
+ g_settings_set_string (settings, key, override_str);
+ }
+ else if (g_variant_is_of_type (default_value, G_VARIANT_TYPE_BOOLEAN))
+ {
+ gboolean current_bool;
+ gboolean override_bool;
+ gboolean default_bool;
+
+ default_bool = g_variant_get_boolean (default_value);
+ current_bool = g_settings_get_boolean (settings, key);
+ override_bool = g_key_file_get_boolean (key_file, group, key, NULL);
+
+ if (default_bool != current_bool)
+ g_settings_set_boolean (settings, key, override_bool);
+ }
+ else if (g_variant_is_of_type (default_value, G_VARIANT_TYPE_INT32))
+ {
+ gint32 current_int32;
+ gint32 override_int32;
+ gint32 default_int32;
+
+ default_int32 = g_variant_get_int32 (default_value);
+ current_int32 = g_settings_get_int (settings, key);
+ override_int32 = g_key_file_get_integer (key_file, group, key, NULL);
+
+ if (default_int32 != current_int32)
+ g_settings_set_int (settings, key, override_int32);
+ }
+ else
+ {
+ g_error ("Teach me about variant type: %s",
+ g_variant_get_type_string (default_value));
+ g_assert_not_reached ();
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static gint
+ide_language_defaults_get_current_version (const gchar *path,
+ GError **error)
+{
+ GError *local_error = NULL;
+ g_autofree gchar *contents = NULL;
+ gsize length = 0;
+ gint64 version;
+
+ if (!g_file_get_contents (path, &contents, &length, &local_error))
+ {
+ if (g_error_matches (local_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+ {
+ g_clear_error (&local_error);
+ return 0;
+ }
+ else
+ {
+ g_propagate_error (error, local_error);
+ return -1;
+ }
+ }
+
+ if (!g_str_is_ascii (contents))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("%s contained invalid ASCII"),
+ path);
+ return -1;
+ }
+
+ if ((length == 0) || (contents [0] == '\0'))
+ return 0;
+
+ version = g_ascii_strtoll (contents, NULL, 10);
+
+ if ((version < 0) || (version >= G_MAXINT))
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("Failed to parse integer from \"%s\""),
+ path);
+ return -1;
+ }
+
+ return version;
+}
+
+static GBytes *
+ide_language_defaults_get_defaults (GError **error)
+{
+ return g_resources_lookup_data ("/org/gnome/libide/file-settings/defaults.ini",
+ G_RESOURCE_LOOKUP_FLAGS_NONE, error);
+}
+
+static void
+ide_language_defaults_init_worker (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ g_autofree gchar *version_path = NULL;
+ g_autofree gchar *version_contents = NULL;
+ g_autofree gchar *version_dir = NULL;
+ g_autoptr(GBytes) defaults = NULL;
+ g_autoptr(GKeyFile) key_file = NULL;
+ gint global_version;
+ gboolean ret;
+ GError *error = NULL;
+ gint current_version;
+
+ IDE_ENTRY;
+
+ g_assert (G_IS_TASK (task));
+ g_assert (source_object == NULL);
+ g_assert (task_data == NULL);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ version_path = g_build_filename (g_get_user_config_dir (),
+ ide_get_program_name (),
+ "syntax",
+ ".defaults",
+ NULL);
+ current_version = ide_language_defaults_get_current_version (version_path, &error);
+
+ if (current_version < 0)
+ {
+ g_task_return_error (task, error);
+ goto failure;
+ }
+
+ defaults = ide_language_defaults_get_defaults (&error);
+
+ if (!defaults)
+ {
+ g_task_return_error (task, error);
+ goto failure;
+ }
+
+ key_file = g_key_file_new ();
+ ret = g_key_file_load_from_data (key_file,
+ g_bytes_get_data (defaults, NULL),
+ g_bytes_get_size (defaults),
+ G_KEY_FILE_NONE,
+ &error);
+
+ if (!ret)
+ {
+ g_task_return_error (task, error);
+ goto failure;
+ }
+
+ if (!g_key_file_has_group (key_file, "global") ||
+ !g_key_file_has_key (key_file, "global", "version", NULL))
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_DATA,
+ _("language defaults missing version in [global] group."));
+ goto failure;
+ }
+
+ global_version = g_key_file_get_integer (key_file, "global", "version", &error);
+
+ if ((global_version == 0) && error)
+ {
+ g_task_return_error (task, error);
+ goto failure;
+ }
+
+ if (global_version > current_version)
+ {
+ if (!ide_language_defaults_migrate (key_file, current_version, global_version, &error))
+ {
+ g_task_return_error (task, error);
+ goto failure;
+ }
+ }
+
+ version_contents = g_strdup_printf ("%d", global_version);
+
+ version_dir = g_path_get_dirname (version_path);
+
+ if (!g_file_test (version_dir, G_FILE_TEST_IS_DIR))
+ {
+ if (g_mkdir_with_parents (version_dir, 0750) == -1)
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ "%s", g_strerror (errno));
+ goto failure;
+ }
+ }
+
+ IDE_TRACE_MSG ("Writing new language defaults version to \"%s\"", version_path);
+
+ if (!g_file_set_contents (version_path, version_contents, -1, &error))
+ {
+ g_task_return_error (task, error);
+ goto failure;
+ }
+
+ g_task_return_boolean (task, TRUE);
+
+ {
+ GList *list;
+ GList *iter;
+
+ G_LOCK (lock);
+
+ gInitializing = FALSE;
+ gInitialized = TRUE;
+
+ list = gTasks;
+ gTasks = NULL;
+
+ G_UNLOCK (lock);
+
+ for (iter = list; iter; iter = iter->next)
+ {
+ g_task_return_boolean (iter->data, TRUE);
+ g_object_unref (iter->data);
+ }
+
+ g_list_free (list);
+ }
+
+ IDE_EXIT;
+
+failure:
+ {
+ GList *list;
+ GList *iter;
+
+ G_LOCK (lock);
+
+ gInitializing = FALSE;
+ gInitialized = TRUE;
+
+ list = gTasks;
+ gTasks = NULL;
+
+ G_UNLOCK (lock);
+
+ for (iter = list; iter; iter = iter->next)
+ {
+ g_task_return_new_error (iter->data,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Failed to initialize defaults."));
+ g_object_unref (iter->data);
+ }
+
+ g_list_free (list);
+ }
+
+ IDE_EXIT;
+}
+
+void
+ide_language_defaults_init_async (GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = NULL;
+
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (NULL, cancellable, callback, user_data);
+
+ G_LOCK (lock);
+
+ if (gInitialized)
+ {
+ g_task_return_boolean (task, TRUE);
+ }
+ else if (gInitializing)
+ {
+ g_list_prepend (gTasks, g_object_ref (task));
+ }
+ else
+ {
+ gInitializing = TRUE;
+ g_task_run_in_thread (task, ide_language_defaults_init_worker);
+ }
+
+ G_UNLOCK (lock);
+}
+
+gboolean
+ide_language_defaults_init_finish (GAsyncResult *result,
+ GError **error)
+{
+ GTask *task = (GTask *)result;
+
+ g_return_val_if_fail (G_IS_TASK (task), FALSE);
+
+ return g_task_propagate_boolean (task, error);
+}
diff --git a/libide/gsettings/ide-language-defaults.h b/libide/gsettings/ide-language-defaults.h
new file mode 100644
index 0000000..73256b1
--- /dev/null
+++ b/libide/gsettings/ide-language-defaults.h
@@ -0,0 +1,34 @@
+/* ide-language-defaults.h
+ *
+ * Copyright (C) 2015 Christian Hergert <christian hergert me>
+ *
+ * This file 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.1 of the License, or (at your option) any later version.
+ *
+ * This file 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 General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef IDE_LANGUAGE_DEFAULTS_H
+#define IDE_LANGUAGE_DEFAULTS_H
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+void ide_language_defaults_init_async (GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean ide_language_defaults_init_finish (GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* IDE_LANGUAGE_DEFAULTS_H */
diff --git a/libide/resources/libide.gresource.xml b/libide/resources/libide.gresource.xml
index 967333c..ea33f8a 100644
--- a/libide/resources/libide.gresource.xml
+++ b/libide/resources/libide.gresource.xml
@@ -13,6 +13,8 @@
<file alias="snippets/vala.snippets">../../data/snippets/vala.snippets</file>
<file alias="snippets/xml.snippets">../../data/snippets/xml.snippets</file>
+ <file alias="file-settings/defaults.ini">../../data/file-settings/defaults.ini</file>
+
<file alias="keybindings/emacs.css">../../data/keybindings/emacs.css</file>
<file alias="keybindings/vim.css">../../data/keybindings/vim.css</file>
diff --git a/tests/test-ide-source-view.c b/tests/test-ide-source-view.c
index 145f1ee..c74b5bc 100644
--- a/tests/test-ide-source-view.c
+++ b/tests/test-ide-source-view.c
@@ -724,6 +724,7 @@ main (int argc,
{ NULL }
};
+ ide_set_program_name ("gnome-builder");
ide_log_init (TRUE, NULL);
context = g_option_context_new (_("[FILES...] - A mini editor for libide"));
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]