Commit 39997b29 authored by Phaedrus Leeds's avatar Phaedrus Leeds
Browse files

configuration: Make the default config persist

When the build configuration management changed to using
IdeConfigurationProviders rather than doing everything in
IdeConfigurationManager, the default configuration stopped persisting to
the disk (so changes made are only effective during a session). This is
because the configuration was being added by the manager as an
IdeConfiguration rather than an IdeBuildconfigConfiguration, and
IdeBuildconfigConfigurationProvider knows how to read and write
".buildconfig" files.

The most obvious solution, creating the default configuration in the
IdeBuildconfigConfigurationProvider's load function, doesn't work because the
loads are asynchronous and there has to be at least one configuration
when the IdeConfigurationManager finishes initializing (otherwise the
IdeBuildPipeline will fail to initialize).

Instead, the load interface for IdeConfigurationProviders was changed to
an async/finish pair, so the IdeConfigurationManager knows when the
loads finish. At that point, it can check if a configuration was
restored from a .buildconfig file (in which case nothing needs to be
done) or if the default configuration was added by the
IdeConfigurationManager (in which case the buildconfig provider needs to
be informed of it so it can be persisted when changes are made).

https://bugzilla.gnome.org/show_bug.cgi?id=779240
parent f713fe80
......@@ -41,7 +41,6 @@ struct _IdeBuildconfigConfigurationProvider
GObject parent_instance;
IdeConfigurationManager *manager;
GCancellable *cancellable;
GPtrArray *configurations;
GKeyFile *key_file;
......@@ -55,7 +54,6 @@ G_DEFINE_TYPE_EXTENDED (IdeBuildconfigConfigurationProvider, ide_buildconfig_con
G_IMPLEMENT_INTERFACE (IDE_TYPE_CONFIGURATION_PROVIDER,
configuration_provider_iface_init))
static void ide_buildconfig_configuration_provider_load (IdeConfigurationProvider *provider, IdeConfigurationManager *manager);
static void ide_buildconfig_configuration_provider_unload (IdeConfigurationProvider *provider, IdeConfigurationManager *manager);
static void
......@@ -511,11 +509,13 @@ ide_buildconfig_configuration_provider_load_cb (GObject *object,
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));
......@@ -544,35 +544,57 @@ ide_buildconfig_configuration_provider_load_cb (GObject *object,
self->configurations = g_steal_pointer (&ar);
if (error != NULL)
g_warning ("Failed to restore configuration: %s", error->message);
g_task_return_error (task, g_steal_pointer (&error));
else
g_task_return_boolean (task, TRUE);
IDE_EXIT;
}
static void
ide_buildconfig_configuration_provider_load (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager)
ide_buildconfig_configuration_provider_load_async (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
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));
ide_set_weak_pointer (&self->manager, manager);
self->cancellable = g_cancellable_new ();
/* This task is needed so the caller knows when the load finishes */
parent_task = g_task_new (self, cancellable, callback, user_data);
task = g_task_new (self, self->cancellable, ide_buildconfig_configuration_provider_load_cb, NULL);
g_task_set_source_tag (task, ide_buildconfig_configuration_provider_load);
/* 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);
}
static void
ide_buildconfig_configuration_provider_unload (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager)
......@@ -598,15 +620,27 @@ ide_buildconfig_configuration_provider_unload (IdeConfigurationProvider *provide
g_clear_pointer (&self->configurations, g_ptr_array_unref);
if (self->cancellable != NULL)
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
ide_clear_weak_pointer (&self->manager);
IDE_EXIT;
}
void
ide_buildconfig_configuration_provider_track_config (IdeBuildconfigConfigurationProvider *self,
IdeBuildconfigConfiguration *config)
{
g_assert (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (self));
g_return_if_fail (IDE_IS_BUILDCONFIG_CONFIGURATION (config));
g_signal_connect_object (config,
"changed",
G_CALLBACK (ide_buildconfig_configuration_provider_changed),
self,
G_CONNECT_SWAPPED);
g_ptr_array_add (self->configurations, config);
}
static void
ide_buildconfig_configuration_provider_class_init (IdeBuildconfigConfigurationProviderClass *klass)
{
......@@ -620,7 +654,8 @@ ide_buildconfig_configuration_provider_init (IdeBuildconfigConfigurationProvider
static void
configuration_provider_iface_init (IdeConfigurationProviderInterface *iface)
{
iface->load = ide_buildconfig_configuration_provider_load;
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;
......
......@@ -23,12 +23,17 @@
#include "ide-types.h"
#include "buildconfig/ide-buildconfig-configuration.h"
G_BEGIN_DECLS
#define IDE_TYPE_BUILDCONFIG_CONFIGURATION_PROVIDER (ide_buildconfig_configuration_provider_get_type())
G_DECLARE_FINAL_TYPE (IdeBuildconfigConfigurationProvider, ide_buildconfig_configuration_provider, IDE, BUILDCONFIG_CONFIGURATION_PROVIDER, GObject)
void ide_buildconfig_configuration_provider_track_config (IdeBuildconfigConfigurationProvider *self,
IdeBuildconfigConfiguration *config);
G_END_DECLS
#endif /* IDE_BUILDCONFIG_CONFIGURATION_PROVIDER_H */
......@@ -30,6 +30,9 @@
#include "buildsystem/ide-configuration.h"
#include "buildsystem/ide-configuration-provider.h"
#include "buildconfig/ide-buildconfig-configuration.h"
#include "buildconfig/ide-buildconfig-configuration-provider.h"
struct _IdeConfigurationManager
{
GObject parent_instance;
......@@ -37,6 +40,8 @@ struct _IdeConfigurationManager
GPtrArray *configurations;
IdeConfiguration *current;
PeasExtensionSet *extensions;
GCancellable *cancellable;
guint providers_loading;
};
static void async_initable_iface_init (GAsyncInitableIface *iface);
......@@ -65,19 +70,24 @@ static guint signals [N_SIGNALS];
static void
ide_configuration_manager_add_default (IdeConfigurationManager *self)
{
g_autoptr(IdeConfiguration) config = NULL;
g_autoptr(IdeBuildconfigConfiguration) config = NULL;
IdeContext *context;
g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
context = ide_object_get_context (IDE_OBJECT (self));
config = ide_configuration_new (context, "default", "local", "host");
ide_configuration_set_display_name (config, _("Default"));
ide_configuration_manager_add (self, config);
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, config);
ide_configuration_manager_set_current (self, IDE_CONFIGURATION (config));
}
static void
......@@ -254,6 +264,10 @@ ide_configuration_manager_finalize (GObject *object)
g_clear_object (&self->current);
}
if (self->cancellable != NULL)
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
G_OBJECT_CLASS (ide_configuration_manager_parent_class)->finalize (object);
}
......@@ -382,6 +396,79 @@ list_model_iface_init (GListModelInterface *iface)
iface->get_item = ide_configuration_manager_get_item;
}
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));
if (IDE_IS_BUILDCONFIG_CONFIGURATION_PROVIDER (provider) && config != NULL)
ide_buildconfig_configuration_provider_track_config ((IdeBuildconfigConfigurationProvider *)provider,
(IdeBuildconfigConfiguration *)g_object_ref (config));
}
static void
ide_configuration_manager_load_cb (GObject *object,
GAsyncResult *result,
gpointer user_data)
{
IdeConfigurationProvider *provider = (IdeConfigurationProvider *)object;
IdeConfigurationManager *self = user_data;
g_autoptr(GError) error = NULL;
IDE_ENTRY;
g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
g_assert (IDE_IS_CONFIGURATION_MANAGER (self));
g_assert (G_IS_TASK (result));
if (!ide_configuration_provider_load_finish (provider, result, &error))
g_warning ("%s: %s", G_OBJECT_TYPE_NAME (provider), error->message);
self->providers_loading--;
if (self->providers_loading == 0)
{
IdeConfiguration *default_config;
gboolean restored_buildconfig = FALSE;
for (guint i = 0; i < self->configurations->len; i++)
{
IdeConfiguration *configuration = g_ptr_array_index (self->configurations, i);
if (IDE_IS_BUILDCONFIG_CONFIGURATION (configuration) &&
g_strcmp0 ("default", ide_configuration_get_id (configuration)) != 0)
restored_buildconfig = TRUE;
}
/*
* If the default config was added by the manager rather than the provider,
* let the provider know about it so changes are persisted to the disk.
*/
default_config = ide_configuration_manager_get_configuration (self, "default");
if (!restored_buildconfig)
{
if (default_config == NULL)
{
ide_configuration_manager_add_default (self);
default_config = ide_configuration_manager_get_configuration (self, "default");
}
peas_extension_set_foreach (self->extensions,
ide_configuration_manager_track_buildconfig,
default_config);
}
}
IDE_EXIT;
}
static void
ide_configuration_manager_extension_added (PeasExtensionSet *set,
PeasPluginInfo *plugin_info,
......@@ -395,7 +482,12 @@ ide_configuration_manager_extension_added (PeasExtensionSet *set,
g_assert (plugin_info != NULL);
g_assert (IDE_IS_CONFIGURATION_PROVIDER (provider));
ide_configuration_provider_load (provider, self);
self->providers_loading++;
ide_configuration_provider_load_async (provider,
self,
self->cancellable,
ide_configuration_manager_load_cb,
self);
}
static void
......@@ -432,6 +524,10 @@ ide_configuration_manager_init_worker (GTask *task,
context = ide_object_get_context (IDE_OBJECT (self));
g_assert (IDE_IS_CONTEXT (context));
self->providers_loading = 0;
self->cancellable = g_cancellable_new ();
self->extensions = peas_extension_set_new (peas_engine_get_default (),
IDE_TYPE_CONFIGURATION_PROVIDER,
NULL);
......@@ -567,6 +663,15 @@ ide_configuration_manager_add (IdeConfigurationManager *self,
g_return_if_fail (IDE_IS_CONFIGURATION_MANAGER (self));
g_return_if_fail (IDE_IS_CONFIGURATION (configuration));
/* Allow the default config to be overridden by one from a provider */
if (g_strcmp0 ("default", ide_configuration_get_id (configuration)) == 0)
{
IdeConfiguration *default_config;
default_config = ide_configuration_manager_get_configuration (self, "default");
if (default_config != NULL)
g_ptr_array_remove_fast (self->configurations, default_config);
}
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);
......
......@@ -22,9 +22,32 @@
G_DEFINE_INTERFACE (IdeConfigurationProvider, ide_configuration_provider, G_TYPE_OBJECT)
static void
ide_configuration_provider_real_load (IdeConfigurationProvider *self,
IdeConfigurationManager *manager)
ide_configuration_provider_real_load_async (IdeConfigurationProvider *self,
IdeConfigurationManager *manager,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = user_data;
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));
g_return_if_fail (G_IS_TASK (task));
g_warning ("The current IdeConfigurationProvider doesn't implement load_async");
g_task_return_boolean (task, TRUE);
}
gboolean
ide_configuration_provider_real_load_finish (IdeConfigurationProvider *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (IDE_IS_CONFIGURATION_PROVIDER (self), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
return TRUE;
}
static void
......@@ -63,20 +86,36 @@ ide_configuration_provider_real_save_finish (IdeConfigurationProvider *self,
static void
ide_configuration_provider_default_init (IdeConfigurationProviderInterface *iface)
{
iface->load = ide_configuration_provider_real_load;
iface->load_async = ide_configuration_provider_real_load_async;
iface->load_finish = ide_configuration_provider_real_load_finish;
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;
}
void
ide_configuration_provider_load (IdeConfigurationProvider *self,
IdeConfigurationManager *manager)
ide_configuration_provider_load_async (IdeConfigurationProvider *self,
IdeConfigurationManager *manager,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
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 (self, manager);
gboolean
ide_configuration_provider_load_finish (IdeConfigurationProvider *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (IDE_IS_CONFIGURATION_PROVIDER (self), FALSE);
g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
return IDE_CONFIGURATION_PROVIDER_GET_IFACE (self)->save_finish (self, result, error);
}
void
......
......@@ -33,8 +33,14 @@ struct _IdeConfigurationProviderInterface
{
GTypeInterface parent;
void (*load) (IdeConfigurationProvider *self,
IdeConfigurationManager *manager);
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,
......@@ -46,8 +52,14 @@ struct _IdeConfigurationProviderInterface
GError **error);
};
void ide_configuration_provider_load (IdeConfigurationProvider *self,
IdeConfigurationManager *manager);
void ide_configuration_provider_load_async (IdeConfigurationProvider *self,
IdeConfigurationManager *manager,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean ide_configuration_provider_load_finish (IdeConfigurationProvider *self,
GAsyncResult *result,
GError **error);
void ide_configuration_provider_unload (IdeConfigurationProvider *self,
IdeConfigurationManager *manager);
void ide_configuration_provider_save_async (IdeConfigurationProvider *self,
......
......@@ -36,7 +36,6 @@ struct _GbpFlatpakConfigurationProvider
{
GObject parent_instance;
IdeConfigurationManager *manager;
GCancellable *cancellable;
GPtrArray *configurations;
GPtrArray *manifest_monitors;
......@@ -45,8 +44,6 @@ struct _GbpFlatpakConfigurationProvider
};
static void configuration_provider_iface_init (IdeConfigurationProviderInterface *iface);
static void gbp_flatpak_configuration_provider_load (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager);
static void gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager);
......@@ -999,16 +996,18 @@ gbp_flatpak_configuration_provider_load_cb (GObject *object,
GPtrArray *ret;
GError *error = NULL;
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_clear_error (&error);
g_task_return_error (task, g_steal_pointer (&error));
IDE_EXIT;
}
......@@ -1022,33 +1021,52 @@ gbp_flatpak_configuration_provider_load_cb (GObject *object,
self->configurations = ret;
g_task_return_boolean (task, TRUE);
IDE_EXIT;
}
static void
gbp_flatpak_configuration_provider_load (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager)
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 (!cancellable || G_IS_CANCELLABLE (cancellable));
ide_set_weak_pointer (&self->manager, manager);
self->manifest_monitors = g_ptr_array_new_with_free_func (g_object_unref);
self->cancellable = g_cancellable_new ();
task = g_task_new (self, self->cancellable, gbp_flatpak_configuration_provider_load_cb, NULL);
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));
g_task_run_in_thread (task, gbp_flatpak_configuration_provider_load_worker);
IDE_EXIT;
}
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);
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider,
IdeConfigurationManager *manager)
......@@ -1076,11 +1094,6 @@ gbp_flatpak_configuration_provider_unload (IdeConfigurationProvider *provider,
g_clear_pointer (&self->manifest_monitors, g_ptr_array_unref);
if (self->cancellable != NULL)
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
ide_clear_weak_pointer (&self->manager);
IDE_EXIT;
......@@ -1102,7 +1115,8 @@ gbp_flatpak_configuration_provider_init (GbpFlatpakConfigurationProvider *self)
static void
configuration_provider_iface_init (IdeConfigurationProviderInterface *iface)
{
iface->load = gbp_flatpak_configuration_provider_load;
iface->load_async = gbp_flatpak_configuration_provider_load_async;
iface->load_finish = gbp_flatpak_configuration_provider_load_finish;
iface->unload = gbp_flatpak_configuration_provider_unload;
iface->save_async = gbp_flatpak_configuration_provider_save_async;
iface->save_finish = gbp_flatpak_configuration_provider_save_finish;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment