[gnome-builder] config: refactor config providers to be less racey
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] config: refactor config providers to be less racey
- Date: Wed, 24 Jan 2018 23:15:19 +0000 (UTC)
commit 1ab088f0e613790119237582844a28758a7bca44
Author: Christian Hergert <chergert redhat com>
Date: Wed Jan 24 03:06:01 2018 -0800
config: refactor config providers to be less racey
We had a number of issues in practice with configuration providers where
things would race and as well as some unsafe threading/false-sharing.
This redesigns those components to avoid a number of issues in thread
safety.
There doesn't seem to be any regressions. However, it has pointed out
a few things that are/were broken in the flatpak configuration provider.
We will address those as part of a revamped build preferences that is
more pluggable (See #344 and #352).
Another piece that would be nice to apply on top of this is tracking
the last selected configuration so when restarting Builder we keep
the same config active (See #338).
Fixes #359
po/POTFILES.in | 1 +
.../ide-buildconfig-configuration-provider.c | 906 +++++++++++----------
.../ide-buildconfig-configuration-provider.h | 12 +-
.../buildconfig/ide-buildconfig-configuration.c | 3 +-
src/libide/buildui/buildui.plugin | 2 -
src/libide/buildui/ide-build-perspective.c | 10 +-
src/libide/buildui/ide-build-plugin.c | 3 -
src/libide/buildui/ide-build-tool.c | 337 --------
src/libide/buildui/meson.build | 2 -
src/libide/config/ide-configuration-manager.c | 492 +++++++----
src/libide/config/ide-configuration-manager.h | 12 +-
src/libide/config/ide-configuration-provider.c | 239 +++++-
src/libide/config/ide-configuration-provider.h | 99 ++-
src/libide/config/ide-configuration.c | 180 +---
src/libide/config/ide-configuration.h | 7 -
.../flatpak/gbp-flatpak-configuration-provider.c | 360 ++++----
16 files changed, 1282 insertions(+), 1383 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 45365e1f5..acceb51d6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -30,6 +30,7 @@ src/libide/application/ide-application-shortcuts.c
src/libide/buffers/ide-buffer.c
src/libide/buffers/ide-buffer-manager.c
src/libide/buffers/ide-unsaved-files.c
+src/libide/buildconfig/ide-buildconfig-configuration-provider.c
src/libide/buildsystem/ide-build-manager.c
src/libide/buildsystem/ide-build-pipeline.c
src/libide/buildsystem/ide-build-stage-transfer.c
diff --git a/src/libide/buildconfig/ide-buildconfig-configuration-provider.c
b/src/libide/buildconfig/ide-buildconfig-configuration-provider.c
index 13d535d63..acdce8846 100644
--- a/src/libide/buildconfig/ide-buildconfig-configuration-provider.c
+++ b/src/libide/buildconfig/ide-buildconfig-configuration-provider.c
@@ -20,6 +20,8 @@
#include <dazzle.h>
#include <gio/gio.h>
+#include <glib/gi18n.h>
+#include <string.h>
#include "ide-context.h"
#include "ide-debug.h"
@@ -33,39 +35,289 @@
#include "vcs/ide-vcs.h"
#define DOT_BUILDCONFIG ".buildconfig"
-#define WRITEBACK_TIMEOUT_SECS 2
struct _IdeBuildconfigConfigurationProvider
{
- IdeObject parent_instance;
+ IdeObject parent_instance;
- IdeConfigurationManager *manager;
- GPtrArray *configurations;
- GKeyFile *key_file;
+ /*
+ * A GPtrArray of IdeBuildconfigConfiguration that have been registered.
+ * We append/remove to/from this array in our default signal handler for
+ * the ::added and ::removed signals.
+ */
+ GPtrArray *configs;
+
+ /*
+ * The GKeyFile that was parsed from disk. We keep this around so that
+ * we can persist the changes back without destroying comments.
+ */
+ GKeyFile *key_file;
- guint writeback_handler;
- guint change_count;
+ /*
+ * If we removed items from the keyfile, we need to know that so that
+ * we persist it back to disk. We only persist back to disk if this bit
+ * is set or if any of our registered configs are "dirty".
+ *
+ * We try hard to avoid writing .buildconfig files unless we know the
+ * user did something to change a config. Otherwise we would liter
+ * everyone's projects with .buildconfig files.
+ */
+ guint key_file_dirty : 1;
};
-static void configuration_provider_iface_init (IdeConfigurationProviderInterface *);
+static gchar *
+gen_next_id (const gchar *id)
+{
+ g_auto(GStrv) parts = g_strsplit (id, "-", 0);
+ guint len = g_strv_length (parts);
+ const gchar *end;
+ guint64 n64;
-G_DEFINE_TYPE_WITH_CODE (IdeBuildconfigConfigurationProvider,
- ide_buildconfig_configuration_provider,
- IDE_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (IDE_TYPE_CONFIGURATION_PROVIDER,
- configuration_provider_iface_init))
+ if (len == 0)
+ goto add_suffix;
+
+ end = parts[len - 1];
+
+ n64 = g_ascii_strtoull (end, (gchar **)&end, 10);
+ if (n64 == 0 || n64 == G_MAXUINT64 || *end != 0)
+ goto add_suffix;
+
+ g_free (g_steal_pointer (&parts[len -1]));
+ parts[len -1] = g_strdup_printf ("%"G_GUINT64_FORMAT, n64+1);
+ return g_strjoinv ("-", parts);
+
+add_suffix:
+ return g_strdup_printf ("%s-2", id);
+}
+
+static gchar *
+get_next_id (IdeConfigurationManager *manager,
+ const gchar *id)
+{
+ g_autoptr(GPtrArray) tries = NULL;
+
+ g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
+
+ tries = g_ptr_array_new_with_free_func (g_free);
+
+ while (ide_configuration_manager_get_configuration (manager, id))
+ {
+ g_autofree gchar *next = gen_next_id (id);
+ id = next;
+ g_ptr_array_add (tries, g_steal_pointer (&next));
+ }
+
+ return g_strdup (id);
+}
+
+static void
+load_string (IdeConfiguration *config,
+ GKeyFile *key_file,
+ const gchar *group,
+ const gchar *key,
+ const gchar *property)
+{
+ g_assert (IDE_IS_CONFIGURATION (config));
+ g_assert (key_file != NULL);
+ g_assert (group != NULL);
+ g_assert (key != NULL);
+
+ if (g_key_file_has_key (key_file, group, key, NULL))
+ {
+ g_auto(GValue) value = G_VALUE_INIT;
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_value_take_string (&value, g_key_file_get_string (key_file, group, key, NULL));
+ g_object_set_property (G_OBJECT (config), property, &value);
+ }
+}
+
+static void
+load_strv (IdeConfiguration *config,
+ GKeyFile *key_file,
+ const gchar *group,
+ const gchar *key,
+ const gchar *property)
+{
+ g_assert (IDE_IS_CONFIGURATION (config));
+ g_assert (key_file != NULL);
+ g_assert (group != NULL);
+ g_assert (key != NULL);
+
+ if (g_key_file_has_key (key_file, group, key, NULL))
+ {
+ g_auto(GStrv) strv = NULL;
+ g_auto(GValue) value = G_VALUE_INIT;
+
+ strv = g_key_file_get_string_list (key_file, group, key, NULL, NULL);
+ g_value_init (&value, G_TYPE_STRV);
+ g_value_take_boxed (&value, g_steal_pointer (&strv));
+ g_object_set_property (G_OBJECT (config), property, &value);
+ }
+}
+
+static void
+load_environ (IdeConfiguration *config,
+ GKeyFile *key_file,
+ const gchar *group)
+{
+ IdeEnvironment *environment;
+ g_auto(GStrv) keys = NULL;
+ gsize len = 0;
+
+ g_assert (IDE_IS_CONFIGURATION (config));
+ g_assert (key_file != NULL);
+ g_assert (group != NULL);
+
+ environment = ide_configuration_get_environment (config);
+ keys = g_key_file_get_keys (key_file, group, &len, NULL);
+
+ for (gsize i = 0; i < len; i++)
+ {
+ g_autofree gchar *value = NULL;
+
+ value = g_key_file_get_string (key_file, group, keys[i], NULL);
+ if (value != NULL)
+ ide_environment_setenv (environment, keys [i], value);
+ }
+}
+
+static IdeConfiguration *
+ide_buildconfig_configuration_provider_create (IdeBuildconfigConfigurationProvider *self,
+ const gchar *config_id)
+{
+ g_autoptr(IdeConfiguration) config = NULL;
+ g_autofree gchar *env_group = NULL;
+ IdeContext *context;
+
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
+ g_assert (self->key_file != NULL);
+ g_assert (config_id != NULL);
+
+ context = ide_object_get_context (IDE_OBJECT (self));
+
+ config = g_object_new (IDE_TYPE_BUILDCONFIG_CONFIGURATION,
+ "context", context,
+ "id", config_id,
+ NULL);
+
+ load_string (config, self->key_file, config_id, "config-opts", "config-opts");
+ load_string (config, self->key_file, config_id, "device", "device-id");
+ load_string (config, self->key_file, config_id, "name", "display-name");
+ load_string (config, self->key_file, config_id, "run-opts", "run-opts");
+ load_string (config, self->key_file, config_id, "runtime", "runtime-id");
+ load_string (config, self->key_file, config_id, "prefix", "prefix");
+ load_string (config, self->key_file, config_id, "app-id", "app-id");
+ load_strv (config, self->key_file, config_id, "prebuild", "prebuild");
+ load_strv (config, self->key_file, config_id, "postbuild", "postbuild");
+
+ env_group = g_strdup_printf ("%s.environment", config_id);
+ if (g_key_file_has_group (self->key_file, env_group))
+ load_environ (config, self->key_file, env_group);
+
+ return g_steal_pointer (&config);
+}
+
+static void
+ide_buildconfig_configuration_provider_load_async (IdeConfigurationProvider *provider,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
+ g_autoptr(IdeConfiguration) fallback = NULL;
+ g_autoptr(GTask) task = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autofree gchar *path = NULL;
+ g_auto(GStrv) groups = NULL;
+ IdeContext *context;
+ gsize len;
+
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
+ g_assert (self->key_file == NULL);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, ide_buildconfig_configuration_provider_load_async);
+ g_task_set_priority (task, G_PRIORITY_LOW);
+
+ self->key_file = g_key_file_new ();
+
+ /*
+ * We could do this in a thread, but it's not really worth it. We want these
+ * configs loaded ASAP, and nothing can really progress until it's loaded
+ * anyway.
+ */
+
+ context = ide_object_get_context (IDE_OBJECT (self));
+ path = ide_context_build_filename (context, DOT_BUILDCONFIG, NULL);
+ if (!g_file_test (path, G_FILE_TEST_IS_REGULAR))
+ goto add_default;
+
+ if (!g_key_file_load_from_file (self->key_file, path, G_KEY_FILE_KEEP_COMMENTS, &error))
+ {
+ g_warning ("Failed to load .buildconfig: %s", error->message);
+ goto add_default;
+ }
+
+ groups = g_key_file_get_groups (self->key_file, &len);
+
+ for (gsize i = 0; i < len; i++)
+ {
+ g_autoptr(IdeConfiguration) config = NULL;
+ const gchar *group = groups[i];
+
+ if (strchr (group, '.') != NULL)
+ continue;
+
+ config = ide_buildconfig_configuration_provider_create (self, group);
+ ide_configuration_set_dirty (config, FALSE);
+ ide_configuration_provider_emit_added (provider, config);
+ }
+
+ if (self->configs->len > 0)
+ goto complete;
+
+add_default:
+ /* "Default" is not translated because .buildconfig can be checked in */
+ fallback = g_object_new (IDE_TYPE_BUILDCONFIG_CONFIGURATION,
+ "context", context,
+ "device-id", "local",
+ "display-name", "Default",
+ "id", "default",
+ "runtime-id", "host",
+ NULL);
+ ide_configuration_set_dirty (fallback, FALSE);
+ ide_configuration_provider_emit_added (provider, fallback);
+
+complete:
+ g_task_return_boolean (task, TRUE);
+}
+
+static gboolean
+ide_buildconfig_configuration_provider_load_finish (IdeConfigurationProvider *provider,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (provider));
+ g_assert (G_IS_TASK (result));
+ g_assert (g_task_is_valid (G_TASK (result), provider));
+
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
static void
ide_buildconfig_configuration_provider_save_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
+ GFile *file = (GFile *)object;
g_autoptr(GTask) task = user_data;
g_autoptr(GError) error = NULL;
- GFile *file = (GFile *)object;
g_assert (G_IS_FILE (file));
g_assert (G_IS_ASYNC_RESULT (result));
+ g_assert (G_IS_TASK (task));
if (!g_file_replace_contents_finish (file, result, NULL, &error))
g_task_return_error (task, g_steal_pointer (&error));
@@ -73,7 +325,7 @@ ide_buildconfig_configuration_provider_save_cb (GObject *object,
g_task_return_boolean (task, TRUE);
}
-void
+static void
ide_buildconfig_configuration_provider_save_async (IdeConfigurationProvider *provider,
GCancellable *cancellable,
GAsyncReadyCallback callback,
@@ -82,75 +334,86 @@ ide_buildconfig_configuration_provider_save_async (IdeConfigurationProvider *pro
IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
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;
g_autoptr(GError) error = NULL;
- gchar *data;
- gsize length = 0;
+ g_auto(GStrv) groups = NULL;
+ g_autofree gchar *path = NULL;
+ g_autofree gchar *data = NULL;
+ IdeConfigurationManager *manager;
IdeContext *context;
- IdeVcs *vcs;
- GFile *workdir;
-
- IDE_ENTRY;
+ gboolean dirty = FALSE;
+ gsize length = 0;
g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_assert (self->key_file != NULL);
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, ide_buildconfig_configuration_provider_save_async);
+ g_task_set_priority (task, G_PRIORITY_LOW);
+
+ dirty = self->key_file_dirty;
+
+ /* If no configs are dirty, short circuit to avoid writing any files to disk. */
+ for (guint i = 0; !dirty && i < self->configs->len; i++)
+ {
+ IdeConfiguration *config = g_ptr_array_index (self->configs, i);
+ dirty |= ide_configuration_get_dirty (config);
+ }
- if (self->configurations == NULL || self->change_count == 0)
+ if (!dirty)
{
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_BUILDCONFIG);
+ context = ide_object_get_context (IDE_OBJECT (self));
+ manager = ide_context_get_configuration_manager (context);
+ path = ide_context_build_filename (context, DOT_BUILDCONFIG, NULL);
+ file = g_file_new_for_path (path);
/*
- * NOTE:
+ * We keep the GKeyFile around from when we parsed .buildconfig, so that we
+ * can try to preserve comments and such when writing back.
*
- * 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.
+ * 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 (guint i = 0; i < self->configurations->len; i++)
+ for (guint i = 0; i < self->configs->len; i++)
{
- IdeConfiguration *configuration = g_ptr_array_index (self->configurations, i);
- IdeEnvironment *environment;
+ IdeConfiguration *config = g_ptr_array_index (self->configs, i);
+ g_autofree gchar *env_group = NULL;
+ const gchar *config_id;
+ IdeEnvironment *env;
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);
+ if (!ide_configuration_get_dirty (config))
+ continue;
+
+ config_id = ide_configuration_get_id (config);
+ env_group = g_strdup_printf ("%s.environment", config_id);
+ env = ide_configuration_get_environment (config);
/*
* 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);
+ g_hash_table_insert (group_names, g_strdup (config_id), NULL);
+ g_hash_table_insert (group_names, g_strdup (env_group), NULL);
#define PERSIST_STRING_KEY(key, getter) \
- g_key_file_set_string (self->key_file, group, key, \
- ide_configuration_##getter (configuration) ?: "")
+ g_key_file_set_string (self->key_file, config_id, key, \
+ ide_configuration_##getter (config) ?: "")
+#define PERSIST_STRV_KEY(key, getter) G_STMT_START { \
+ const gchar * const *val = ide_buildconfig_configuration_##getter (IDE_BUILDCONFIG_CONFIGURATION
(config)); \
+ gsize vlen = val ? g_strv_length ((gchar **)val) : 0; \
+ g_key_file_set_string_list (self->key_file, config_id, key, val, vlen); \
+} G_STMT_END
+
PERSIST_STRING_KEY ("name", get_display_name);
PERSIST_STRING_KEY ("device", get_device_id);
PERSIST_STRING_KEY ("runtime", get_runtime_id);
@@ -158,54 +421,58 @@ ide_buildconfig_configuration_provider_save_async (IdeConfigurationProvider *pro
PERSIST_STRING_KEY ("run-opts", get_run_opts);
PERSIST_STRING_KEY ("prefix", get_prefix);
PERSIST_STRING_KEY ("app-id", get_app_id);
+ PERSIST_STRV_KEY ("postbuild", get_postbuild);
+ PERSIST_STRV_KEY ("prebuild", get_prebuild);
+
#undef PERSIST_STRING_KEY
+#undef PERSIST_STRV_KEY
- if (configuration == ide_configuration_manager_get_current (self->manager))
- g_key_file_set_boolean (self->key_file, group, "default", TRUE);
+ if (config == ide_configuration_manager_get_current (manager))
+ g_key_file_set_boolean (self->key_file, config_id, "default", TRUE);
else
- g_key_file_remove_key (self->key_file, group, "default", NULL);
+ g_key_file_remove_key (self->key_file, config_id, "default", NULL);
- environment = ide_configuration_get_environment (configuration);
+ env = ide_configuration_get_environment (config);
/*
* 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))
+ if (g_key_file_has_group (self->key_file, env_group))
{
g_auto(GStrv) keys = NULL;
- if (NULL != (keys = g_key_file_get_keys (self->key_file, group_environ, NULL, NULL)))
+ if (NULL != (keys = g_key_file_get_keys (self->key_file, env_group, NULL, NULL)))
{
- for (j = 0; keys [j]; j++)
+ for (guint 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);
+ if (!ide_environment_getenv (env, keys [j]))
+ g_key_file_remove_key (self->key_file, env_group, keys [j], NULL);
}
}
}
- n_items = g_list_model_get_n_items (G_LIST_MODEL (environment));
+ n_items = g_list_model_get_n_items (G_LIST_MODEL (env));
- for (j = 0; j < n_items; j++)
+ for (guint 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);
+ var = g_list_model_get_item (G_LIST_MODEL (env), j);
key = ide_environment_variable_get_key (var);
value = ide_environment_variable_get_value (var);
if (!dzl_str_empty0 (key))
- g_key_file_set_string (self->key_file, group_environ, key, value ?: "");
+ g_key_file_set_string (self->key_file, env_group, key, value ?: "");
}
+
+ ide_configuration_set_dirty (config, FALSE);
}
- /*
- * Now truncate any old groups in the keyfile.
- */
+ /* Now truncate any old groups in the keyfile. */
if (NULL != (groups = g_key_file_get_groups (self->key_file, NULL)))
{
for (guint i = 0; groups [i]; i++)
@@ -215,13 +482,23 @@ ide_buildconfig_configuration_provider_save_async (IdeConfigurationProvider *pro
}
}
- if (NULL == (data = g_key_file_to_data (self->key_file, &length, &error)))
+ if (!(data = g_key_file_to_data (self->key_file, &length, &error)))
{
g_task_return_error (task, g_steal_pointer (&error));
- IDE_EXIT;
+ return;
}
- bytes = g_bytes_new_take (data, length);
+ self->key_file_dirty = FALSE;
+
+ if (length == 0)
+ {
+ /* Remove the file if it exists, since it would be empty */
+ g_file_delete (file, cancellable, NULL);
+ g_task_return_boolean (task, TRUE);
+ return;
+ }
+
+ bytes = g_bytes_new_take (g_steal_pointer (&data), length);
g_file_replace_contents_bytes_async (file,
bytes,
@@ -231,432 +508,243 @@ ide_buildconfig_configuration_provider_save_async (IdeConfigurationProvider *pro
cancellable,
ide_buildconfig_configuration_provider_save_cb,
g_steal_pointer (&task));
-
- IDE_EXIT;
}
-gboolean
+static gboolean
ide_buildconfig_configuration_provider_save_finish (IdeConfigurationProvider *provider,
GAsyncResult *result,
GError **error)
{
- IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
-
- g_return_val_if_fail (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self), FALSE);
- g_return_val_if_fail (G_IS_TASK (result), FALSE);
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (provider));
+ g_assert (G_IS_TASK (result));
+ g_assert (g_task_is_valid (G_TASK (result), provider));
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 (IDE_CONFIGURATION_PROVIDER (self), NULL, NULL, NULL);
-
- return G_SOURCE_REMOVE;
-}
-
static void
-ide_buildconfig_configuration_provider_queue_writeback (IdeBuildconfigConfigurationProvider *self)
+ide_buildconfig_configuration_provider_delete (IdeConfigurationProvider *provider,
+ IdeConfiguration *config)
{
- 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;
-}
+ IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
+ g_autoptr(IdeConfiguration) hold = NULL;
+ g_autofree gchar *env = NULL;
+ const gchar *config_id;
+ gboolean had_group;
-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++;
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION (config));
+ g_assert (self->key_file != NULL);
+ g_assert (self->configs->len > 0);
- ide_buildconfig_configuration_provider_queue_writeback (self);
-}
+ hold = g_object_ref (config);
-static void
-load_string (IdeConfiguration *configuration,
- GKeyFile *key_file,
- const gchar *group,
- const gchar *key,
- const gchar *property)
-{
- g_assert (IDE_IS_CONFIGURATION (configuration));
- g_assert (key_file != NULL);
- g_assert (group != NULL);
- g_assert (key != NULL);
-
- if (g_key_file_has_key (key_file, group, key, NULL))
+ if (!g_ptr_array_remove (self->configs, hold))
{
- g_auto(GValue) value = G_VALUE_INIT;
-
- g_value_init (&value, G_TYPE_STRING);
- g_value_take_string (&value, g_key_file_get_string (key_file, group, key, NULL));
- g_object_set_property (G_OBJECT (configuration), property, &value);
+ g_critical ("No such configuration %s",
+ ide_configuration_get_id (hold));
+ return;
}
-}
-static void
-load_environ (IdeConfiguration *configuration,
- GKeyFile *key_file,
- const gchar *group)
-{
- IdeEnvironment *environment;
- g_auto(GStrv) keys = NULL;
+ config_id = ide_configuration_get_id (config);
+ had_group = g_key_file_has_group (self->key_file, config_id);
+ env = g_strdup_printf ("%s.environment", config_id);
+ g_key_file_remove_group (self->key_file, config_id, NULL);
+ g_key_file_remove_group (self->key_file, env, NULL);
- g_assert (IDE_IS_CONFIGURATION (configuration));
- g_assert (key_file != NULL);
- g_assert (group != NULL);
-
- environment = ide_configuration_get_environment (configuration);
- keys = g_key_file_get_keys (key_file, group, NULL, NULL);
+ self->key_file_dirty = had_group;
- if (keys != NULL)
+ /*
+ * If we removed our last buildconfig, synthesize a new one to replace it so
+ * that we never have no configurations available. We add it before we remove
+ * @config so that we never have zero configurations available.
+ *
+ * At some point in the future we might want a read only NULL configuration
+ * for fallback, and group configs by type or something. But until we have
+ * designs for that, this will do.
+ */
+ if (self->configs->len == 0)
{
- guint i;
+ g_autoptr(IdeConfiguration) new_config = NULL;
+ IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
+
+ /* "Default" is not translated because .buildconfig can be checked in */
+ new_config = g_object_new (IDE_TYPE_BUILDCONFIG_CONFIGURATION,
+ "context", context,
+ "device-id", "local",
+ "display-name", "Default",
+ "id", "default",
+ "runtime-id", "host",
+ NULL);
- for (i = 0; keys [i]; i++)
- {
- g_autofree gchar *value = NULL;
-
- value = g_key_file_get_string (key_file, group, keys [i], NULL);
-
- if (value != NULL)
- ide_environment_setenv (environment, keys [i], value);
- }
+ /*
+ * Only persist this back if there was data in the keyfile
+ * before we were requested to delete the build-config.
+ */
+ ide_configuration_set_dirty (new_config, had_group);
+ ide_configuration_provider_emit_added (provider, new_config);
}
+
+ ide_configuration_provider_emit_removed (provider, hold);
}
-static gboolean
-ide_buildconfig_configuration_provider_load_group (IdeBuildconfigConfigurationProvider *self,
- GKeyFile *key_file,
- const gchar *group,
- GPtrArray *configs,
- GError **error)
+static void
+ide_buildconfig_configuration_provider_duplicate (IdeConfigurationProvider *provider,
+ IdeConfiguration *config)
{
- g_autoptr(IdeConfiguration) configuration = NULL;
- g_autofree gchar *env_group = NULL;
+ IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
+ g_autoptr(IdeConfiguration) new_config = NULL;
+ g_autofree GParamSpec **pspecs = NULL;
+ g_autofree gchar *new_config_id = NULL;
+ g_autofree gchar *new_name = NULL;
+ IdeConfigurationManager *manager;
+ const gchar *config_id;
+ const gchar *name;
IdeContext *context;
+ guint n_pspecs = 0;
g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
- g_assert (key_file != NULL);
- g_assert (group != NULL);
-
- context = ide_object_get_context (IDE_OBJECT (self->manager));
-
- configuration = g_object_new (IDE_TYPE_BUILDCONFIG_CONFIGURATION,
- "id", group,
- "context", context,
- NULL);
-
- load_string (configuration, key_file, group, "config-opts", "config-opts");
- load_string (configuration, key_file, group, "device", "device-id");
- load_string (configuration, key_file, group, "name", "display-name");
- load_string (configuration, key_file, group, "run-opts", "run-opts");
- load_string (configuration, key_file, group, "runtime", "runtime-id");
- load_string (configuration, key_file, group, "prefix", "prefix");
- load_string (configuration, key_file, group, "app-id", "app-id");
-
- if (g_key_file_has_key (key_file, group, "prebuild", NULL))
- {
- g_auto(GStrv) commands = NULL;
-
- commands = g_key_file_get_string_list (key_file, group, "prebuild", NULL, NULL);
- ide_buildconfig_configuration_set_prebuild (IDE_BUILDCONFIG_CONFIGURATION (configuration),
- (const gchar * const *)commands);
- }
-
- if (g_key_file_has_key (key_file, group, "postbuild", NULL))
- {
- g_auto(GStrv) commands = NULL;
-
- commands = g_key_file_get_string_list (key_file, group, "postbuild", NULL, NULL);
- ide_buildconfig_configuration_set_postbuild (IDE_BUILDCONFIG_CONFIGURATION (configuration),
- (const gchar * const *)commands);
- }
-
- env_group = g_strdup_printf ("%s.environment", group);
+ g_assert (IDE_IS_CONFIGURATION (config));
+ g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION (config));
- if (g_key_file_has_group (key_file, env_group))
- load_environ (configuration, key_file, env_group);
+ context = ide_object_get_context (IDE_OBJECT (self));
+ g_assert (IDE_IS_CONTEXT (context));
- ide_configuration_set_dirty (configuration, FALSE);
+ manager = ide_context_get_configuration_manager (context);
+ g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
- if (g_key_file_get_boolean (key_file, group, "default", NULL))
- g_object_set_data (G_OBJECT (configuration), "WAS_DEFAULT", GINT_TO_POINTER (TRUE));
+ config_id = ide_configuration_get_id (config);
+ g_return_if_fail (config_id != NULL);
- g_signal_connect_object (configuration,
- "changed",
- G_CALLBACK (ide_buildconfig_configuration_provider_changed),
- self,
- G_CONNECT_SWAPPED);
+ new_config_id = get_next_id (manager, config_id);
+ g_return_if_fail (new_config_id != NULL);
- g_ptr_array_add (configs, g_steal_pointer (&configuration));
+ name = ide_configuration_get_display_name (config);
+ /* translators: %s is replaced with the name of the configuration */
+ new_name = g_strdup_printf (_("%s (Copy)"), name);
- return TRUE;
-}
-
-static gboolean
-ide_buildconfig_configuration_provider_restore (IdeBuildconfigConfigurationProvider *self,
- GFile *file,
- GPtrArray *configs,
- GCancellable *cancellable,
- GError **error)
-{
- g_autofree gchar *contents = NULL;
- g_auto(GStrv) groups = NULL;
- gsize length = 0;
- guint i;
+ new_config = g_object_new (IDE_TYPE_BUILDCONFIG_CONFIGURATION,
+ "id", new_config_id,
+ "context", context,
+ "display-name", new_name,
+ NULL);
- IDE_ENTRY;
+ pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (new_config), &n_pspecs);
- g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
- g_assert (self->key_file == NULL);
- g_assert (G_IS_FILE (file));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- self->key_file = g_key_file_new ();
-
- if (!g_file_load_contents (file, cancellable, &contents, &length, NULL, error))
- IDE_RETURN (FALSE);
+ for (guint i = 0; i < n_pspecs; i++)
+ {
+ GParamSpec *pspec = pspecs[i];
- if (!g_key_file_load_from_data (self->key_file,
- contents,
- length,
- G_KEY_FILE_KEEP_COMMENTS,
- error))
- IDE_RETURN (FALSE);
+ if (g_str_equal (pspec->name, "context") ||
+ g_str_equal (pspec->name, "id") ||
+ g_str_equal (pspec->name, "display-name") ||
+ g_type_is_a (pspec->value_type, G_TYPE_BOXED) ||
+ g_type_is_a (pspec->value_type, G_TYPE_OBJECT))
+ continue;
- groups = g_key_file_get_groups (self->key_file, NULL);
- for (i = 0; groups [i]; i++)
- {
- if (g_str_has_suffix (groups [i], ".environment"))
- continue;
+ if ((pspec->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE &&
+ (pspec->flags & G_PARAM_CONSTRUCT_ONLY) == 0)
+ {
+ GValue value = G_VALUE_INIT;
- if (!ide_buildconfig_configuration_provider_load_group (self, self->key_file, groups [i], configs,
error))
- IDE_RETURN (FALSE);
+ g_value_init (&value, pspec->value_type);
+ g_object_get_property (G_OBJECT (config), pspec->name, &value);
+ g_object_set_property (G_OBJECT (new_config), pspec->name, &value);
+ }
}
- IDE_RETURN (TRUE);
+ ide_configuration_set_dirty (new_config, TRUE);
+ ide_configuration_provider_emit_added (provider, new_config);
}
static void
-ide_buildconfig_configuration_provider_load_worker (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
+ide_buildconfig_configuration_provider_unload (IdeConfigurationProvider *provider)
{
- IdeBuildconfigConfigurationProvider *self = source_object;
- g_autoptr(GFile) settings_file = NULL;
- g_autoptr(GError) error = NULL;
+ IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
g_autoptr(GPtrArray) configs = NULL;
- IdeConfigurationManager *manager = task_data;
- IdeContext *context;
- IdeVcs *vcs;
- GFile *workdir;
-
- IDE_ENTRY;
- g_assert (G_IS_TASK (task));
g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+ g_assert (self->configs != NULL);
- configs = g_ptr_array_new_with_free_func (g_object_unref);
+ configs = g_steal_pointer (&self->configs);
+ self->configs = g_ptr_array_new_with_free_func (g_object_unref);
- context = ide_object_get_context (IDE_OBJECT (manager));
- vcs = ide_context_get_vcs (context);
- workdir = ide_vcs_get_working_directory (vcs);
- settings_file = g_file_get_child (workdir, DOT_BUILDCONFIG);
-
- if (g_file_query_exists (settings_file, cancellable))
+ for (guint i = 0; i < configs->len; i++)
{
- if (!ide_buildconfig_configuration_provider_restore (self, settings_file, configs, cancellable,
&error))
- {
- g_task_return_error (task, g_steal_pointer (&error));
- IDE_EXIT;
- }
+ IdeConfiguration *config = g_ptr_array_index (configs, i);
+ ide_configuration_provider_emit_removed (provider, config);
}
-
- g_task_return_pointer (task, g_steal_pointer (&configs), (GDestroyNotify)g_ptr_array_unref);
-
- IDE_EXIT;
}
static void
-ide_buildconfig_configuration_provider_load_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
+ide_buildconfig_configuration_provider_added (IdeConfigurationProvider *provider,
+ IdeConfiguration *config)
{
- IdeBuildconfigConfigurationProvider *self;
- g_autoptr(GPtrArray) ar = NULL;
- g_autoptr(GError) error = NULL;
- g_autoptr(GTask) task = user_data;
-
- IDE_ENTRY;
-
- g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (object));
- g_assert (G_IS_TASK (result));
- g_assert (G_IS_TASK (task));
-
- ar = g_task_propagate_pointer (G_TASK (result), &error);
- self = g_task_get_source_object (G_TASK (result));
+ IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
- g_assert (self->configurations == NULL);
-
- if (ar != NULL && self->manager != NULL)
- {
- for (guint i = 0; i < ar->len; i++)
- {
- IdeConfiguration *config = g_ptr_array_index (ar, i);
-
- g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION (config));
-
- ide_configuration_manager_add (self->manager, config);
-
- if (g_object_get_data (G_OBJECT (config), "WAS_DEFAULT"))
- {
- ide_configuration_manager_set_current (self->manager, config);
- g_object_set_data (G_OBJECT (config), "WAS_DEFAULT", NULL);
- }
- }
- }
+ g_assert (IDE_IS_CONFIGURATION (config));
+ g_assert (self->configs != NULL);
- self->configurations = g_steal_pointer (&ar);
-
- if (error != NULL)
- g_task_return_error (task, g_steal_pointer (&error));
- else
- g_task_return_boolean (task, TRUE);
-
- IDE_EXIT;
+ g_ptr_array_add (self->configs, g_object_ref (config));
}
static void
-ide_buildconfig_configuration_provider_load_async (IdeConfigurationProvider *provider,
- IdeConfigurationManager *manager,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
+ide_buildconfig_configuration_provider_removed (IdeConfigurationProvider *provider,
+ IdeConfiguration *config)
{
IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
- g_autoptr(GTask) parent_task = NULL;
- g_autoptr(GTask) task = NULL;
-
- IDE_ENTRY;
g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
- g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
- dzl_set_weak_pointer (&self->manager, manager);
-
- /* This task is needed so the caller knows when the load finishes */
- parent_task = g_task_new (self, cancellable, callback, user_data);
+ g_assert (IDE_IS_CONFIGURATION (config));
+ g_assert (self->configs != NULL);
- /* This task is used to run the load_worker in its own thread */
- task = g_task_new (self, cancellable, ide_buildconfig_configuration_provider_load_cb, g_steal_pointer
(&parent_task));
- g_task_set_source_tag (task, ide_buildconfig_configuration_provider_load_async);
- g_task_set_task_data (task, g_object_ref (manager), g_object_unref);
- g_task_run_in_thread (task, ide_buildconfig_configuration_provider_load_worker);
-
- IDE_EXIT;
-}
-
-gboolean
-ide_buildconfig_configuration_provider_load_finish (IdeConfigurationProvider *provider,
- GAsyncResult *result,
- GError **error)
-{
- IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
-
- 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);
+ /* It's possible we already removed it by now */
+ g_ptr_array_remove (self->configs, config);
}
static void
-ide_buildconfig_configuration_provider_unload (IdeConfigurationProvider *provider,
- IdeConfigurationManager *manager)
+configuration_provider_iface_init (IdeConfigurationProviderInterface *iface)
{
- IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)provider;
-
- IDE_ENTRY;
-
- g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
-
- dzl_clear_source (&self->writeback_handler);
-
- if (self->configurations != NULL)
- {
- for (guint i= 0; i < self->configurations->len; i++)
- {
- IdeConfiguration *configuration = g_ptr_array_index (self->configurations, i);
-
- ide_configuration_manager_remove (manager, configuration);
- }
- }
-
- g_clear_pointer (&self->configurations, g_ptr_array_unref);
-
- dzl_clear_weak_pointer (&self->manager);
-
- IDE_EXIT;
+ iface->added = ide_buildconfig_configuration_provider_added;
+ iface->removed = ide_buildconfig_configuration_provider_removed;
+ iface->load_async = ide_buildconfig_configuration_provider_load_async;
+ iface->load_finish = ide_buildconfig_configuration_provider_load_finish;
+ iface->save_async = ide_buildconfig_configuration_provider_save_async;
+ iface->save_finish = ide_buildconfig_configuration_provider_save_finish;
+ iface->delete = ide_buildconfig_configuration_provider_delete;
+ iface->duplicate = ide_buildconfig_configuration_provider_duplicate;
+ iface->unload = ide_buildconfig_configuration_provider_unload;
}
-void
-ide_buildconfig_configuration_provider_track_config (IdeBuildconfigConfigurationProvider *self,
- IdeBuildconfigConfiguration *config)
+G_DEFINE_TYPE_WITH_CODE (IdeBuildconfigConfigurationProvider,
+ ide_buildconfig_configuration_provider,
+ IDE_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (IDE_TYPE_CONFIGURATION_PROVIDER,
+ configuration_provider_iface_init))
+
+static void
+ide_buildconfig_configuration_provider_finalize (GObject *object)
{
- g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION (config));
+ IdeBuildconfigConfigurationProvider *self = (IdeBuildconfigConfigurationProvider *)object;
- g_signal_connect_object (config,
- "changed",
- G_CALLBACK (ide_buildconfig_configuration_provider_changed),
- self,
- G_CONNECT_SWAPPED);
+ g_clear_pointer (&self->configs, g_ptr_array_unref);
+ g_clear_pointer (&self->key_file, g_key_file_free);
- g_ptr_array_add (self->configurations, g_object_ref (config));
+ G_OBJECT_CLASS (ide_buildconfig_configuration_provider_parent_class)->finalize (object);
}
static void
ide_buildconfig_configuration_provider_class_init (IdeBuildconfigConfigurationProviderClass *klass)
{
-}
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
-static void
-ide_buildconfig_configuration_provider_init (IdeBuildconfigConfigurationProvider *self)
-{
+ object_class->finalize = ide_buildconfig_configuration_provider_finalize;
}
static void
-configuration_provider_iface_init (IdeConfigurationProviderInterface *iface)
+ide_buildconfig_configuration_provider_init (IdeBuildconfigConfigurationProvider *self)
{
- iface->load_async = ide_buildconfig_configuration_provider_load_async;
- iface->load_finish = ide_buildconfig_configuration_provider_load_finish;
- iface->unload = ide_buildconfig_configuration_provider_unload;
- iface->save_async = ide_buildconfig_configuration_provider_save_async;
- iface->save_finish = ide_buildconfig_configuration_provider_save_finish;
+ self->configs = g_ptr_array_new_with_free_func (g_object_unref);
}
diff --git a/src/libide/buildconfig/ide-buildconfig-configuration-provider.h
b/src/libide/buildconfig/ide-buildconfig-configuration-provider.h
index 836c03dd0..ce8f3e49d 100644
--- a/src/libide/buildconfig/ide-buildconfig-configuration-provider.h
+++ b/src/libide/buildconfig/ide-buildconfig-configuration-provider.h
@@ -18,13 +18,7 @@
#pragma once
-#include <glib.h>
-
-#include "ide-version-macros.h"
-
-#include "ide-types.h"
-
-#include "buildconfig/ide-buildconfig-configuration.h"
+#include "ide-object.h"
G_BEGIN_DECLS
@@ -32,8 +26,4 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (IdeBuildconfigConfigurationProvider, ide_buildconfig_configuration_provider, IDE,
BUILDCONFIG_CONFIGURATION_PROVIDER, IdeObject)
-IDE_AVAILABLE_IN_ALL
-void ide_buildconfig_configuration_provider_track_config (IdeBuildconfigConfigurationProvider *self,
- IdeBuildconfigConfiguration *config);
-
G_END_DECLS
diff --git a/src/libide/buildconfig/ide-buildconfig-configuration.c
b/src/libide/buildconfig/ide-buildconfig-configuration.c
index c08b7ec27..293fb5fe9 100644
--- a/src/libide/buildconfig/ide-buildconfig-configuration.c
+++ b/src/libide/buildconfig/ide-buildconfig-configuration.c
@@ -23,6 +23,7 @@
struct _IdeBuildconfigConfiguration
{
IdeConfiguration parent_instance;
+
gchar **prebuild;
gchar **postbuild;
};
@@ -113,7 +114,7 @@ ide_buildconfig_configuration_class_init (IdeBuildconfigConfigurationClass *klas
g_param_spec_boxed ("postbuild", NULL, NULL,
G_TYPE_STRV,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
+
g_object_class_install_properties (object_class, N_PROPS, properties);
}
diff --git a/src/libide/buildui/buildui.plugin b/src/libide/buildui/buildui.plugin
index 31524ca32..9b10a2ca1 100644
--- a/src/libide/buildui/buildui.plugin
+++ b/src/libide/buildui/buildui.plugin
@@ -8,5 +8,3 @@ Depends=editor
Hidden=true
Builtin=true
Embedded=ide_build_tool_register_types
-X-Tool-Name=build
-X-Tool-Description=Build a project
diff --git a/src/libide/buildui/ide-build-perspective.c b/src/libide/buildui/ide-build-perspective.c
index f59166dbc..3694d8b42 100644
--- a/src/libide/buildui/ide-build-perspective.c
+++ b/src/libide/buildui/ide-build-perspective.c
@@ -211,10 +211,12 @@ duplicate_configuration (GSimpleAction *action,
if (self->configuration != NULL)
{
- g_autoptr(IdeConfiguration) copy = NULL;
+ IdeContext *context;
+ IdeConfigurationManager *config_manager;
- copy = ide_configuration_duplicate (self->configuration);
- ide_configuration_manager_add (self->configuration_manager, copy);
+ context = ide_widget_get_context (GTK_WIDGET (self));
+ config_manager = ide_context_get_configuration_manager (context);
+ ide_configuration_manager_duplicate (config_manager, self->configuration);
}
}
@@ -236,7 +238,7 @@ delete_configuration (GSimpleAction *action,
* self->configuration will change during this call.
*/
config = g_object_ref (self->configuration);
- ide_configuration_manager_remove (self->configuration_manager, config);
+ ide_configuration_manager_delete (self->configuration_manager, config);
/*
* Switch to the first configuration in the list. The configuration
diff --git a/src/libide/buildui/ide-build-plugin.c b/src/libide/buildui/ide-build-plugin.c
index dd8ba146b..b17ececd8 100644
--- a/src/libide/buildui/ide-build-plugin.c
+++ b/src/libide/buildui/ide-build-plugin.c
@@ -27,9 +27,6 @@
void
ide_build_tool_register_types (PeasObjectModule *module)
{
- peas_object_module_register_extension_type (module,
- IDE_TYPE_APPLICATION_TOOL,
- IDE_TYPE_BUILD_TOOL);
peas_object_module_register_extension_type (module,
IDE_TYPE_WORKBENCH_ADDIN,
IDE_TYPE_BUILD_WORKBENCH_ADDIN);
diff --git a/src/libide/buildui/meson.build b/src/libide/buildui/meson.build
index cbedb1f06..e82edc676 100644
--- a/src/libide/buildui/meson.build
+++ b/src/libide/buildui/meson.build
@@ -12,8 +12,6 @@ buildui_private_sources = [
'ide-build-plugin.c',
'ide-build-stage-row.c',
'ide-build-stage-row.h',
- 'ide-build-tool.c',
- 'ide-build-tool.h',
'ide-build-workbench-addin.c',
'ide-build-workbench-addin.h',
'ide-environment-editor-row.c',
diff --git a/src/libide/config/ide-configuration-manager.c b/src/libide/config/ide-configuration-manager.c
index 89baafa75..eefc1df41 100644
--- a/src/libide/config/ide-configuration-manager.c
+++ b/src/libide/config/ide-configuration-manager.c
@@ -24,22 +24,33 @@
#include "ide-context.h"
#include "ide-debug.h"
+#include "application/ide-application.h"
#include "config/ide-configuration-manager.h"
#include "config/ide-configuration.h"
#include "config/ide-configuration-provider.h"
-
#include "buildconfig/ide-buildconfig-configuration.h"
#include "buildconfig/ide-buildconfig-configuration-provider.h"
+#define WRITEBACK_DELAY_SEC 2
+
struct _IdeConfigurationManager
{
GObject parent_instance;
- GPtrArray *configurations;
+ GCancellable *cancellable;
+ GArray *configs;
IdeConfiguration *current;
- PeasExtensionSet *extensions;
+ PeasExtensionSet *providers;
+
+ guint queued_save_source;
};
+typedef struct
+{
+ IdeConfigurationProvider *provider;
+ IdeConfiguration *config;
+} ConfigInfo;
+
static void async_initable_iface_init (GAsyncInitableIface *iface);
static void list_model_iface_init (GListModelInterface *iface);
static void ide_configuration_manager_save_tick (GTask *task);
@@ -64,47 +75,12 @@ static GParamSpec *properties [LAST_PROP];
static guint signals [N_SIGNALS];
static void
-ide_configuration_manager_track_buildconfig (PeasExtensionSet *set,
- PeasPluginInfo *plugin_info,
- PeasExtension *exten,
- gpointer user_data)
-{
- IdeConfigurationProvider *provider = (IdeConfigurationProvider *)exten;
- IdeConfiguration *config = user_data;
-
- g_assert (PEAS_IS_EXTENSION_SET (set));
- g_assert (plugin_info != NULL);
- g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
- g_assert (!config || IDE_IS_BUILDCONFIG_CONFIGURATION (config));
-
- if (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (provider) && config != NULL)
- ide_buildconfig_configuration_provider_track_config (IDE_BUILDCONFIG_CONFIGURATION_PROVIDER (provider),
- IDE_BUILDCONFIG_CONFIGURATION (config));
-}
-
-static void
-ide_configuration_manager_add_default (IdeConfigurationManager *self)
+config_info_clear (gpointer data)
{
- g_autoptr(IdeBuildconfigConfiguration) config = NULL;
- IdeContext *context;
-
- g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+ ConfigInfo *info = data;
- context = ide_object_get_context (IDE_OBJECT (self));
- config = g_object_new (IDE_TYPE_BUILDCONFIG_CONFIGURATION,
- "id", "default",
- "context", context,
- "device-id", "local",
- "runtime-id", "host",
- NULL);
- ide_configuration_set_display_name (IDE_CONFIGURATION (config), _("Default"));
- ide_configuration_manager_add (self, IDE_CONFIGURATION (config));
- if (self->configurations->len == 1)
- ide_configuration_manager_set_current (self, IDE_CONFIGURATION (config));
-
- peas_extension_set_foreach (self->extensions,
- ide_configuration_manager_track_buildconfig,
- config);
+ g_clear_object (&info->config);
+ g_clear_object (&info->provider);
}
static void
@@ -186,8 +162,8 @@ ide_configuration_manager_save_async (IdeConfigurationManager *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- g_autoptr(GTask) task = NULL;
g_autoptr(GPtrArray) providers = NULL;
+ g_autoptr(GTask) task = NULL;
IDE_ENTRY;
@@ -196,22 +172,18 @@ ide_configuration_manager_save_async (IdeConfigurationManager *self,
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, ide_configuration_manager_save_async);
+ g_task_set_priority (task, G_PRIORITY_LOW);
providers = g_ptr_array_new_with_free_func (g_object_unref);
-
- peas_extension_set_foreach (self->extensions,
+ peas_extension_set_foreach (self->providers,
ide_configuration_manager_collect_providers,
providers);
+ g_task_set_task_data (task, g_ptr_array_ref (providers), (GDestroyNotify)g_ptr_array_unref);
if (providers->len == 0)
- {
- g_task_return_boolean (task, TRUE);
- IDE_EXIT;
- }
-
- g_task_set_task_data (task, g_steal_pointer (&providers), (GDestroyNotify)g_ptr_array_unref);
-
- ide_configuration_manager_save_tick (task);
+ g_task_return_boolean (task, TRUE);
+ else
+ ide_configuration_manager_save_tick (task);
IDE_EXIT;
}
@@ -244,23 +216,30 @@ ide_configuration_manager_get_configuration (IdeConfigurationManager *self,
g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
g_return_val_if_fail (id != NULL, NULL);
- for (guint i = 0; i < self->configurations->len; i++)
+ for (guint i = 0; i < self->configs->len; i++)
{
- IdeConfiguration *config = g_ptr_array_index (self->configurations, i);
- const gchar *config_id;
-
- g_assert (config != NULL);
- g_assert (IDE_IS_CONFIGURATION (config));
+ const ConfigInfo *info = &g_array_index (self->configs, ConfigInfo, i);
- config_id = ide_configuration_get_id (config);
+ g_assert (IDE_IS_CONFIGURATION (info->config));
- if (dzl_str_equal0 (config_id, id))
- return config;
+ if (dzl_str_equal0 (id, ide_configuration_get_id (info->config)))
+ return info->config;
}
return NULL;
}
+static const gchar *
+ide_configuration_manager_get_display_name (IdeConfigurationManager *self)
+{
+ g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
+
+ if (self->current != NULL)
+ return ide_configuration_get_display_name (self->current);
+
+ return "";
+}
+
static void
ide_configuration_manager_notify_display_name (IdeConfigurationManager *self,
GParamSpec *pspec,
@@ -272,12 +251,23 @@ ide_configuration_manager_notify_display_name (IdeConfigurationManager *self,
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CURRENT_DISPLAY_NAME]);
}
+static void
+ide_configuration_manager_dispose (GObject *object)
+{
+ IdeConfigurationManager *self = (IdeConfigurationManager *)object;
+
+ g_cancellable_cancel (self->cancellable);
+
+ G_OBJECT_CLASS (ide_configuration_manager_parent_class)->dispose (object);
+}
+
static void
ide_configuration_manager_finalize (GObject *object)
{
IdeConfigurationManager *self = (IdeConfigurationManager *)object;
- g_clear_pointer (&self->configurations, g_ptr_array_unref);
+ g_clear_object (&self->cancellable);
+ g_clear_pointer (&self->configs, g_array_unref);
if (self->current != NULL)
{
@@ -306,8 +296,7 @@ ide_configuration_manager_get_property (GObject *object,
case PROP_CURRENT_DISPLAY_NAME:
{
- IdeConfiguration *current = ide_configuration_manager_get_current (self);
- g_value_set_string (value, ide_configuration_get_display_name (current));
+ g_value_set_string (value, ide_configuration_manager_get_display_name (self));
break;
}
@@ -340,6 +329,7 @@ ide_configuration_manager_class_init (IdeConfigurationManagerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->dispose = ide_configuration_manager_dispose;
object_class->finalize = ide_configuration_manager_finalize;
object_class->get_property = ide_configuration_manager_get_property;
object_class->set_property = ide_configuration_manager_set_property;
@@ -349,7 +339,7 @@ ide_configuration_manager_class_init (IdeConfigurationManagerClass *klass)
"Current",
"The current configuration for the context",
IDE_TYPE_CONFIGURATION,
- (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
properties [PROP_CURRENT_DISPLAY_NAME] =
g_param_spec_string ("current-display-name",
@@ -362,6 +352,7 @@ ide_configuration_manager_class_init (IdeConfigurationManagerClass *klass)
/**
* IdeConfigurationManager::invalidate:
+ * @self: an #IdeConfigurationManager
*
* This signal is emitted any time a new configuration is selected or the
* currently selected configurations state changes.
@@ -370,13 +361,17 @@ ide_configuration_manager_class_init (IdeConfigurationManagerClass *klass)
g_signal_new ("invalidate",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
- 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
static void
ide_configuration_manager_init (IdeConfigurationManager *self)
{
- self->configurations = g_ptr_array_new_with_free_func (g_object_unref);
+ self->cancellable = g_cancellable_new ();
+ self->configs = g_array_new (FALSE, FALSE, sizeof (ConfigInfo));
+ g_array_set_clear_func (self->configs, config_info_clear);
}
static GType
@@ -391,8 +386,9 @@ ide_configuration_manager_get_n_items (GListModel *model)
IdeConfigurationManager *self = (IdeConfigurationManager *)model;
g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+ g_assert (self->configs != NULL);
- return self->configurations->len;
+ return self->configs->len;
}
static gpointer
@@ -400,11 +396,14 @@ ide_configuration_manager_get_item (GListModel *model,
guint position)
{
IdeConfigurationManager *self = (IdeConfigurationManager *)model;
+ const ConfigInfo *info;
g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
- g_return_val_if_fail (position < self->configurations->len, NULL);
+ g_return_val_if_fail (position < self->configs->len, NULL);
+
+ info = &g_array_index (self->configs, ConfigInfo, position);
- return g_object_ref (g_ptr_array_index (self->configurations, position));
+ return g_object_ref (info->config);
}
static void
@@ -415,12 +414,107 @@ list_model_iface_init (GListModelInterface *iface)
iface->get_item = ide_configuration_manager_get_item;
}
+static gboolean
+ide_configuration_manager_do_save (gpointer data)
+{
+ IdeConfigurationManager *self = data;
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+
+ self->queued_save_source = 0;
+
+ ide_configuration_manager_save_async (self, NULL, NULL, NULL);
+
+ IDE_RETURN (G_SOURCE_REMOVE);
+}
+
static void
-ide_configuration_manager_load_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
+ide_configuration_manager_changed (IdeConfigurationManager *self,
+ IdeConfiguration *config)
+{
+ g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+ g_assert (IDE_IS_CONFIGURATION (config));
+
+ g_signal_emit (self, signals [INVALIDATE], 0);
+
+ dzl_clear_source (&self->queued_save_source);
+ self->queued_save_source =
+ g_timeout_add_seconds_full (G_PRIORITY_LOW,
+ WRITEBACK_DELAY_SEC,
+ ide_configuration_manager_do_save,
+ g_object_ref (self),
+ g_object_unref);
+}
+
+static void
+ide_configuration_manager_config_added (IdeConfigurationManager *self,
+ IdeConfiguration *config,
+ IdeConfigurationProvider *provider)
+{
+ ConfigInfo info = {0};
+
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+ g_assert (IDE_IS_CONFIGURATION (config));
+ g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
+
+ g_signal_connect_object (config,
+ "changed",
+ G_CALLBACK (ide_configuration_manager_changed),
+ self,
+ G_CONNECT_SWAPPED);
+
+ info.provider = g_object_ref (provider);
+ info.config = g_object_ref (config);
+ g_array_append_val (self->configs, info);
+
+ g_list_model_items_changed (G_LIST_MODEL (self), self->configs->len - 1, 0, 1);
+
+ if (self->current == NULL)
+ ide_configuration_manager_set_current (self, config);
+
+ IDE_EXIT;
+}
+
+static void
+ide_configuration_manager_config_removed (IdeConfigurationManager *self,
+ IdeConfiguration *config,
+ IdeConfigurationProvider *provider)
+{
+ IDE_ENTRY;
+
+ g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+ g_assert (IDE_IS_CONFIGURATION (config));
+ g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
+
+ for (guint i = 0; i < self->configs->len; i++)
+ {
+ const ConfigInfo *info = &g_array_index (self->configs, ConfigInfo, i);
+
+ if (info->provider == provider && info->config == config)
+ {
+ g_signal_handlers_disconnect_by_func (config,
+ G_CALLBACK (ide_configuration_manager_changed),
+ self);
+ g_array_remove_index (self->configs, i);
+ g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
+ break;
+ }
+ }
+
+ IDE_EXIT;
+}
+
+static void
+ide_configuration_manager_provider_load_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
IdeConfigurationProvider *provider = (IdeConfigurationProvider *)object;
+ IdeContext *context;
g_autoptr(IdeConfigurationManager) self = user_data;
g_autoptr(GError) error = NULL;
@@ -430,47 +524,105 @@ ide_configuration_manager_load_cb (GObject *object,
g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
g_assert (G_IS_TASK (result));
+ context = ide_object_get_context (IDE_OBJECT (self));
+
if (!ide_configuration_provider_load_finish (provider, result, &error))
- g_warning ("%s failed to initialize: %s",
- G_OBJECT_TYPE_NAME (provider), error->message);
+ ide_context_warning (context,
+ "Failed to initialize config provider: %s: %s",
+ G_OBJECT_TYPE_NAME (provider), error->message);
IDE_EXIT;
}
static void
-ide_configuration_manager_extension_added (PeasExtensionSet *set,
- PeasPluginInfo *plugin_info,
- PeasExtension *exten,
- gpointer user_data)
+provider_connect (IdeConfigurationManager *self,
+ IdeConfigurationProvider *provider)
+{
+ g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+ g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
+
+ g_signal_connect_object (provider,
+ "added",
+ G_CALLBACK (ide_configuration_manager_config_added),
+ self,
+ G_CONNECT_SWAPPED);
+ g_signal_connect_object (provider,
+ "removed",
+ G_CALLBACK (ide_configuration_manager_config_removed),
+ self,
+ G_CONNECT_SWAPPED);
+}
+
+static void
+provider_disconnect (IdeConfigurationManager *self,
+ IdeConfigurationProvider *provider)
+{
+ g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+ g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
+
+ g_signal_handlers_disconnect_by_func (provider,
+ G_CALLBACK (ide_configuration_manager_config_added),
+ self);
+ g_signal_handlers_disconnect_by_func (provider,
+ G_CALLBACK (ide_configuration_manager_config_removed),
+ self);
+}
+
+static void
+ide_configuration_manager_provider_added (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
{
IdeConfigurationManager *self = user_data;
IdeConfigurationProvider *provider = (IdeConfigurationProvider *)exten;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (PEAS_IS_EXTENSION_SET (set));
g_assert (plugin_info != NULL);
g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
+ provider_connect (self, provider);
+
ide_configuration_provider_load_async (provider,
- self,
- NULL,
- ide_configuration_manager_load_cb,
+ self->cancellable,
+ ide_configuration_manager_provider_load_cb,
g_object_ref (self));
}
static void
-ide_configuration_manager_extension_removed (PeasExtensionSet *set,
- PeasPluginInfo *plugin_info,
- PeasExtension *exten,
- gpointer user_data)
+ide_configuration_manager_provider_removed (PeasExtensionSet *set,
+ PeasPluginInfo *plugin_info,
+ PeasExtension *exten,
+ gpointer user_data)
{
IdeConfigurationManager *self = user_data;
IdeConfigurationProvider *provider = (IdeConfigurationProvider *)exten;
+ g_autoptr(IdeConfigurationProvider) hold = NULL;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (PEAS_IS_EXTENSION_SET (set));
g_assert (plugin_info != NULL);
g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
- ide_configuration_provider_unload (provider, self);
+ hold = g_object_ref (provider);
+
+ ide_configuration_provider_unload (provider);
+
+ provider_disconnect (self, provider);
+
+ for (guint i = self->configs->len; i > 0; i--)
+ {
+ const ConfigInfo *info = &g_array_index (self->configs, ConfigInfo, i - 1);
+
+ if (info->provider == provider)
+ {
+ g_warning ("%s failed to remove configuration \"%s\"",
+ G_OBJECT_TYPE_NAME (provider),
+ ide_configuration_get_id (info->config));
+ g_array_remove_index (self->configs, i);
+ }
+ }
}
static void
@@ -483,9 +635,11 @@ ide_configuration_manager_init_load_cb (GObject *object,
g_autoptr(GError) error = NULL;
g_autoptr(GTask) task = user_data;
GPtrArray *providers;
+ IdeContext *context;
IDE_ENTRY;
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
g_assert (G_IS_ASYNC_RESULT (result));
g_assert (G_IS_TASK (task));
@@ -493,18 +647,24 @@ ide_configuration_manager_init_load_cb (GObject *object,
self = g_task_get_source_object (task);
g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
+ context = ide_object_get_context (IDE_OBJECT (self));
+ g_assert (IDE_IS_CONTEXT (context));
+
if (!ide_configuration_provider_load_finish (provider, result, &error))
- g_warning ("%s failed to initialize: %s",
- G_OBJECT_TYPE_NAME (provider), error->message);
+ {
+ g_print ("%s\n", G_OBJECT_TYPE_NAME (provider));
+ g_assert (error != NULL);
+ ide_context_warning (context,
+ "Failed to initialize config provider: %s: %s",
+ G_OBJECT_TYPE_NAME (provider), error->message);
+ }
providers = g_task_get_task_data (task);
g_assert (providers != NULL);
g_assert (providers->len > 0);
- g_ptr_array_remove (providers, provider);
-
- if (self->configurations->len == 0)
- ide_configuration_manager_add_default (self);
+ if (!g_ptr_array_remove (providers, provider))
+ g_critical ("Failed to locate provider in active set");
if (providers->len == 0)
g_task_return_boolean (task, TRUE);
@@ -520,8 +680,8 @@ ide_configuration_manager_init_async (GAsyncInitable *initable,
gpointer user_data)
{
IdeConfigurationManager *self = (IdeConfigurationManager *)initable;
- g_autoptr(GTask) task = NULL;
g_autoptr(GPtrArray) providers = NULL;
+ g_autoptr(GTask) task = NULL;
IdeContext *context;
g_assert (G_IS_ASYNC_INITABLE (self));
@@ -534,44 +694,43 @@ ide_configuration_manager_init_async (GAsyncInitable *initable,
context = ide_object_get_context (IDE_OBJECT (self));
g_assert (IDE_IS_CONTEXT (context));
- self->extensions = peas_extension_set_new (peas_engine_get_default (),
- IDE_TYPE_CONFIGURATION_PROVIDER,
- NULL);
+ self->providers = peas_extension_set_new (peas_engine_get_default (),
+ IDE_TYPE_CONFIGURATION_PROVIDER,
+ "context", context,
+ NULL);
- g_signal_connect (self->extensions,
+ g_signal_connect (self->providers,
"extension-added",
- G_CALLBACK (ide_configuration_manager_extension_added),
+ G_CALLBACK (ide_configuration_manager_provider_added),
self);
- g_signal_connect (self->extensions,
+ g_signal_connect (self->providers,
"extension-removed",
- G_CALLBACK (ide_configuration_manager_extension_removed),
+ G_CALLBACK (ide_configuration_manager_provider_removed),
self);
providers = g_ptr_array_new_with_free_func (g_object_unref);
- peas_extension_set_foreach (self->extensions,
+ peas_extension_set_foreach (self->providers,
ide_configuration_manager_collect_providers,
providers);
- g_task_set_task_data (task,
- g_ptr_array_ref (providers),
- (GDestroyNotify)g_ptr_array_unref);
+ g_task_set_task_data (task, g_ptr_array_ref (providers), (GDestroyNotify)g_ptr_array_unref);
for (guint i = 0; i < providers->len; i++)
{
IdeConfigurationProvider *provider = g_ptr_array_index (providers, i);
+ g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
+
+ provider_connect (self, provider);
+
ide_configuration_provider_load_async (provider,
- self,
cancellable,
ide_configuration_manager_init_load_cb,
g_object_ref (task));
}
if (providers->len == 0)
- {
- ide_configuration_manager_add_default (self);
- g_task_return_boolean (task, TRUE);
- }
+ g_task_return_boolean (task, TRUE);
}
static gboolean
@@ -579,6 +738,7 @@ ide_configuration_manager_init_finish (GAsyncInitable *initable,
GAsyncResult *result,
GError **error)
{
+ g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_CONFIGURATION_MANAGER (initable));
g_assert (G_IS_TASK (result));
@@ -596,6 +756,7 @@ void
ide_configuration_manager_set_current (IdeConfigurationManager *self,
IdeConfiguration *current)
{
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
g_return_if_fail (IDE_IS_CONFIGURATION_MANAGER (self));
g_return_if_fail (!current || IDE_IS_CONFIGURATION (current));
@@ -643,93 +804,78 @@ IdeConfiguration *
ide_configuration_manager_get_current (IdeConfigurationManager *self)
{
g_return_val_if_fail (IDE_IS_CONFIGURATION_MANAGER (self), NULL);
+ g_return_val_if_fail (self->current != NULL || self->configs->len > 0, NULL);
- if ((self->current == NULL) && (self->configurations->len > 0))
- return g_ptr_array_index (self->configurations, 0);
+ if (self->current != NULL)
+ return self->current;
- return self->current;
-}
+ if (self->configs->len > 0)
+ {
+ const ConfigInfo *info = &g_array_index (self->configs, ConfigInfo, 0);
-static void
-ide_configuration_manager_changed (IdeConfigurationManager *self,
- IdeConfiguration *configuration)
-{
- g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
- g_assert (IDE_IS_CONFIGURATION (configuration));
+ g_assert (IDE_IS_CONFIGURATION_PROVIDER (info->provider));
+ g_assert (IDE_IS_CONFIGURATION (info->config));
- g_signal_emit (self, signals [INVALIDATE], 0);
+ return info->config;
+ }
+
+ g_critical ("Failed to locate activate configuration. This should not happen.");
+
+ return NULL;
}
void
-ide_configuration_manager_add (IdeConfigurationManager *self,
- IdeConfiguration *configuration)
+ide_configuration_manager_duplicate (IdeConfigurationManager *self,
+ IdeConfiguration *config)
{
- const gchar *config_id;
- guint position;
-
g_return_if_fail (IDE_IS_CONFIGURATION_MANAGER (self));
- g_return_if_fail (IDE_IS_CONFIGURATION (configuration));
+ g_return_if_fail (IDE_IS_CONFIGURATION (config));
- for (guint i = 0; i < self->configurations->len; i++)
+ for (guint i = 0; i < self->configs->len; i++)
{
- IdeConfiguration *ele = g_ptr_array_index (self->configurations, i);
-
- /* Do nothing if we already have this. Unlikely to happen but might
- * be if we got into a weird race with registering default configurations
- * and receiving a default from a provider.
- */
- if (configuration == ele)
- return;
- }
+ const ConfigInfo *info = &g_array_index (self->configs, ConfigInfo, i);
- config_id = ide_configuration_get_id (configuration);
+ g_assert (IDE_IS_CONFIGURATION_PROVIDER (info->provider));
+ g_assert (IDE_IS_CONFIGURATION (info->config));
- /* Allow the default config to be overridden by one from a provider */
- if (dzl_str_equal0 ("default", config_id))
- {
- IdeConfiguration *def = ide_configuration_manager_get_configuration (self, "default");
-
- g_assert (def != configuration);
+ if (info->config == config)
+ {
+ g_autoptr(IdeConfigurationProvider) provider = g_object_ref (info->provider);
- if (def != NULL)
- g_ptr_array_remove_fast (self->configurations, def);
+ info = NULL; /* info becomes invalid */
+ ide_configuration_provider_duplicate (provider, config);
+ ide_configuration_provider_save_async (provider, NULL, NULL, NULL);
+ break;
+ }
}
-
- position = self->configurations->len;
- g_ptr_array_add (self->configurations, g_object_ref (configuration));
- g_list_model_items_changed (G_LIST_MODEL (self), position, 0, 1);
-
- g_signal_connect_object (configuration,
- "changed",
- G_CALLBACK (ide_configuration_manager_changed),
- self,
- G_CONNECT_SWAPPED);
}
void
-ide_configuration_manager_remove (IdeConfigurationManager *self,
- IdeConfiguration *configuration)
+ide_configuration_manager_delete (IdeConfigurationManager *self,
+ IdeConfiguration *config)
{
- guint i;
+ g_autoptr(IdeConfiguration) hold = NULL;
g_return_if_fail (IDE_IS_CONFIGURATION_MANAGER (self));
- g_return_if_fail (IDE_IS_CONFIGURATION (configuration));
+ g_return_if_fail (IDE_IS_CONFIGURATION (config));
+
+ hold = g_object_ref (config);
- for (i = 0; i < self->configurations->len; i++)
+ for (guint i = 0; i < self->configs->len; i++)
{
- IdeConfiguration *item = g_ptr_array_index (self->configurations, i);
+ const ConfigInfo *info = &g_array_index (self->configs, ConfigInfo, i);
+ g_autoptr(IdeConfigurationProvider) provider = NULL;
- if (item == configuration)
+ g_assert (IDE_IS_CONFIGURATION_PROVIDER (info->provider));
+ g_assert (IDE_IS_CONFIGURATION (info->config));
+
+ provider = g_object_ref (info->provider);
+
+ if (info->config == config)
{
- g_signal_handlers_disconnect_by_func (configuration,
- G_CALLBACK (ide_configuration_manager_changed),
- self);
- g_ptr_array_remove_index (self->configurations, i);
- g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
- if (self->configurations->len == 0)
- ide_configuration_manager_add_default (self);
- if (self->current == configuration)
- ide_configuration_manager_set_current (self, NULL);
+ info = NULL; /* info becomes invalid */
+ ide_configuration_provider_delete (provider, config);
+ ide_configuration_provider_save_async (provider, NULL, NULL, NULL);
break;
}
}
diff --git a/src/libide/config/ide-configuration-manager.h b/src/libide/config/ide-configuration-manager.h
index b7997d32b..f6d0ef43d 100644
--- a/src/libide/config/ide-configuration-manager.h
+++ b/src/libide/config/ide-configuration-manager.h
@@ -39,12 +39,12 @@ void ide_configuration_manager_set_current (IdeConfigurationM
IDE_AVAILABLE_IN_ALL
IdeConfiguration *ide_configuration_manager_get_configuration (IdeConfigurationManager *self,
const gchar *id);
-IDE_AVAILABLE_IN_ALL
-void ide_configuration_manager_add (IdeConfigurationManager *self,
- IdeConfiguration *configuration);
-IDE_AVAILABLE_IN_ALL
-void ide_configuration_manager_remove (IdeConfigurationManager *self,
- IdeConfiguration *configuration);
+IDE_AVAILABLE_IN_3_28
+void ide_configuration_manager_duplicate (IdeConfigurationManager *self,
+ IdeConfiguration *config);
+IDE_AVAILABLE_IN_3_28
+void ide_configuration_manager_delete (IdeConfigurationManager *self,
+ IdeConfiguration *config);
IDE_AVAILABLE_IN_ALL
void ide_configuration_manager_save_async (IdeConfigurationManager *self,
GCancellable *cancellable,
diff --git a/src/libide/config/ide-configuration-provider.c b/src/libide/config/ide-configuration-provider.c
index ed70947a1..8383f2f00 100644
--- a/src/libide/config/ide-configuration-provider.c
+++ b/src/libide/config/ide-configuration-provider.c
@@ -19,21 +19,28 @@
#define G_LOG_DOMAIN "ide-configuration-provider"
#include "application/ide-application.h"
+#include "config/ide-configuration.h"
#include "config/ide-configuration-manager.h"
#include "config/ide-configuration-provider.h"
G_DEFINE_INTERFACE (IdeConfigurationProvider, ide_configuration_provider, IDE_TYPE_OBJECT)
+enum {
+ ADDED,
+ REMOVED,
+ N_SIGNALS
+};
+
+static guint signals [N_SIGNALS];
+
static void
ide_configuration_provider_real_load_async (IdeConfigurationProvider *self,
- IdeConfigurationManager *manager,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
g_task_report_new_error (self, callback, user_data,
@@ -58,12 +65,21 @@ ide_configuration_provider_real_load_finish (IdeConfigurationProvider *self,
}
static void
-ide_configuration_provider_real_unload (IdeConfigurationProvider *self,
- IdeConfigurationManager *manager)
+ide_configuration_provider_real_duplicate (IdeConfigurationProvider *self,
+ IdeConfiguration *config)
+{
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (IDE_IS_CONFIGURATION_PROVIDER (self));
+ g_assert (IDE_IS_CONFIGURATION (config));
+
+}
+
+static void
+ide_configuration_provider_real_unload (IdeConfigurationProvider *self)
{
g_assert (IDE_IS_MAIN_THREAD ());
g_assert (IDE_IS_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
+
}
void
@@ -102,26 +118,96 @@ ide_configuration_provider_default_init (IdeConfigurationProviderInterface *ifac
{
iface->load_async = ide_configuration_provider_real_load_async;
iface->load_finish = ide_configuration_provider_real_load_finish;
+ iface->duplicate = ide_configuration_provider_real_duplicate;
iface->unload = ide_configuration_provider_real_unload;
iface->save_async = ide_configuration_provider_real_save_async;
iface->save_finish = ide_configuration_provider_real_save_finish;
+
+ /**
+ * IdeConfigurationProvider:added:
+ * @self: an #IdeConfigurationProvider
+ * @config: an #IdeConfiguration
+ *
+ * The "added" signal is emitted when a configuration
+ * has been added to a configuration provider.
+ *
+ * Since: 3.28
+ */
+ signals [ADDED] =
+ g_signal_new ("added",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (IdeConfigurationProviderInterface, added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, IDE_TYPE_CONFIGURATION);
+ g_signal_set_va_marshaller (signals [ADDED],
+ G_TYPE_FROM_INTERFACE (iface),
+ g_cclosure_marshal_VOID__OBJECTv);
+
+ /**
+ * IdeConfigurationProvider:removed:
+ * @self: an #IdeConfigurationProvider
+ * @config: an #IdeConfiguration
+ *
+ * The "removed" signal is emitted when a configuration
+ * has been removed from a configuration provider.
+ *
+ * Since: 3.28
+ */
+ signals [REMOVED] =
+ g_signal_new ("removed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (IdeConfigurationProviderInterface, removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, IDE_TYPE_CONFIGURATION);
+ g_signal_set_va_marshaller (signals [REMOVED],
+ G_TYPE_FROM_INTERFACE (iface),
+ g_cclosure_marshal_VOID__OBJECTv);
+
}
+/**
+ * ide_configuration_provider_load_async:
+ * @self: a #IdeConfigurationProvider
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: a callback to execute upon completion
+ * @user_data: closure data for @callback
+ *
+ * This function is called to initialize the configuration provider after
+ * the plugin instance has been created. The provider should locate any
+ * build configurations within the project and call
+ * ide_configuration_provider_emit_added() before completing the
+ * asynchronous function so that the configuration manager may be made
+ * aware of the configurations.
+ *
+ * Since: 3.28
+ */
void
ide_configuration_provider_load_async (IdeConfigurationProvider *self,
- IdeConfigurationManager *manager,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (IDE_IS_MAIN_THREAD ());
g_return_if_fail (IDE_IS_CONFIGURATION_PROVIDER (self));
- g_return_if_fail (IDE_IS_CONFIGURATION_MANAGER (manager));
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
- IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->load_async (self, manager, cancellable, callback, user_data);
+ IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->load_async (self, cancellable, callback, user_data);
}
+/**
+ * ide_configuration_provider_load_finish:
+ * @self: a #IdeConfigurationProvider
+ * @result: a #GAsyncResult
+ * @error: a location for a #GError, or %NULL
+ *
+ * Completes an asynchronous request to ide_configuration_provider_load_async().
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error is set.
+ */
gboolean
ide_configuration_provider_load_finish (IdeConfigurationProvider *self,
GAsyncResult *result,
@@ -134,17 +220,39 @@ ide_configuration_provider_load_finish (IdeConfigurationProvider *self,
return IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->load_finish (self, result, error);
}
+/**
+ * ide_configuration_provider_unload:
+ * @self: a #IdeConfigurationProvider
+ *
+ * Requests that the configuration provider unload any state. This is called
+ * shortly before the configuration provider is finalized.
+ *
+ * Implementations of #IdeConfigurationProvider should emit removed
+ * for every configuration they have registered so that the
+ * #IdeConfigurationManager has correct information.
+ */
void
-ide_configuration_provider_unload (IdeConfigurationProvider *self,
- IdeConfigurationManager *manager)
+ide_configuration_provider_unload (IdeConfigurationProvider *self)
{
g_return_if_fail (IDE_IS_MAIN_THREAD ());
g_return_if_fail (IDE_IS_CONFIGURATION_PROVIDER (self));
- g_return_if_fail (IDE_IS_CONFIGURATION_MANAGER (manager));
- IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->unload (self, manager);
+ IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->unload (self);
}
+/**
+ * ide_configuration_provider_save_async:
+ * @self: a #IdeConfigurationProvider
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: a callback to execute upon completion
+ * @user_data: closure data for @callback
+ *
+ * This function is called to request that the configuration provider
+ * persist any changed configurations back to disk.
+ *
+ * This function will be called before unloading the configuration provider
+ * so that it has a chance to persist any outstanding changes.
+ */
void
ide_configuration_provider_save_async (IdeConfigurationProvider *self,
GCancellable *cancellable,
@@ -158,6 +266,16 @@ ide_configuration_provider_save_async (IdeConfigurationProvider *self,
IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->save_async (self, cancellable, callback, user_data);
}
+/**
+ * ide_configuration_provider_save_finish:
+ * @self: a #IdeConfigurationProvider
+ * @result: a #GAsyncResult
+ * @error: a location for a #GError, or %NULL
+ *
+ * Completes an asynchronous request to ide_configuration_provider_save_async().
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error is set.
+ */
gboolean
ide_configuration_provider_save_finish (IdeConfigurationProvider *self,
GAsyncResult *result,
@@ -169,3 +287,100 @@ ide_configuration_provider_save_finish (IdeConfigurationProvider *self,
return IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->save_finish (self, result, error);
}
+
+/**
+ * ide_configuration_provider_emit_added:
+ * @self: an #IdeConfigurationProvider
+ * @config: an #IdeConfiguration
+ *
+ * #IdeConfigurationProvider implementations should call this function with
+ * a @config when it has discovered a new configuration.
+ *
+ * Since: 3.28
+ */
+void
+ide_configuration_provider_emit_added (IdeConfigurationProvider *self,
+ IdeConfiguration *config)
+{
+ g_return_if_fail (IDE_IS_CONFIGURATION_PROVIDER (self));
+ g_return_if_fail (IDE_IS_CONFIGURATION (config));
+
+ g_signal_emit (self, signals [ADDED], 0, config);
+}
+
+/**
+ * ide_configuration_provider_emit_removed:
+ * @self: an #IdeConfigurationProvider
+ * @config: an #IdeConfiguration
+ *
+ * #IdeConfigurationProvider implementations should call this function with
+ * a @config when it has discovered it was removed.
+ *
+ * Since: 3.28
+ */
+void
+ide_configuration_provider_emit_removed (IdeConfigurationProvider *self,
+ IdeConfiguration *config)
+{
+ g_return_if_fail (IDE_IS_CONFIGURATION_PROVIDER (self));
+ g_return_if_fail (IDE_IS_CONFIGURATION (config));
+
+ g_signal_emit (self, signals [REMOVED], 0, config);
+}
+
+/**
+ * ide_configuration_provider_delete:
+ * @self: a #IdeConfigurationProvider
+ * @config: an #IdeConfiguration owned by the provider
+ *
+ * Requests that the configuration provider delete the configuration.
+ *
+ * ide_configuration_provider_save_async() will be called by the
+ * #IdeConfigurationManager after calling this function.
+ *
+ * Since: 3.28
+ */
+void
+ide_configuration_provider_delete (IdeConfigurationProvider *self,
+ IdeConfiguration *config)
+{
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (IDE_IS_CONFIGURATION_PROVIDER (self));
+ g_return_if_fail (IDE_IS_CONFIGURATION (config));
+
+ if (IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->delete)
+ IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->delete (self, config);
+ else
+ g_warning ("Cannot delete configuration %s",
+ ide_configuration_get_id (config));
+}
+
+/**
+ * ide_configuration_provider_duplicate:
+ * @self: an #IdeConfigurationProvider
+ * @config: an #IdeConfiguration
+ *
+ * Requests that the configuration provider duplicate the configuration.
+ *
+ * This is useful when the user wants to experiment with alternate settings
+ * without breaking a previous configuration.
+ *
+ * The configuration provider does not need to persist the configuration
+ * in this function, ide_configuration_provider_save_async() will be called
+ * afterwards to persist configurations to disk.
+ *
+ * It is expected that the #IdeConfigurationProvider will emit
+ * #IdeConfigurationProvider::added with the new configuration.
+ *
+ * Since: 3.28
+ */
+void
+ide_configuration_provider_duplicate (IdeConfigurationProvider *self,
+ IdeConfiguration *config)
+{
+ g_return_if_fail (IDE_IS_MAIN_THREAD ());
+ g_return_if_fail (IDE_IS_CONFIGURATION_PROVIDER (self));
+ g_return_if_fail (IDE_IS_CONFIGURATION (config));
+
+ IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->duplicate (self, config);
+}
diff --git a/src/libide/config/ide-configuration-provider.h b/src/libide/config/ide-configuration-provider.h
index b1e7dea12..0b0509e74 100644
--- a/src/libide/config/ide-configuration-provider.h
+++ b/src/libide/config/ide-configuration-provider.h
@@ -1,6 +1,7 @@
/* ide-configuration-provider.h
*
* Copyright © 2016 Matthew Leeds <mleeds redhat com>
+ * Copyright © 2018 Christian Hergert <chergert redhat com>
*
* 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
@@ -20,9 +21,8 @@
#include <gio/gio.h>
-#include "ide-version-macros.h"
-
#include "ide-types.h"
+#include "ide-version-macros.h"
G_BEGIN_DECLS
@@ -32,48 +32,63 @@ G_DECLARE_INTERFACE (IdeConfigurationProvider, ide_configuration_provider, IDE,
struct _IdeConfigurationProviderInterface
{
- GTypeInterface parent;
+ GTypeInterface parent_iface;
- void (*load_async) (IdeConfigurationProvider *self,
- IdeConfigurationManager *manager,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
- gboolean (*load_finish) (IdeConfigurationProvider *self,
- GAsyncResult *result,
- GError **error);
- void (*unload) (IdeConfigurationProvider *self,
- IdeConfigurationManager *manager);
- void (*save_async) (IdeConfigurationProvider *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
- gboolean (*save_finish) (IdeConfigurationProvider *self,
- GAsyncResult *result,
- GError **error);
+ void (*added) (IdeConfigurationProvider *self,
+ IdeConfiguration *config);
+ void (*removed) (IdeConfigurationProvider *self,
+ IdeConfiguration *config);
+ void (*load_async) (IdeConfigurationProvider *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*load_finish) (IdeConfigurationProvider *self,
+ GAsyncResult *result,
+ GError **error);
+ void (*save_async) (IdeConfigurationProvider *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (*save_finish) (IdeConfigurationProvider *self,
+ GAsyncResult *result,
+ GError **error);
+ void (*delete) (IdeConfigurationProvider *self,
+ IdeConfiguration *config);
+ void (*duplicate) (IdeConfigurationProvider *self,
+ IdeConfiguration *config);
+ void (*unload) (IdeConfigurationProvider *self);
};
-IDE_AVAILABLE_IN_ALL
-void ide_configuration_provider_load_async (IdeConfigurationProvider *self,
- IdeConfigurationManager *manager,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-IDE_AVAILABLE_IN_ALL
-gboolean ide_configuration_provider_load_finish (IdeConfigurationProvider *self,
- GAsyncResult *result,
- GError **error);
-IDE_AVAILABLE_IN_ALL
-void ide_configuration_provider_unload (IdeConfigurationProvider *self,
- IdeConfigurationManager *manager);
-IDE_AVAILABLE_IN_ALL
-void ide_configuration_provider_save_async (IdeConfigurationProvider *self,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-IDE_AVAILABLE_IN_ALL
-gboolean ide_configuration_provider_save_finish (IdeConfigurationProvider *self,
- GAsyncResult *result,
- GError **error);
+IDE_AVAILABLE_IN_3_28
+void ide_configuration_provider_emit_added (IdeConfigurationProvider *self,
+ IdeConfiguration *config);
+IDE_AVAILABLE_IN_3_28
+void ide_configuration_provider_emit_removed (IdeConfigurationProvider *self,
+ IdeConfiguration *config);
+IDE_AVAILABLE_IN_3_28
+void ide_configuration_provider_load_async (IdeConfigurationProvider *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_3_28
+gboolean ide_configuration_provider_load_finish (IdeConfigurationProvider *self,
+ GAsyncResult *result,
+ GError **error);
+IDE_AVAILABLE_IN_3_28
+void ide_configuration_provider_save_async (IdeConfigurationProvider *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+IDE_AVAILABLE_IN_3_28
+gboolean ide_configuration_provider_save_finish (IdeConfigurationProvider *self,
+ GAsyncResult *result,
+ GError **error);
+IDE_AVAILABLE_IN_3_28
+void ide_configuration_provider_delete (IdeConfigurationProvider *self,
+ IdeConfiguration *config);
+void ide_configuration_provider_duplicate (IdeConfigurationProvider *self,
+ IdeConfiguration *config);
+IDE_AVAILABLE_IN_3_28
+void ide_configuration_provider_unload (IdeConfigurationProvider *self);
G_END_DECLS
diff --git a/src/libide/config/ide-configuration.c b/src/libide/config/ide-configuration.c
index ccb144475..950eba7df 100644
--- a/src/libide/config/ide-configuration.c
+++ b/src/libide/config/ide-configuration.c
@@ -56,7 +56,6 @@ typedef struct
guint dirty : 1;
guint debug : 1;
- guint is_snapshot : 1;
/*
* These are used to determine if we can make progress building
@@ -69,7 +68,7 @@ typedef struct
IdeBuildLocality locality : 3;
} IdeConfigurationPrivate;
-G_DEFINE_TYPE_WITH_PRIVATE (IdeConfiguration, ide_configuration, IDE_TYPE_OBJECT)
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (IdeConfiguration, ide_configuration, IDE_TYPE_OBJECT)
enum {
PROP_0,
@@ -126,20 +125,6 @@ _value_new (GType type)
return value;
}
-static GValue *
-_value_copy (const GValue *value)
-{
- GValue *dst;
-
- g_assert (value != NULL);
-
- dst = g_slice_new0 (GValue);
- g_value_init (dst, G_VALUE_TYPE (value));
- g_value_copy (value, dst);
-
- return dst;
-}
-
static void
ide_configuration_emit_changed (IdeConfiguration *self)
{
@@ -385,6 +370,10 @@ ide_configuration_get_property (GObject *object,
g_value_set_object (value, ide_configuration_get_device (self));
break;
+ case PROP_DEVICE_ID:
+ g_value_set_string (value, ide_configuration_get_device_id (self));
+ break;
+
case PROP_DIRTY:
g_value_set_boolean (value, ide_configuration_get_dirty (self));
break;
@@ -710,25 +699,6 @@ ide_configuration_init (IdeConfiguration *self)
G_CONNECT_SWAPPED);
}
-IdeConfiguration *
-ide_configuration_new (IdeContext *context,
- const gchar *id,
- const gchar *device_id,
- const gchar *runtime_id)
-{
- g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
- g_return_val_if_fail (id != NULL, NULL);
- g_return_val_if_fail (device_id != NULL, NULL);
- g_return_val_if_fail (runtime_id != NULL, NULL);
-
- return g_object_new (IDE_TYPE_CONFIGURATION,
- "context", context,
- "device-id", device_id,
- "id", id,
- "runtime-id", runtime_id,
- NULL);
-}
-
const gchar *
ide_configuration_get_device_id (IdeConfiguration *self)
{
@@ -748,6 +718,9 @@ ide_configuration_set_device_id (IdeConfiguration *self,
g_return_if_fail (IDE_IS_CONFIGURATION (self));
g_return_if_fail (device_id != NULL);
+ if (device_id == NULL)
+ device_id = "local";
+
if (g_strcmp0 (device_id, priv->device_id) != 0)
{
IdeContext *context;
@@ -819,11 +792,13 @@ ide_configuration_set_app_id (IdeConfiguration *self,
IdeConfigurationPrivate *priv = ide_configuration_get_instance_private (self);
g_return_if_fail (IDE_IS_CONFIGURATION (self));
- g_return_if_fail (app_id != NULL);
-
- g_free (priv->app_id);
- priv->app_id = g_strdup (app_id);
+ if (priv->app_id != app_id)
+ {
+ g_free (priv->app_id);
+ priv->app_id = g_strdup (app_id);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_APP_ID]);
+ }
}
const gchar *
@@ -843,7 +818,9 @@ ide_configuration_set_runtime_id (IdeConfiguration *self,
IdeConfigurationPrivate *priv = ide_configuration_get_instance_private (self);
g_return_if_fail (IDE_IS_CONFIGURATION (self));
- g_return_if_fail (runtime_id != NULL);
+
+ if (runtime_id == NULL)
+ runtime_id = "host";
if (g_strcmp0 (runtime_id, priv->runtime_id) != 0)
{
@@ -1074,37 +1051,6 @@ ide_configuration_get_dirty (IdeConfiguration *self)
return priv->dirty;
}
-static gboolean
-propagate_dirty_bit (gpointer user_data)
-{
- g_autofree gpointer *data = user_data;
- g_autoptr(IdeContext) context = NULL;
- g_autofree gchar *id = NULL;
- IdeConfigurationManager *config_manager;
- IdeConfiguration *config;
- IdeConfigurationPrivate *config_priv;
- guint sequence;
-
- g_assert (data != NULL);
- g_assert (IDE_IS_CONTEXT (data[0]));
-
- context = data[0];
- id = data[1];
- sequence = GPOINTER_TO_UINT (data[2]);
-
- config_manager = ide_context_get_configuration_manager (context);
- config = ide_configuration_manager_get_configuration (config_manager, id);
- config_priv = ide_configuration_get_instance_private (config);
-
- if (config != NULL)
- {
- if (sequence == config_priv->sequence)
- ide_configuration_set_dirty (config, FALSE);
- }
-
- return G_SOURCE_REMOVE;
-}
-
void
ide_configuration_set_dirty (IdeConfiguration *self,
gboolean dirty)
@@ -1134,21 +1080,6 @@ ide_configuration_set_dirty (IdeConfiguration *self,
IDE_TRACE_MSG ("configuration set dirty with sequence %u", priv->sequence);
ide_configuration_emit_changed (self);
}
- else if (priv->is_snapshot)
- {
- gpointer *data;
-
- /*
- * If we are marking this not-dirty, and it is a snapshot (which means it
- * was copied for a build process), then we want to propagate the dirty
- * bit back to the primary configuration.
- */
- data = g_new0 (gpointer, 3);
- data[0] = g_object_ref (ide_object_get_context (IDE_OBJECT (self)));
- data[1] = g_strdup (priv->id);
- data[2] = GUINT_TO_POINTER (priv->sequence);
- g_timeout_add (0, propagate_dirty_bit, data);
- }
IDE_EXIT;
}
@@ -1264,83 +1195,6 @@ ide_configuration_set_post_install_commands (IdeConfiguration *self,
}
}
-/**
- * ide_configuration_snapshot:
- *
- * Makes a snapshot of the configuration that can be used by build processes
- * to build the project without synchronizing with other threads.
- *
- * Returns: (transfer full): A newly allocated #IdeConfiguration.
- */
-IdeConfiguration *
-ide_configuration_snapshot (IdeConfiguration *self)
-{
- IdeConfigurationPrivate *priv = ide_configuration_get_instance_private (self);
- IdeConfigurationPrivate *copy_priv;
- IdeConfiguration *copy;
- IdeContext *context;
- const gchar *key;
- const GValue *value;
- GHashTableIter iter;
-
- g_return_val_if_fail (IDE_IS_CONFIGURATION (self), NULL);
-
- context = ide_object_get_context (IDE_OBJECT (self));
-
- copy = g_object_new (IDE_TYPE_CONFIGURATION,
- "config-opts", priv->config_opts,
- "context", context,
- "device-id", priv->device_id,
- "display-name", priv->display_name,
- "id", priv->id,
- "parallelism", priv->parallelism,
- "prefix", priv->prefix,
- "runtime-id", priv->runtime_id,
- NULL);
-
- copy_priv = ide_configuration_get_instance_private (copy);
- copy_priv->environment = ide_environment_copy (priv->environment);
-
- g_hash_table_iter_init (&iter, priv->internal);
- while (g_hash_table_iter_next (&iter, (gpointer *)&key, (gpointer *)&value))
- g_hash_table_insert (copy_priv->internal, g_strdup (key), _value_copy (value));
-
- copy_priv->dirty = priv->dirty;
- copy_priv->is_snapshot = TRUE;
- copy_priv->sequence = priv->sequence;
-
- return copy;
-}
-
-/**
- * ide_configuration_duplicate:
- * @self: An #IdeConfiguration
- *
- * Copies the configuration into a new configuration.
- *
- * Returns: (transfer full): An #IdeConfiguration.
- */
-IdeConfiguration *
-ide_configuration_duplicate (IdeConfiguration *self)
-{
- IdeConfigurationPrivate *priv = ide_configuration_get_instance_private (self);
- IdeConfigurationPrivate *copy_priv;
- static gint next_counter = 2;
- IdeConfiguration *copy;
-
- copy = ide_configuration_snapshot (self);
- copy_priv = ide_configuration_get_instance_private (copy);
-
- g_free (copy_priv->id);
- g_free (copy_priv->display_name);
-
- copy_priv->id = g_strdup_printf ("%s %d", priv->id, next_counter++);
- copy_priv->display_name = g_strdup_printf ("%s Copy", priv->display_name);
- copy_priv->is_snapshot = FALSE;
-
- return copy;
-}
-
/**
* ide_configuration_get_sequence:
* @self: An #IdeConfiguration
diff --git a/src/libide/config/ide-configuration.h b/src/libide/config/ide-configuration.h
index 70844ea3b..62e2fa65f 100644
--- a/src/libide/config/ide-configuration.h
+++ b/src/libide/config/ide-configuration.h
@@ -74,11 +74,6 @@ struct _IdeConfigurationClass
gpointer _reserved16;
};
-IDE_AVAILABLE_IN_ALL
-IdeConfiguration *ide_configuration_new (IdeContext *context,
- const gchar *id,
- const gchar *device_id,
- const gchar *runtime_id);
IDE_AVAILABLE_IN_3_28
const gchar *ide_configuration_get_append_path (IdeConfiguration *self);
IDE_AVAILABLE_IN_3_28
@@ -173,8 +168,6 @@ IDE_AVAILABLE_IN_ALL
void ide_configuration_set_environment (IdeConfiguration *self,
IdeEnvironment *environment);
IDE_AVAILABLE_IN_ALL
-IdeConfiguration *ide_configuration_duplicate (IdeConfiguration *self);
-IDE_AVAILABLE_IN_ALL
IdeConfiguration *ide_configuration_snapshot (IdeConfiguration *self);
IDE_AVAILABLE_IN_ALL
guint ide_configuration_get_sequence (IdeConfiguration *self);
diff --git a/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
b/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
index 06174abfb..b23ea5493 100644
--- a/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
+++ b/src/plugins/flatpak/gbp-flatpak-configuration-provider.c
@@ -25,19 +25,14 @@
#include "gbp-flatpak-configuration.h"
#include "gbp-flatpak-configuration-provider.h"
-#define WRITEBACK_TIMEOUT_SECS 2
#define DISCOVERY_MAX_DEPTH 3
struct _GbpFlatpakConfigurationProvider
{
- IdeObject parent_instance;
-
- IdeConfigurationManager *manager;
- GPtrArray *configurations;
- GPtrArray *manifest_monitors;
-
- guint writeback_handler;
- guint change_count;
+ IdeObject parent_instance;
+ GMutex mutex;
+ GPtrArray *configs;
+ GPtrArray *manifest_monitors;
};
static void configuration_provider_iface_init (IdeConfigurationProviderInterface *iface);
@@ -64,13 +59,11 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- self->change_count = 0;
-
- if (self->configurations == NULL)
- IDE_EXIT;
+ g_mutex_lock (&self->mutex);
- for (guint i = 0; i < self->configurations->len; i++)
+ for (guint i = 0; i < self->configs->len; i++)
{
+ GbpFlatpakConfiguration *configuration = g_ptr_array_index (self->configs, i);
g_autoptr(GFileInputStream) file_stream = NULL;
g_autoptr(GDataInputStream) data_stream = NULL;
g_autoptr(GRegex) runtime_regex = NULL;
@@ -108,24 +101,19 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
guint opts_per_line = 0;
guint nested_curly_braces;
- GbpFlatpakConfiguration *configuration = (GbpFlatpakConfiguration *)g_ptr_array_index
(self->configurations, i);
-
- manifest = gbp_flatpak_configuration_get_manifest (configuration);
- if (manifest == NULL)
+ if (!(manifest = gbp_flatpak_configuration_get_manifest (configuration)))
continue;
- primary_module = gbp_flatpak_configuration_get_primary_module (configuration);
- if (primary_module == NULL)
+ if (!(primary_module = gbp_flatpak_configuration_get_primary_module (configuration)))
{
g_warning ("Flatpak manifest configuration has no primary module set");
continue;
}
- file_stream = g_file_read (manifest, NULL, &error);
- if (file_stream == NULL)
+ if (!(file_stream = g_file_read (manifest, NULL, &error)))
{
g_task_return_error (task, g_steal_pointer (&error));
- IDE_EXIT;
+ IDE_GOTO (unlock);
}
data_stream = g_data_input_stream_new (G_INPUT_STREAM (file_stream));
@@ -138,6 +126,7 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
primary_module_regex = g_regex_new (primary_module_regex_str, 0, 0, NULL);
new_runtime_id = ide_configuration_get_runtime_id (IDE_CONFIGURATION (configuration));
+
if (g_str_has_prefix (new_runtime_id, "flatpak:"))
{
new_runtime_parts = g_strsplit (new_runtime_id + 8, "/", 3);
@@ -173,13 +162,14 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
nested_curly_braces = 0;
for (;;)
{
- gchar *line;
+ g_autofree gchar *line = NULL;
line = g_data_input_stream_read_line_utf8 (data_stream, NULL, NULL, &error);
+
if (error != NULL)
{
g_task_return_error (task, g_steal_pointer (&error));
- IDE_EXIT;
+ IDE_GOTO (unlock);
}
if (line == NULL)
@@ -276,7 +266,6 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
}
/* Discard the line because it will be replaced with new info */
- g_free (line);
continue;
}
else
@@ -284,7 +273,6 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
if (nested_curly_braces > 0)
{
nested_curly_braces--;
- g_free (line);
continue;
}
else
@@ -439,7 +427,6 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
opts_per_line = (opts_per_line > 0) ? opts_per_line : 1;
}
- g_free (line);
continue;
}
}
@@ -447,7 +434,6 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
{
in_config_opts_array = TRUE;
config_opt_indent = g_strsplit (line, "\"", 0)[0];
- g_free (line);
continue;
}
@@ -456,7 +442,7 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
if (error != NULL)
{
g_task_return_error (task, g_steal_pointer (&error));
- IDE_EXIT;
+ IDE_GOTO (unlock);
}
if (g_str_has_prefix (next_line, primary_module_right_curly_brace))
right_curly_brace_line = next_line;
@@ -511,7 +497,6 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
}
/* Discard the line that was just replaced with the new config-opts array */
- g_free (line);
/* If we're on the last line of the module, add the curly brace now */
if (right_curly_brace_line != NULL)
@@ -555,10 +540,15 @@ gbp_flatpak_configuration_provider_save_worker (GTask *task,
&error))
{
g_task_return_error (task, g_steal_pointer (&error));
- IDE_EXIT;
+ IDE_GOTO (unlock);
}
}
+ g_task_return_boolean (task, TRUE);
+
+unlock:
+ g_mutex_unlock (&self->mutex);
+
IDE_EXIT;
}
@@ -577,11 +567,9 @@ gbp_flatpak_configuration_provider_save_async (IdeConfigurationProvider *provide
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);
- else
- g_task_run_in_thread (task, gbp_flatpak_configuration_provider_save_worker);
+ g_task_set_source_tag (task, gbp_flatpak_configuration_provider_save_async);
+ g_task_set_priority (task, G_PRIORITY_LOW);
+ g_task_run_in_thread (task, gbp_flatpak_configuration_provider_save_worker);
IDE_EXIT;
}
@@ -599,49 +587,6 @@ gbp_flatpak_configuration_provider_save_finish (IdeConfigurationProvider *provi
return g_task_propagate_boolean (G_TASK (result), error);
}
-static gboolean
-gbp_flatpak_configuration_provider_do_writeback (gpointer data)
-{
- GbpFlatpakConfigurationProvider *self = data;
-
- g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
-
- self->writeback_handler = 0;
-
- gbp_flatpak_configuration_provider_save_async (IDE_CONFIGURATION_PROVIDER (self), NULL, NULL, NULL);
-
- return G_SOURCE_REMOVE;
-}
-
-static void
-gbp_flatpak_configuration_provider_queue_writeback (GbpFlatpakConfigurationProvider *self)
-{
- g_assert (GBP_IS_FLATPAK_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,
- gbp_flatpak_configuration_provider_do_writeback,
- self);
-
- IDE_EXIT;
-}
-
-static void
-gbp_flatpak_configuration_provider_config_changed (GbpFlatpakConfigurationProvider *self,
- IdeConfiguration *configuration)
-{
- g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_CONFIGURATION (configuration));
-
- self->change_count++;
-
- gbp_flatpak_configuration_provider_queue_writeback (self);
-}
-
static gboolean
contains_id (GPtrArray *ar,
const gchar *id)
@@ -694,12 +639,12 @@ gbp_flatpak_configuration_provider_manifest_changed (GbpFlatpakConfigurationProv
GFileMonitorEvent event,
GFileMonitor *file_monitor)
{
- GbpFlatpakConfiguration *relevant_config = NULL;
+ g_autoptr(GbpFlatpakConfiguration) relevant_config = NULL;
IdeContext *context;
- GFile *new_config_file;
g_autofree gchar *filename = NULL;
g_autofree gchar *path = NULL;
g_autofree gchar *id = NULL;
+ GFile *new_config_file;
IDE_ENTRY;
@@ -707,19 +652,21 @@ gbp_flatpak_configuration_provider_manifest_changed (GbpFlatpakConfigurationProv
g_assert (G_IS_FILE (file));
g_assert (G_IS_FILE_MONITOR (file_monitor));
- context = ide_object_get_context (IDE_OBJECT (self->manager));
+ context = ide_object_get_context (IDE_OBJECT (self));
- if (self->configurations != NULL)
+ g_mutex_lock (&self->mutex);
+
+ if (self->configs != NULL)
{
- for (guint i = 0; i < self->configurations->len; i++)
+ for (guint i = 0; i < self->configs->len; i++)
{
- GbpFlatpakConfiguration *configuration = g_ptr_array_index (self->configurations, i);
+ GbpFlatpakConfiguration *configuration = g_ptr_array_index (self->configs, i);
GFile *config_manifest;
config_manifest = gbp_flatpak_configuration_get_manifest (configuration);
if (g_file_equal (file, config_manifest) ||
(event == G_FILE_MONITOR_EVENT_RENAMED && g_file_equal (other_file, config_manifest)))
{
- relevant_config = configuration;
+ relevant_config = g_object_ref (configuration);
break;
}
}
@@ -728,22 +675,23 @@ gbp_flatpak_configuration_provider_manifest_changed (GbpFlatpakConfigurationProv
if (relevant_config == NULL &&
event != G_FILE_MONITOR_EVENT_CREATED &&
event != G_FILE_MONITOR_EVENT_MOVED_IN)
- IDE_EXIT;
+ IDE_GOTO (unlock);
new_config_file = file;
switch (event)
{
case G_FILE_MONITOR_EVENT_DELETED:
case G_FILE_MONITOR_EVENT_MOVED_OUT:
- ide_configuration_manager_remove (self->manager, IDE_CONFIGURATION (relevant_config));
- g_ptr_array_remove_fast (self->configurations, relevant_config);
+ ide_configuration_provider_emit_removed (IDE_CONFIGURATION_PROVIDER (self),
+ IDE_CONFIGURATION (relevant_config));
+ g_ptr_array_remove_fast (self->configs, relevant_config);
break;
case G_FILE_MONITOR_EVENT_RENAMED:
filename = g_file_get_basename (other_file);
/* The "rename" is just a temporary file created by an editor */
if (g_str_has_suffix (filename, "~"))
- IDE_EXIT;
+ IDE_GOTO (unlock);
else
g_clear_pointer (&filename, g_free);
new_config_file = other_file;
@@ -757,7 +705,7 @@ gbp_flatpak_configuration_provider_manifest_changed (GbpFlatpakConfigurationProv
filename = g_file_get_basename (new_config_file);
id = get_manifest_id (path, filename);
- if (!contains_id (self->configurations, id))
+ if (!contains_id (self->configs, id))
{
g_autoptr(GbpFlatpakConfiguration) new_config = NULL;
@@ -767,12 +715,6 @@ gbp_flatpak_configuration_provider_manifest_changed (GbpFlatpakConfigurationProv
g_autoptr(GFileMonitor) manifest_monitor = NULL;
g_autoptr(GError) local_error = NULL;
- g_signal_connect_object (new_config,
- "changed",
- G_CALLBACK (gbp_flatpak_configuration_provider_config_changed),
- self,
- G_CONNECT_SWAPPED);
-
manifest_monitor = g_file_monitor_file (new_config_file, G_FILE_MONITOR_WATCH_MOVES, NULL,
&local_error);
if (manifest_monitor == NULL)
g_warning ("Error encountered trying to monitor flatpak manifest %s: %s", path,
local_error->message);
@@ -788,13 +730,14 @@ gbp_flatpak_configuration_provider_manifest_changed (GbpFlatpakConfigurationProv
if (relevant_config != NULL)
{
- ide_configuration_manager_remove (self->manager, IDE_CONFIGURATION (relevant_config));
- g_ptr_array_remove_fast (self->configurations, relevant_config);
+ ide_configuration_provider_emit_removed (IDE_CONFIGURATION_PROVIDER (self),
+ IDE_CONFIGURATION (relevant_config));
+ g_ptr_array_remove_fast (self->configs, relevant_config);
}
g_ptr_array_remove_fast (self->manifest_monitors, file_monitor);
- ide_configuration_manager_add (self->manager, IDE_CONFIGURATION (new_config));
- ide_configuration_manager_set_current (self->manager, IDE_CONFIGURATION (new_config));
- g_ptr_array_add (self->configurations, g_steal_pointer (&new_config));
+ g_ptr_array_add (self->configs, g_object_ref (new_config));
+ ide_configuration_provider_emit_added (IDE_CONFIGURATION_PROVIDER (self),
+ IDE_CONFIGURATION (new_config));
}
}
break;
@@ -808,6 +751,9 @@ gbp_flatpak_configuration_provider_manifest_changed (GbpFlatpakConfigurationProv
break;
}
+unlock:
+ g_mutex_unlock (&self->mutex);
+
IDE_EXIT;
}
@@ -821,8 +767,8 @@ gbp_flatpak_configuration_provider_find_manifests (GbpFlatpakConfigurationProvid
{
g_autoptr(GFileEnumerator) enumerator = NULL;
g_autoptr(GPtrArray) child_dirs = NULL;
- GFileInfo *file_info = NULL;
IdeContext *context;
+ gpointer infoptr;
g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
g_assert (G_IS_FILE (directory));
@@ -830,19 +776,21 @@ gbp_flatpak_configuration_provider_find_manifests (GbpFlatpakConfigurationProvid
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
g_assert (depth < DISCOVERY_MAX_DEPTH);
- context = ide_object_get_context (IDE_OBJECT (self->manager));
+ context = ide_object_get_context (IDE_OBJECT (self));
+ g_assert (IDE_IS_CONTEXT (context));
enumerator = g_file_enumerate_children (directory,
G_FILE_ATTRIBUTE_STANDARD_NAME,
G_FILE_QUERY_INFO_NONE,
cancellable,
error);
- if (!enumerator)
+
+ if (enumerator == NULL)
return;
- while ((file_info = g_file_enumerator_next_file (enumerator, cancellable, NULL)))
+ while ((infoptr = g_file_enumerator_next_file (enumerator, cancellable, NULL)))
{
- GFileType file_type;
+ g_autoptr(GFileInfo) file_info = infoptr;
g_autofree gchar *filename = NULL;
g_autofree gchar *path = NULL;
g_autofree gchar *id = NULL;
@@ -851,6 +799,7 @@ gbp_flatpak_configuration_provider_find_manifests (GbpFlatpakConfigurationProvid
g_autoptr(GbpFlatpakConfiguration) possible_config = NULL;
g_autoptr(GFileMonitor) manifest_monitor = NULL;
g_autoptr(GError) local_error = NULL;
+ GFileType file_type;
file_type = g_file_info_get_file_type (file_info);
filename = g_strdup (g_file_info_get_name (file_info));
@@ -892,12 +841,6 @@ gbp_flatpak_configuration_provider_find_manifests (GbpFlatpakConfigurationProvid
if (!gbp_flatpak_configuration_load_from_file (possible_config, file))
continue;
- g_signal_connect_object (possible_config,
- "changed",
- G_CALLBACK (gbp_flatpak_configuration_provider_config_changed),
- self,
- G_CONNECT_SWAPPED);
-
manifest_monitor = g_file_monitor_file (file, G_FILE_MONITOR_WATCH_MOVES, NULL, &local_error);
if (manifest_monitor == NULL)
g_warning ("Error encountered trying to monitor flatpak manifest %s: %s", path,
local_error->message);
@@ -926,27 +869,28 @@ gbp_flatpak_configuration_provider_find_manifests (GbpFlatpakConfigurationProvid
gbp_flatpak_configuration_provider_find_manifests (self, file, configs, depth + 1, cancellable,
error);
}
}
-
- return;
}
static void
gbp_flatpak_configuration_provider_load_manifests (GbpFlatpakConfigurationProvider *self,
- GPtrArray *configurations,
+ GPtrArray *configs,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GPtrArray) ar = NULL;
g_autoptr(GFileInfo) file_info = NULL;
+ g_autoptr(GFile) project_dir = NULL;
IdeContext *context;
GFile *project_file;
- g_autoptr(GFile) project_dir = NULL;
g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+ g_assert (configs != NULL);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- context = ide_object_get_context (IDE_OBJECT (self->manager));
- project_file = ide_context_get_project_file (context);
+ context = ide_object_get_context (IDE_OBJECT (self));
+ g_assert (IDE_IS_CONTEXT (context));
+ project_file = ide_context_get_project_file (context);
g_assert (G_IS_FILE (project_file));
file_info = g_file_query_info (project_file,
@@ -954,7 +898,6 @@ gbp_flatpak_configuration_provider_load_manifests (GbpFlatpakConfigurationProvid
G_FILE_QUERY_INFO_NONE,
cancellable,
error);
-
if (file_info == NULL)
return;
@@ -963,18 +906,11 @@ gbp_flatpak_configuration_provider_load_manifests (GbpFlatpakConfigurationProvid
else
project_dir = g_file_get_parent (project_file);
- gbp_flatpak_configuration_provider_find_manifests (self,
- project_dir,
- configurations,
- 0,
- cancellable,
- error);
- if (error != NULL)
- return;
+ g_mutex_lock (&self->mutex);
+ gbp_flatpak_configuration_provider_find_manifests (self, project_dir, configs, 0, cancellable, error);
+ g_mutex_unlock (&self->mutex);
- IDE_TRACE_MSG ("Found %u flatpak manifests", configurations->len);
-
- return;
+ g_debug ("Found %u flatpak manifests", configs->len);
}
static void
@@ -984,147 +920,145 @@ gbp_flatpak_configuration_provider_load_worker (GTask *task,
GCancellable *cancellable)
{
GbpFlatpakConfigurationProvider *self = source_object;
- g_autoptr(GPtrArray) ret = NULL;
- g_autoptr(GFile) file = NULL;
- g_autofree gchar *path = NULL;
- GError *error = NULL;
+ g_autoptr(GError) error = NULL;
+ GPtrArray *configs = task_data;
IDE_ENTRY;
g_assert (G_IS_TASK (task));
g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_CONFIGURATION_MANAGER (self->manager));
+ g_assert (configs != NULL);
+ g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- ret = g_ptr_array_new_with_free_func (g_object_unref);
+ gbp_flatpak_configuration_provider_load_manifests (self, configs, cancellable, &error);
- /* Load flatpak manifests in the repo */
- gbp_flatpak_configuration_provider_load_manifests (self, ret, cancellable, &error);
if (error != NULL)
- {
- g_warning ("%s", error->message);
- g_clear_error (&error);
- }
-
- g_task_return_pointer (task, g_steal_pointer (&ret), (GDestroyNotify)g_ptr_array_unref);
-
- IDE_EXIT;
-}
-
-static void
-gbp_flatpak_configuration_provider_load_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)object;
- g_autoptr(GError) error = NULL;
- GPtrArray *ret;
- guint i;
- g_autoptr(GTask) task = user_data;
-
- IDE_ENTRY;
-
- g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
- g_assert (G_IS_TASK (result));
- g_assert (G_IS_TASK (task));
-
- if (!(ret = g_task_propagate_pointer (G_TASK (result), &error)))
- {
- g_warning ("%s", error->message);
- g_task_return_error (task, g_steal_pointer (&error));
- IDE_EXIT;
- }
-
- for (i = 0; i < ret->len; i++)
- {
- IdeConfiguration *configuration = g_ptr_array_index (ret, i);
-
- ide_configuration_manager_add (self->manager, configuration);
- ide_configuration_manager_set_current (self->manager, configuration);
- }
-
- self->configurations = ret;
-
- g_task_return_boolean (task, TRUE);
+ g_task_return_error (task, g_steal_pointer (&error));
+ else
+ g_task_return_boolean (task, TRUE);
IDE_EXIT;
}
static void
gbp_flatpak_configuration_provider_load_async (IdeConfigurationProvider *provider,
- IdeConfigurationManager *manager,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)provider;
- g_autoptr(GTask) parent_task = NULL;
g_autoptr(GTask) task = NULL;
IDE_ENTRY;
- g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (provider));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
- dzl_set_weak_pointer (&self->manager, manager);
-
- self->manifest_monitors = g_ptr_array_new_with_free_func (g_object_unref);
-
- parent_task = g_task_new (self, cancellable, callback, user_data);
- task = g_task_new (self, cancellable, gbp_flatpak_configuration_provider_load_cb, g_steal_pointer
(&parent_task));
+ task = g_task_new (provider, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gbp_flatpak_configuration_provider_load_async);
+ g_task_set_priority (task, G_PRIORITY_LOW);
+ g_task_set_task_data (task,
+ g_ptr_array_new_with_free_func (g_object_unref),
+ (GDestroyNotify)g_ptr_array_unref);
g_task_run_in_thread (task, gbp_flatpak_configuration_provider_load_worker);
IDE_EXIT;
}
-gboolean
+static gboolean
gbp_flatpak_configuration_provider_load_finish (IdeConfigurationProvider *provider,
GAsyncResult *result,
GError **error)
{
GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)provider;
- g_return_val_if_fail (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self), FALSE);
- g_return_val_if_fail (G_IS_TASK (result), FALSE);
+ g_assert (IDE_IS_MAIN_THREAD ());
+ g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
+ g_assert (G_IS_TASK (result));
+ g_assert (g_task_is_valid (G_TASK (result), provider));
- return g_task_propagate_boolean (G_TASK (result), error);
+ if (g_task_propagate_boolean (G_TASK (result), error))
+ {
+ GPtrArray *configs = g_task_get_task_data (G_TASK (result));
+
+ g_assert (configs != NULL);
+
+ for (guint i = 0; i < configs->len; i++)
+ {
+ IdeConfiguration *config = g_ptr_array_index (configs, i);
+ g_assert (IDE_IS_CONFIGURATION (config));
+ ide_configuration_provider_emit_added (provider, config);
+ }
+
+ if (configs->len > 0)
+ {
+ IdeConfiguration *config = g_ptr_array_index (configs, 0);
+ IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
+ IdeConfigurationManager *manager = ide_context_get_configuration_manager (context);
+
+ g_assert (IDE_IS_CONFIGURATION (config));
+
+ /* TODO: We should have a GSetting for this, in config-manager */
+ ide_configuration_manager_set_current (manager, config);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
}
static void
-gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider,
- IdeConfigurationManager *manager)
+gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider)
{
GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)provider;
IDE_ENTRY;
g_assert (GBP_IS_FLATPAK_CONFIGURATION_PROVIDER (self));
- g_assert (IDE_IS_CONFIGURATION_MANAGER (manager));
- dzl_clear_source (&self->writeback_handler);
+ g_mutex_lock (&self->mutex);
- if (self->configurations != NULL)
+ if (self->configs != NULL)
{
- for (guint i = 0; i < self->configurations->len; i++)
+ for (guint i = self->configs->len; i > 0; i--)
{
- IdeConfiguration *configuration = g_ptr_array_index (self->configurations, i);
+ g_autoptr(IdeConfiguration) config = NULL;
+
+ config = g_object_ref (g_ptr_array_index (self->configs, i - 1));
+ g_ptr_array_remove_index (self->configs, i);
- ide_configuration_manager_remove (manager, configuration);
+ g_mutex_unlock (&self->mutex);
+ ide_configuration_provider_emit_removed (provider, config);
+ g_mutex_lock (&self->mutex);
}
}
- g_clear_pointer (&self->configurations, g_ptr_array_unref);
-
+ g_clear_pointer (&self->configs, g_ptr_array_unref);
g_clear_pointer (&self->manifest_monitors, g_ptr_array_unref);
- dzl_clear_weak_pointer (&self->manager);
+ g_mutex_unlock (&self->mutex);
IDE_EXIT;
}
+static void
+gbp_flatpak_configuration_provider_finalize (GObject *object)
+{
+ GbpFlatpakConfigurationProvider *self = (GbpFlatpakConfigurationProvider *)object;
+
+ g_mutex_clear (&self->mutex);
+
+ G_OBJECT_CLASS (gbp_flatpak_configuration_provider_parent_class)->finalize (object);
+}
+
static void
gbp_flatpak_configuration_provider_class_init (GbpFlatpakConfigurationProviderClass *klass)
{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gbp_flatpak_configuration_provider_finalize;
+
/* This regex is based on https://wiki.gnome.org/HowDoI/ChooseApplicationID */
filename_regex = g_regex_new ("^[[:alnum:]-_]+\\.[[:alnum:]-_]+(\\.[[:alnum:]-_]+)*\\.json$",
G_REGEX_OPTIMIZE, 0, NULL);
@@ -1133,6 +1067,10 @@ gbp_flatpak_configuration_provider_class_init (GbpFlatpakConfigurationProviderCl
static void
gbp_flatpak_configuration_provider_init (GbpFlatpakConfigurationProvider *self)
{
+ g_mutex_init (&self->mutex);
+
+ self->manifest_monitors = g_ptr_array_new_with_free_func (g_object_unref);
+ self->configs = g_ptr_array_new_with_free_func (g_object_unref);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]