[gnome-builder/wip/mwleeds/ide-config-provider: 26/27] configuration: Make IdeBuildconfigConfigurationProvider writeback work
- From: Matthew Leeds <mwleeds src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/mwleeds/ide-config-provider: 26/27] configuration: Make IdeBuildconfigConfigurationProvider writeback work
- Date: Thu, 19 Jan 2017 23:01:05 +0000 (UTC)
commit bd9b901f7b3f02641ab2b95a2c4cf1336c32fdd2
Author: Matthew Leeds <mleeds redhat com>
Date: Thu Jan 12 17:02:29 2017 -0600
configuration: Make IdeBuildconfigConfigurationProvider writeback work
.../ide-buildconfig-configuration-provider.c | 245 ++++++++++++++++++++
.../ide-buildconfig-configuration-provider.h | 8 +
2 files changed, 253 insertions(+), 0 deletions(-)
---
diff --git a/libide/buildsystem/ide-buildconfig-configuration-provider.c
b/libide/buildsystem/ide-buildconfig-configuration-provider.c
index 47a4636..12944b7 100644
--- a/libide/buildsystem/ide-buildconfig-configuration-provider.c
+++ b/libide/buildsystem/ide-buildconfig-configuration-provider.c
@@ -35,14 +35,19 @@
#include "vcs/ide-vcs.h"
#define DOT_BUILD_CONFIG ".buildconfig"
+#define WRITEBACK_TIMEOUT_SECS 2
struct _IdeBuildconfigConfigurationProvider
{
GObject parent_instance;
+
IdeConfigurationManager *manager;
GCancellable *cancellable;
GPtrArray *configurations;
GKeyFile *key_file;
+
+ gulong writeback_handler;
+ guint change_count;
};
static void configuration_provider_iface_init (IdeConfigurationProviderInterface *);
@@ -55,6 +60,238 @@ static void ide_buildconfig_configuration_provider_load (IdeConfigurationProvide
static void ide_buildconfig_configuration_provider_unload (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager);
static void
+ide_buildconfig_configuration_provider_save_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = user_data;
+ GError *error = NULL;
+ GFile *file = (GFile *)object;
+
+ g_assert (G_IS_FILE (file));
+ g_assert (G_IS_ASYNC_RESULT (result));
+
+ if (!g_file_replace_contents_finish (file, result, NULL, &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+}
+
+void
+ide_buildconfig_configuration_provider_save_async (IdeBuildconfigConfigurationProvider *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_autoptr(GHashTable) group_names = NULL;
+ g_autoptr(GTask) task = NULL;
+ g_auto(GStrv) groups = NULL;
+ g_autoptr(GFile) file = NULL;
+ g_autoptr(GBytes) bytes = NULL;
+ gchar *data;
+ gsize length;
+ IdeContext *context;
+ IdeVcs *vcs;
+ GFile *workdir;
+ GError *error = NULL;
+ guint i;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+
+ if (self->change_count == 0)
+ {
+ g_task_return_boolean (task, TRUE);
+ return;
+ }
+
+ self->change_count = 0;
+
+ context = ide_object_get_context (IDE_OBJECT (self->manager));
+ vcs = ide_context_get_vcs (context);
+ workdir = ide_vcs_get_working_directory (vcs);
+ file = g_file_get_child (workdir, DOT_BUILD_CONFIG);
+
+ /*
+ * NOTE:
+ *
+ * We keep the GKeyFile around from when we parsed .buildconfig, so that
+ * we can try to preserve comments and such when writing back.
+ *
+ * This means that we need to fill in all our known configuration
+ * sections, and then remove any that were removed since we were
+ * parsed it last.
+ */
+
+ if (self->key_file == NULL)
+ self->key_file = g_key_file_new ();
+
+ group_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ for (i = 0; i < self->configurations->len; i++)
+ {
+ IdeConfiguration *configuration = g_ptr_array_index (self->configurations, i);
+ IdeEnvironment *environment;
+ guint n_items;
+ guint j;
+ gchar *group;
+ gchar *group_environ;
+
+ group = g_strdup (ide_configuration_get_id (configuration));
+ group_environ = g_strdup_printf ("%s.environment", group);
+
+ /*
+ * Track our known group names, so we can remove missing names after
+ * we've updated the GKeyFile.
+ */
+ g_hash_table_insert (group_names, group, NULL);
+ g_hash_table_insert (group_names, group_environ, NULL);
+
+#define PERSIST_STRING_KEY(key, getter) \
+ g_key_file_set_string (self->key_file, group, key, \
+ ide_configuration_##getter (configuration) ?: "")
+ PERSIST_STRING_KEY ("name", get_display_name);
+ PERSIST_STRING_KEY ("device", get_device_id);
+ PERSIST_STRING_KEY ("runtime", get_runtime_id);
+ PERSIST_STRING_KEY ("config-opts", get_config_opts);
+ PERSIST_STRING_KEY ("prefix", get_prefix);
+ PERSIST_STRING_KEY ("app-id", get_app_id);
+#undef PERSIST_STRING_KEY
+
+ if (configuration == ide_configuration_manager_get_current (self->manager))
+ g_key_file_set_boolean (self->key_file, group, "default", TRUE);
+ else
+ g_key_file_remove_key (self->key_file, group, "default", NULL);
+
+ environment = ide_configuration_get_environment (configuration);
+
+ /*
+ * Remove all environment keys that are no longer specified in the
+ * environment. This allows us to just do a single pass of additions
+ * from the environment below.
+ */
+ if (g_key_file_has_group (self->key_file, group_environ))
+ {
+ g_auto(GStrv) keys = NULL;
+
+ if (NULL != (keys = g_key_file_get_keys (self->key_file, group_environ, NULL, NULL)))
+ {
+ for (j = 0; keys [j]; j++)
+ {
+ if (!ide_environment_getenv (environment, keys [j]))
+ g_key_file_remove_key (self->key_file, group_environ, keys [j], NULL);
+ }
+ }
+ }
+
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (environment));
+
+ for (j = 0; j < n_items; j++)
+ {
+ g_autoptr(IdeEnvironmentVariable) var = NULL;
+ const gchar *key;
+ const gchar *value;
+
+ var = g_list_model_get_item (G_LIST_MODEL (environment), j);
+ key = ide_environment_variable_get_key (var);
+ value = ide_environment_variable_get_value (var);
+
+ if (!ide_str_empty0 (key))
+ g_key_file_set_string (self->key_file, group_environ, key, value ?: "");
+ }
+ }
+
+ /*
+ * Now truncate any old groups in the keyfile.
+ */
+ if (NULL != (groups = g_key_file_get_groups (self->key_file, NULL)))
+ {
+ for (i = 0; groups [i]; i++)
+ {
+ if (!g_hash_table_contains (group_names, groups [i]))
+ g_key_file_remove_group (self->key_file, groups [i], NULL);
+ }
+ }
+
+ if (NULL == (data = g_key_file_to_data (self->key_file, &length, &error)))
+ {
+ g_task_return_error (task, error);
+ IDE_EXIT;
+ }
+
+ bytes = g_bytes_new_take (data, length);
+
+ g_file_replace_contents_bytes_async (file,
+ bytes,
+ NULL,
+ FALSE,
+ G_FILE_CREATE_NONE,
+ cancellable,
+ ide_buildconfig_configuration_provider_save_cb,
+ g_object_ref (task));
+
+ IDE_EXIT;
+}
+
+gboolean
+ide_buildconfig_configuration_provider_save_finish (IdeBuildconfigConfigurationProvider *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self), FALSE);
+ g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static gboolean
+ide_buildconfig_configuration_provider_do_writeback (gpointer data)
+{
+ IdeBuildconfigConfigurationProvider *self = data;
+
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
+
+ self->writeback_handler = 0;
+
+ ide_buildconfig_configuration_provider_save_async (self, NULL, NULL, NULL);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+ide_buildconfig_configuration_provider_queue_writeback (IdeBuildconfigConfigurationProvider *self)
+{
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
+
+ IDE_ENTRY;
+
+ if (self->writeback_handler != 0)
+ g_source_remove (self->writeback_handler);
+
+ self->writeback_handler = g_timeout_add_seconds (WRITEBACK_TIMEOUT_SECS,
+ ide_buildconfig_configuration_provider_do_writeback,
+ self);
+
+ IDE_EXIT;
+}
+
+static void
+ide_buildconfig_configuration_provider_changed (IdeBuildconfigConfigurationProvider *self,
+ IdeConfiguration *configuration)
+{
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
+ g_assert (IDE_IS_CONFIGURATION (configuration));
+
+ self->change_count++;
+
+ ide_buildconfig_configuration_provider_queue_writeback (self);
+}
+
+static void
load_string (IdeConfiguration *configuration,
GKeyFile *key_file,
const gchar *group,
@@ -197,6 +434,12 @@ ide_buildconfig_configuration_provider_load_group (IdeBuildconfigConfigurationPr
if (g_key_file_get_boolean (key_file, group, "default", NULL))
ide_configuration_manager_set_current (self->manager, configuration);
+ g_signal_connect_object (configuration,
+ "changed",
+ G_CALLBACK (ide_buildconfig_configuration_provider_changed),
+ self,
+ G_CONNECT_SWAPPED);
+
return TRUE;
}
@@ -337,6 +580,8 @@ ide_buildconfig_configuration_provider_unload (IdeConfigurationProvider *provide
g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
+ ide_clear_source (&self->writeback_handler);
+
if (self->configurations != NULL)
{
for (guint i= 0; i < self->configurations->len; i++)
diff --git a/libide/buildsystem/ide-buildconfig-configuration-provider.h
b/libide/buildsystem/ide-buildconfig-configuration-provider.h
index 2ec8dff..6097399 100644
--- a/libide/buildsystem/ide-buildconfig-configuration-provider.h
+++ b/libide/buildsystem/ide-buildconfig-configuration-provider.h
@@ -29,6 +29,14 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (IdeBuildconfigConfigurationProvider, ide_buildconfig_configuration_provider, IDE,
BUILDCONFIG_CONFIGURATION_PROVIDER, GObject)
+void ide_buildconfig_configuration_provider_save_async (IdeBuildconfigConfigurationProvider *self,
+ GCancellable
*cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean ide_buildconfig_configuration_provider_save_finish (IdeBuildconfigConfigurationProvider *self,
+ GAsyncResult *result,
+ GError **error);
+
G_END_DECLS
#endif /* IDE_BUILDCONFIG_CONFIGURATION_PROVIDER_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]