[gnome-builder/wip/tintou/toolchain] Replace load by load_async/finish and use toolchain-added/removed signal in the provider



commit b5fa86fa75053cc002dd9bcb401a947d65c845ba
Author: Corentin Noël <corentin noel collabora co uk>
Date:   Fri Apr 13 15:15:00 2018 +0100

    Replace load by load_async/finish and use toolchain-added/removed signal in the provider

 src/libide/toolchain/ide-toolchain-manager.c     | 173 ++++++++++----
 src/libide/toolchain/ide-toolchain-manager.h     |   7 -
 src/libide/toolchain/ide-toolchain-provider.c    | 194 ++++++++++++++-
 src/libide/toolchain/ide-toolchain-provider.h    |  33 ++-
 src/plugins/cmake/gbp-cmake-toolchain-provider.c | 253 ++++++++++----------
 src/plugins/cmake/gbp-cmake-toolchain.c          |  72 ++----
 src/plugins/cmake/gbp-cmake-toolchain.h          |   8 +-
 src/plugins/meson/gbp-meson-toolchain-provider.c | 287 +++++++++++++++--------
 8 files changed, 672 insertions(+), 355 deletions(-)
---
diff --git a/src/libide/toolchain/ide-toolchain-manager.c b/src/libide/toolchain/ide-toolchain-manager.c
index cc013a1a5..de1dafdf0 100644
--- a/src/libide/toolchain/ide-toolchain-manager.c
+++ b/src/libide/toolchain/ide-toolchain-manager.c
@@ -30,6 +30,7 @@
 #include "buildsystem/ide-build-private.h"
 #include "config/ide-configuration.h"
 #include "devices/ide-device.h"
+#include "threading/ide-task.h"
 #include "toolchain/ide-simple-toolchain.h"
 #include "toolchain/ide-toolchain.h"
 #include "toolchain/ide-toolchain-manager.h"
@@ -38,9 +39,10 @@
 struct _IdeToolchainManager
 {
   IdeObject         parent_instance;
+
+  GCancellable     *cancellable;
   PeasExtensionSet *extensions;
   GPtrArray        *toolchains;
-  guint             unloading : 1;
 };
 
 typedef struct
@@ -64,6 +66,112 @@ prepare_state_free (PrepareState *state)
   g_slice_free (PrepareState, state);
 }
 
+static void
+ide_toolchain_manager_toolchain_added (IdeToolchainManager  *self,
+                                       IdeToolchain         *toolchain,
+                                       IdeToolchainProvider *provider)
+{
+  guint idx;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_TOOLCHAIN_MANAGER (self));
+  g_assert (IDE_IS_TOOLCHAIN (toolchain));
+  g_assert (IDE_IS_TOOLCHAIN_PROVIDER (provider));
+
+  idx = self->toolchains->len;
+  g_ptr_array_add (self->toolchains, g_object_ref (toolchain));
+  g_list_model_items_changed (G_LIST_MODEL (self), idx, 0, 1);
+
+  IDE_EXIT;
+}
+
+static void
+ide_toolchain_manager_toolchain_removed (IdeToolchainManager  *self,
+                                         IdeToolchain         *toolchain,
+                                         IdeToolchainProvider *provider)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_TOOLCHAIN_MANAGER (self));
+  g_assert (IDE_IS_TOOLCHAIN (toolchain));
+  g_assert (IDE_IS_TOOLCHAIN_PROVIDER (provider));
+
+  for (guint i = 0; i < self->toolchains->len; i++)
+    {
+      IdeToolchain *item = g_ptr_array_index (self->toolchains, i);
+
+      if (toolchain == item)
+        {
+          g_ptr_array_remove_index (self->toolchains, i);
+          g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
+          break;
+        }
+    }
+
+  IDE_EXIT;
+}
+
+static void
+ide_toolchain_manager_toolchain_load_cb (GObject      *object,
+                                         GAsyncResult *result,
+                                         gpointer      user_data)
+{
+  IdeToolchainProvider *provider = (IdeToolchainProvider *)object;
+  IdeContext *context;
+  g_autoptr(IdeToolchainManager) self = user_data;
+  g_autoptr(GError) error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_TOOLCHAIN_PROVIDER (provider));
+  g_assert (IDE_IS_TOOLCHAIN_MANAGER (self));
+  g_assert (IDE_IS_TASK (result));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+
+  if (!ide_toolchain_provider_load_finish (provider, result, &error))
+    ide_context_warning (context,
+                         "Failed to initialize toolchain provider: %s: %s",
+                         G_OBJECT_TYPE_NAME (provider), error->message);
+
+  IDE_EXIT;
+}
+
+static void
+provider_connect (IdeToolchainManager  *self,
+                  IdeToolchainProvider *provider)
+{
+  g_assert (IDE_IS_TOOLCHAIN_MANAGER (self));
+  g_assert (IDE_IS_TOOLCHAIN_PROVIDER (provider));
+
+  g_signal_connect_object (provider,
+                           "added",
+                           G_CALLBACK (ide_toolchain_manager_toolchain_added),
+                           self,
+                           G_CONNECT_SWAPPED);
+  g_signal_connect_object (provider,
+                           "removed",
+                           G_CALLBACK (ide_toolchain_manager_toolchain_removed),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+provider_disconnect (IdeToolchainManager  *self,
+                     IdeToolchainProvider *provider)
+{
+  g_assert (IDE_IS_TOOLCHAIN_MANAGER (self));
+  g_assert (IDE_IS_TOOLCHAIN_PROVIDER (provider));
+
+  g_signal_handlers_disconnect_by_func (provider,
+                                        G_CALLBACK (ide_toolchain_manager_toolchain_added),
+                                        self);
+  g_signal_handlers_disconnect_by_func (provider,
+                                        G_CALLBACK (ide_toolchain_manager_toolchain_removed),
+                                        self);
+}
+
 static void
 ide_toolchain_manager_extension_added (PeasExtensionSet *set,
                                        PeasPluginInfo   *plugin_info,
@@ -77,7 +185,12 @@ ide_toolchain_manager_extension_added (PeasExtensionSet *set,
   g_assert (plugin_info != NULL);
   g_assert (IDE_IS_TOOLCHAIN_PROVIDER (provider));
 
-  ide_toolchain_provider_load (provider, self);
+  provider_connect (self, provider);
+
+  ide_toolchain_provider_load_async (provider,
+                                     self->cancellable,
+                                     ide_toolchain_manager_toolchain_load_cb,
+                                     g_object_ref (self));
 }
 
 static void
@@ -93,6 +206,8 @@ ide_toolchain_manager_extension_removed (PeasExtensionSet *set,
   g_assert (plugin_info != NULL);
   g_assert (IDE_IS_TOOLCHAIN_PROVIDER (provider));
 
+  provider_disconnect (self, provider);
+
   ide_toolchain_provider_unload (provider, self);
 }
 
@@ -104,6 +219,7 @@ ide_toolchain_manager_initable_init (GInitable     *initable,
   IdeToolchainManager *self = (IdeToolchainManager *)initable;
   IdeContext *context;
   g_autoptr(IdeSimpleToolchain) default_toolchain = NULL;
+  guint idx;
 
   g_assert (IDE_IS_TOOLCHAIN_MANAGER (self));
   context = ide_object_get_context (IDE_OBJECT (self));
@@ -111,6 +227,7 @@ ide_toolchain_manager_initable_init (GInitable     *initable,
 
   self->extensions = peas_extension_set_new (peas_engine_get_default (),
                                              IDE_TYPE_TOOLCHAIN_PROVIDER,
+                                            "context", context,
                                              NULL);
 
   g_signal_connect (self->extensions,
@@ -127,8 +244,10 @@ ide_toolchain_manager_initable_init (GInitable     *initable,
                               ide_toolchain_manager_extension_added,
                               self);
 
+  idx = self->toolchains->len;
   default_toolchain = ide_simple_toolchain_new (context, "default");
-  ide_toolchain_manager_add (self, IDE_TOOLCHAIN (default_toolchain));
+  g_ptr_array_add (self->toolchains, g_object_ref (default_toolchain));
+  g_list_model_items_changed (G_LIST_MODEL (self), idx, 0, 1);
 
   return TRUE;
 }
@@ -139,22 +258,14 @@ initable_iface_init (GInitableIface *iface)
   iface->init = ide_toolchain_manager_initable_init;
 }
 
-void
-_ide_toolchain_manager_unload (IdeToolchainManager *self)
-{
-  g_return_if_fail (IDE_IS_TOOLCHAIN_MANAGER (self));
-
-  self->unloading = TRUE;
-  g_clear_object (&self->extensions);
-}
-
 static void
 ide_toolchain_manager_dispose (GObject *object)
 {
   IdeToolchainManager *self = (IdeToolchainManager *)object;
 
-  _ide_toolchain_manager_unload (self);
+  g_clear_object (&self->extensions);
   g_clear_pointer (&self->toolchains, g_ptr_array_unref);
+  g_clear_object (&self->cancellable);
 
   G_OBJECT_CLASS (ide_toolchain_manager_parent_class)->dispose (object);
 }
@@ -170,6 +281,7 @@ ide_toolchain_manager_class_init (IdeToolchainManagerClass *klass)
 static void
 ide_toolchain_manager_init (IdeToolchainManager *self)
 {
+  self->cancellable = g_cancellable_new ();
   self->toolchains = g_ptr_array_new_with_free_func (g_object_unref);
 }
 
@@ -209,41 +321,6 @@ list_model_iface_init (GListModelInterface *iface)
   iface->get_item = ide_toolchain_manager_get_item;
 }
 
-void
-ide_toolchain_manager_add (IdeToolchainManager *self,
-                           IdeToolchain        *toolchain)
-{
-  guint idx;
-
-  g_return_if_fail (IDE_IS_TOOLCHAIN_MANAGER (self));
-  g_return_if_fail (IDE_IS_TOOLCHAIN (toolchain));
-
-  idx = self->toolchains->len;
-  g_ptr_array_add (self->toolchains, g_object_ref (toolchain));
-  g_list_model_items_changed (G_LIST_MODEL (self), idx, 0, 1);
-}
-
-void
-ide_toolchain_manager_remove (IdeToolchainManager *self,
-                              IdeToolchain        *toolchain)
-{
-  g_return_if_fail (IDE_IS_TOOLCHAIN_MANAGER (self));
-  g_return_if_fail (IDE_IS_TOOLCHAIN (toolchain));
-
-  for (guint i = 0; i < self->toolchains->len; i++)
-    {
-      IdeToolchain *item = g_ptr_array_index (self->toolchains, i);
-
-      if (toolchain == item)
-        {
-          g_ptr_array_remove_index (self->toolchains, i);
-          if (!ide_object_is_unloading (IDE_OBJECT (self)))
-            g_list_model_items_changed (G_LIST_MODEL (self), i, 1, 0);
-          break;
-        }
-    }
-}
-
 /**
  * ide_toolchain_manager_get_toolchain:
  * @self: An #IdeToolchainManager
diff --git a/src/libide/toolchain/ide-toolchain-manager.h b/src/libide/toolchain/ide-toolchain-manager.h
index 91e782be6..f4ef26d34 100644
--- a/src/libide/toolchain/ide-toolchain-manager.h
+++ b/src/libide/toolchain/ide-toolchain-manager.h
@@ -34,11 +34,4 @@ G_DECLARE_FINAL_TYPE (IdeToolchainManager, ide_toolchain_manager, IDE, TOOLCHAIN
 IDE_AVAILABLE_IN_3_30
 IdeToolchain *ide_toolchain_manager_get_toolchain (IdeToolchainManager  *self,
                                                    const gchar          *id);
-IDE_AVAILABLE_IN_3_30
-void          ide_toolchain_manager_add           (IdeToolchainManager  *self,
-                                                   IdeToolchain         *toolchain);
-IDE_AVAILABLE_IN_3_30
-void          ide_toolchain_manager_remove        (IdeToolchainManager  *self,
-                                                   IdeToolchain         *toolchain);
-
 G_END_DECLS
diff --git a/src/libide/toolchain/ide-toolchain-provider.c b/src/libide/toolchain/ide-toolchain-provider.c
index 4ef94d96d..198c64f82 100644
--- a/src/libide/toolchain/ide-toolchain-provider.c
+++ b/src/libide/toolchain/ide-toolchain-provider.c
@@ -23,24 +23,48 @@
 
 #include "ide-debug.h"
 
+#include "application/ide-application.h"
 #include "toolchain/ide-toolchain-provider.h"
 
-G_DEFINE_INTERFACE (IdeToolchainProvider, ide_toolchain_provider, G_TYPE_OBJECT)
+G_DEFINE_INTERFACE (IdeToolchainProvider, ide_toolchain_provider, IDE_TYPE_OBJECT)
+
+enum {
+  ADDED,
+  REMOVED,
+  N_SIGNALS
+};
+
+static guint signals [N_SIGNALS];
 
 static void
-ide_toolchain_provider_default_init (IdeToolchainProviderInterface *iface)
+ide_toolchain_provider_real_load_async (IdeToolchainProvider *self,
+                                        GCancellable         *cancellable,
+                                        GAsyncReadyCallback   callback,
+                                        gpointer              user_data)
 {
-  
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_TOOLCHAIN_PROVIDER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  g_task_report_new_error (self, callback, user_data,
+                           ide_toolchain_provider_real_load_async,
+                           G_IO_ERROR,
+                           G_IO_ERROR_NOT_SUPPORTED,
+                           "%s does not implement load_async",
+                           G_OBJECT_TYPE_NAME (self));
 }
 
-void
-ide_toolchain_provider_load (IdeToolchainProvider *self,
-                             IdeToolchainManager  *manager)
+gboolean
+ide_toolchain_provider_real_load_finish (IdeToolchainProvider  *self,
+                                         GAsyncResult          *result,
+                                         GError               **error)
 {
-  g_return_if_fail (IDE_IS_TOOLCHAIN_PROVIDER (self));
-  g_return_if_fail (IDE_IS_TOOLCHAIN_MANAGER (manager));
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_TOOLCHAIN_PROVIDER (self));
+  g_assert (G_IS_TASK (result));
+  g_assert (g_task_is_valid (G_TASK (result), self));
 
-  IDE_TOOLCHAIN_PROVIDER_GET_IFACE (self)->load (self, manager);
+  return g_task_propagate_boolean (G_TASK (self), error);
 }
 
 void
@@ -52,3 +76,155 @@ ide_toolchain_provider_unload (IdeToolchainProvider *self,
 
   IDE_TOOLCHAIN_PROVIDER_GET_IFACE (self)->unload (self, manager);
 }
+
+static void
+ide_toolchain_provider_real_unload (IdeToolchainProvider *self,
+                                    IdeToolchainManager  *manager)
+{
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_TOOLCHAIN_PROVIDER (self));
+  g_assert (IDE_IS_TOOLCHAIN_MANAGER (manager));
+
+}
+
+static void
+ide_toolchain_provider_default_init (IdeToolchainProviderInterface *iface)
+{
+  iface->load_async = ide_toolchain_provider_real_load_async;
+  iface->load_finish = ide_toolchain_provider_real_load_finish;
+  iface->unload = ide_toolchain_provider_real_unload;
+
+  /**
+   * IdeToolchainProvider:added:
+   * @self: an #IdeToolchainProvider
+   * @toolchain: an #IdeToolchain
+   *
+   * The "added" signal is emitted when a toolchain
+   * has been added to a toolchain provider.
+   *
+   * Since: 3.30
+   */
+  signals [ADDED] =
+    g_signal_new ("added",
+                  G_TYPE_FROM_INTERFACE (iface),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (IdeToolchainProviderInterface, added),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, IDE_TYPE_TOOLCHAIN);
+  g_signal_set_va_marshaller (signals [ADDED],
+                              G_TYPE_FROM_INTERFACE (iface),
+                              g_cclosure_marshal_VOID__OBJECTv);
+
+  /**
+   * IdeToolchainProvider:removed:
+   * @self: an #IdeToolchainProvider
+   * @toolchain: an #IdeToolchain
+   *
+   * The "removed" signal is emitted when a toolchain
+   * has been removed from a toolchain provider.
+   *
+   * Since: 3.30
+   */
+  signals [REMOVED] =
+    g_signal_new ("removed",
+                  G_TYPE_FROM_INTERFACE (iface),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (IdeToolchainProviderInterface, removed),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__OBJECT,
+                  G_TYPE_NONE, 1, IDE_TYPE_TOOLCHAIN);
+  g_signal_set_va_marshaller (signals [REMOVED],
+                              G_TYPE_FROM_INTERFACE (iface),
+                              g_cclosure_marshal_VOID__OBJECTv);
+
+}
+
+/**
+ * ide_toolchain_provider_load_async:
+ * @self: a #IdeToolchainProvider
+ * @manager: a #IdeToolchainManager
+ * @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 toolchain provider after
+ * the plugin instance has been created. The provider should locate any
+ * toolchain within the project and call ide_toolchain_provider_emit_added()
+ * before completing the asynchronous function so that the toolchain
+ * manager may be made aware of the toolchains.
+ *
+ * Since: 3.28
+ */
+void
+ide_toolchain_provider_load_async (IdeToolchainProvider *self,
+                                   GCancellable         *cancellable,
+                                   GAsyncReadyCallback   callback,
+                                   gpointer              user_data)
+{
+  g_return_if_fail (IDE_IS_TOOLCHAIN_PROVIDER (self));
+
+  IDE_TOOLCHAIN_PROVIDER_GET_IFACE (self)->load_async (self, cancellable, callback, user_data);
+}
+
+/**
+ * ide_toolchain_provider_load_finish:
+ * @self: a #IdeToolchainProvider
+ * @result: a #GAsyncResult
+ * @error: a location for a #GError, or %NULL
+ *
+ * Completes an asynchronous request to ide_toolchain_provider_load_async().
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error is set.
+ */
+gboolean
+ide_toolchain_provider_load_finish (IdeToolchainProvider  *self,
+                                    GAsyncResult          *result,
+                                    GError               **error)
+{
+  g_return_val_if_fail (IDE_IS_MAIN_THREAD (), FALSE);
+  g_return_val_if_fail (IDE_IS_TOOLCHAIN_PROVIDER (self), FALSE);
+  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+  return IDE_TOOLCHAIN_PROVIDER_GET_IFACE (self)->load_finish (self, result, error);
+}
+
+/**
+ * ide_toolchain_provider_emit_added:
+ * @self: an #IdeToolchainProvider
+ * @toolchain: an #IdeToolchain
+ *
+ * #IdeToolchainProvider implementations should call this function with
+ * a @toolchain when it has discovered a new toolchain.
+ *
+ * Since: 3.30
+ */
+void
+ide_toolchain_provider_emit_added (IdeToolchainProvider *self,
+                                   IdeToolchain         *toolchain)
+{
+  g_return_if_fail (IDE_IS_TOOLCHAIN_PROVIDER (self));
+  g_return_if_fail (IDE_IS_TOOLCHAIN (toolchain));
+
+  g_signal_emit (self, signals [ADDED], 0, toolchain);
+}
+
+/**
+ * ide_toolchain_provider_emit_removed:
+ * @self: an #IdeToolchainProvider
+ * @toolchain: an #IdeToolchain
+ *
+ * #IdeToolchainProvider implementations should call this function with
+ * a @toolchain when the toolchain was removed.
+ *
+ * Since: 3.30
+ */
+void
+ide_toolchain_provider_emit_removed (IdeToolchainProvider *self,
+                                     IdeToolchain         *toolchain)
+{
+  g_return_if_fail (IDE_IS_TOOLCHAIN_PROVIDER (self));
+  g_return_if_fail (IDE_IS_TOOLCHAIN (toolchain));
+
+  g_signal_emit (self, signals [REMOVED], 0, toolchain);
+}
diff --git a/src/libide/toolchain/ide-toolchain-provider.h b/src/libide/toolchain/ide-toolchain-provider.h
index c5c4477f1..098ee3b63 100644
--- a/src/libide/toolchain/ide-toolchain-provider.h
+++ b/src/libide/toolchain/ide-toolchain-provider.h
@@ -35,17 +35,38 @@ struct _IdeToolchainProviderInterface
 {
   GTypeInterface parent_iface;
 
-  void        (*load)             (IdeToolchainProvider  *self,
-                                   IdeToolchainManager   *manager);
+  void        (*load_async)       (IdeToolchainProvider  *self,
+                                   GCancellable          *cancellable,
+                                   GAsyncReadyCallback    callback,
+                                   gpointer               user_data);
+  gboolean    (*load_finish)      (IdeToolchainProvider  *self,
+                                   GAsyncResult          *result,
+                                   GError               **error);
   void        (*unload)           (IdeToolchainProvider  *self,
                                    IdeToolchainManager   *manager);
+  void        (*added)            (IdeToolchainProvider  *self,
+                                   IdeToolchain          *toolchain);
+  void        (*removed)          (IdeToolchainProvider  *self,
+                                   IdeToolchain          *toolchain);
 };
 
 IDE_AVAILABLE_IN_3_30
-void        ide_toolchain_provider_load   (IdeToolchainProvider  *self,
-                                           IdeToolchainManager   *manager);
+void        ide_toolchain_provider_load_async   (IdeToolchainProvider  *self,
+                                                 GCancellable          *cancellable,
+                                                 GAsyncReadyCallback    callback,
+                                                 gpointer               user_data);
+IDE_AVAILABLE_IN_3_30
+gboolean    ide_toolchain_provider_load_finish  (IdeToolchainProvider  *self,
+                                                 GAsyncResult          *result,
+                                                 GError               **error);
 IDE_AVAILABLE_IN_3_30
-void        ide_toolchain_provider_unload (IdeToolchainProvider  *self,
-                                           IdeToolchainManager   *manager);
+void        ide_toolchain_provider_unload       (IdeToolchainProvider  *self,
+                                                 IdeToolchainManager   *manager);
+IDE_AVAILABLE_IN_3_28
+void        ide_toolchain_provider_emit_added   (IdeToolchainProvider  *self,
+                                                 IdeToolchain          *toolchain);
+IDE_AVAILABLE_IN_3_28
+void        ide_toolchain_provider_emit_removed (IdeToolchainProvider  *self,
+                                                 IdeToolchain          *toolchain);
 
 G_END_DECLS
diff --git a/src/plugins/cmake/gbp-cmake-toolchain-provider.c 
b/src/plugins/cmake/gbp-cmake-toolchain-provider.c
index 9db68fe62..84fd069ec 100644
--- a/src/plugins/cmake/gbp-cmake-toolchain-provider.c
+++ b/src/plugins/cmake/gbp-cmake-toolchain-provider.c
@@ -26,170 +26,168 @@
 struct _GbpCMakeToolchainProvider
 {
   IdeObject            parent_instance;
-  IdeToolchainManager *manager;
-  GCancellable        *loading_cancellable;
+  GPtrArray           *toolchains;
 };
 
-void
-cmake_toolchain_provider_search_folder (GbpCMakeToolchainProvider  *self,
-                                        GFile                      *file);
-
-
 static void
-gbp_cmake_toolchain_verify_async_cb (GObject      *object,
-                                     GAsyncResult *result,
-                                     gpointer      user_data)
-{
-  GbpCMakeToolchain *toolchain = (GbpCMakeToolchain *)object;
-  GbpCMakeToolchainProvider *provider = user_data;
-  g_autoptr(GError) error = NULL;
-
-  IDE_ENTRY;
-
-  g_assert (GBP_IS_CMAKE_TOOLCHAIN (toolchain));
-  g_assert (GBP_IS_CMAKE_TOOLCHAIN_PROVIDER (provider));
-
-  if (!gbp_cmake_toolchain_verify_finish (toolchain, result, &error))
-    IDE_EXIT;
-
-  ide_toolchain_manager_add (provider->manager, IDE_TOOLCHAIN (toolchain));
-  IDE_EXIT;
-}
-
-void
-cmake_toolchain_provider_add_crossfile (GbpCMakeToolchainProvider  *self,
-                                        GFile                      *file)
+gbp_cmake_toolchain_provider_load_worker (IdeTask      *task,
+                                          gpointer      source_object,
+                                          gpointer      task_data,
+                                          GCancellable *cancellable)
 {
+  GbpCMakeToolchainProvider *self = source_object;
+  g_autoptr(GPtrArray) toolchains = NULL;
   IdeContext *context;
-  g_autoptr(GbpCMakeToolchain) toolchain = NULL;
+  GPtrArray *files = task_data;
 
+  g_assert (IDE_IS_TASK (task));
   g_assert (GBP_IS_CMAKE_TOOLCHAIN_PROVIDER (self));
-  g_assert (G_IS_FILE (file));
+  g_assert (files != NULL);
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  context = ide_object_get_context (IDE_OBJECT (self->manager));
-  toolchain = gbp_cmake_toolchain_new (context, file);
+  context = ide_object_get_context (IDE_OBJECT (self));
+  toolchains = g_ptr_array_new_with_free_func (g_object_unref);
 
-  gbp_cmake_toolchain_verify_async (g_steal_pointer (&toolchain), NULL, gbp_cmake_toolchain_verify_async_cb, 
self);
-}
-
-void
-cmake_toolchain_enumerate_children_cb (GObject      *object,
-                                       GAsyncResult *result,
-                                       gpointer      user_data)
-{
-  GbpCMakeToolchainProvider *self = (GbpCMakeToolchainProvider *)user_data;
-  GFile *dir = (GFile *)object;
-  g_autoptr(GError) error = NULL;
-  g_autoptr(GPtrArray) infos = NULL;
-
-  g_assert (G_IS_FILE (dir));
-  g_assert (G_IS_ASYNC_RESULT (result));
-  g_assert (GBP_IS_CMAKE_TOOLCHAIN_PROVIDER (self));
-
-  infos = ide_g_file_get_children_finish (dir, result, &error);
-
-  if (infos == NULL)
-    return;
-
-  for (guint i = 0; i < infos->len; i++)
+  for (guint i = 0; i < files->len; i++)
     {
-      GFileInfo *file_info = g_ptr_array_index (infos, i);
-      GFileType file_type = g_file_info_get_file_type (file_info);
+      GFile *file = g_ptr_array_index (files, i);
+      g_autofree gchar *name = NULL;
 
-      if (file_type == G_FILE_TYPE_REGULAR)
+      g_assert (G_IS_FILE (file));
+
+      name = g_file_get_basename (file);
+      /* Cross-compilation files have .cmake extension, we have to blacklist CMakeSystem.cmake
+       * in case we are looking into a build folder */
+      if (g_strcmp0(name, "CMakeSystem.cmake") != 0)
         {
-          const gchar *name = g_file_info_get_name (file_info);
-          /* Cross-compilation files have .cmake extension, we have to blacklist CMakeSystem.cmake
-           * in case we are looking into a build folder */
-          if (g_str_has_suffix (name, ".cmake") && g_strcmp0(name, "CMakeSystem.cmake") != 0)
+          g_autoptr(GError) file_error = NULL;
+          g_autofree gchar *file_path = g_file_get_path (file);
+          g_autofree gchar *file_contents = NULL;
+          gsize file_contents_len;
+
+          /* Cross-compilation files should at least define CMAKE_SYSTEM_NAME and CMAKE_SYSTEM_PROCESSOR */
+          if (g_file_get_contents (file_path,
+                                   &file_contents, &file_contents_len, &file_error))
             {
-              const gchar *content_type = g_file_info_get_content_type (file_info);
-
-              if (g_content_type_is_mime_type (content_type, "text/x-cmake"))
+              const gchar *system_name = g_strstr_len (file_contents,
+                                                       file_contents_len,
+                                                       "CMAKE_SYSTEM_NAME");
+              if (system_name != NULL)
                 {
-                  g_autoptr(GFile) child = g_file_get_child (dir, name);
-                  g_autoptr(GError) file_error = NULL;
-                  g_autofree gchar *file_path = g_file_get_path (child);
-                  g_autofree gchar *file_contents = NULL;
-                  gsize file_contents_len;
-
-                  /* Cross-compilation files should at least define CMAKE_SYSTEM_NAME and 
CMAKE_SYSTEM_PROCESSOR */
-                  if (g_file_get_contents (file_path,
-                                           &file_contents, &file_contents_len, &file_error))
+                  const gchar *processor_name = g_strstr_len (file_contents,
+                                                              file_contents_len,
+                                                              "CMAKE_SYSTEM_PROCESSOR");
+                  if (processor_name != NULL)
                     {
-                      const gchar *system_name = g_strstr_len (file_contents,
-                                                               file_contents_len,
-                                                               "CMAKE_SYSTEM_NAME");
-                      if (system_name != NULL)
-                        {
-                          const gchar *processor_name = g_strstr_len (file_contents,
-                                                                      file_contents_len,
-                                                                      "CMAKE_SYSTEM_PROCESSOR");
-                          if (processor_name != NULL)
-                            {
-                              cmake_toolchain_provider_add_crossfile (self, child);
-                            }
-                        }
+                      g_autoptr(GbpCMakeToolchain) toolchain = gbp_cmake_toolchain_new (context, file);
+                      if (gbp_cmake_toolchain_verify (toolchain))
+                        g_ptr_array_add (toolchains, g_steal_pointer (&toolchain));
                     }
                 }
-          }
-        }
-      else if (file_type == G_FILE_TYPE_DIRECTORY)
-        {
-          const gchar *name = g_file_info_get_name (file_info);
-          g_autoptr(GFile) child = g_file_get_child (dir, name);
-
-          cmake_toolchain_provider_search_folder (self, child);
+            }
         }
     }
+
+  ide_task_return_pointer (task,
+                           g_steal_pointer (&toolchains),
+                           (GDestroyNotify)g_ptr_array_unref);
 }
 
-void
-cmake_toolchain_provider_search_folder (GbpCMakeToolchainProvider  *self,
-                                        GFile                      *file)
+static void
+load_find_files_cb (GObject      *object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
 {
-  g_assert (GBP_IS_CMAKE_TOOLCHAIN_PROVIDER (self));
+  GFile *file = (GFile *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GPtrArray) ret = NULL;
+
   g_assert (G_IS_FILE (file));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  ret = ide_g_file_find_finish (file, result, &error);
+  IDE_PTR_ARRAY_SET_FREE_FUNC (ret, g_object_unref);
 
-  ide_g_file_get_children_async (file,
-                                 G_FILE_ATTRIBUTE_STANDARD_NAME","
-                                 G_FILE_ATTRIBUTE_STANDARD_TYPE","
-                                 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
-                                 G_FILE_QUERY_INFO_NONE,
-                                 G_PRIORITY_LOW,
-                                 self->loading_cancellable,
-                                 cmake_toolchain_enumerate_children_cb,
-                                 self);
+  if (ret == NULL)
+    {
+      ide_task_return_error (task, g_steal_pointer (&error));
+      return;
+    }
+
+  ide_task_set_task_data (task, g_steal_pointer (&ret), (GDestroyNotify)g_ptr_array_unref);
+  ide_task_run_in_thread (task, gbp_cmake_toolchain_provider_load_worker);
 }
 
-void
-gbp_cmake_toolchain_provider_load (IdeToolchainProvider  *provider,
-                                   IdeToolchainManager   *manager)
+static void
+gbp_cmake_toolchain_provider_load_async (IdeToolchainProvider     *provider,
+                                         GCancellable             *cancellable,
+                                         GAsyncReadyCallback       callback,
+                                         gpointer                  user_data)
 {
-  GbpCMakeToolchainProvider *self = (GbpCMakeToolchainProvider *) provider;
+  GbpCMakeToolchainProvider *self = (GbpCMakeToolchainProvider *)provider;
+  g_autoptr(IdeTask) task = NULL;
   IdeContext *context;
-  g_autoptr(GFile) project_folder = NULL;
+  IdeVcs *vcs;
+  GFile *workdir;
 
   IDE_ENTRY;
 
+  g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (GBP_IS_CMAKE_TOOLCHAIN_PROVIDER (self));
-  g_assert (IDE_IS_TOOLCHAIN_MANAGER (manager));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  self->manager = g_object_ref (manager);
+  context = ide_object_get_context (IDE_OBJECT (self));
+  vcs = ide_context_get_vcs (context);
+  workdir = ide_vcs_get_working_directory (vcs);
 
-  context = ide_object_get_context (IDE_OBJECT (manager));
-  g_return_if_fail (IDE_IS_CONTEXT (context));
-  if (!GBP_IS_CMAKE_BUILD_SYSTEM (ide_context_get_build_system (context)))
-    return;
+  task = ide_task_new (provider, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, gbp_cmake_toolchain_provider_load_async);
+  ide_task_set_priority (task, G_PRIORITY_LOW);
 
-  self->loading_cancellable = g_cancellable_new ();
-
-  project_folder = g_file_get_parent (ide_context_get_project_file (context));
-  cmake_toolchain_provider_search_folder (self, project_folder);
+  ide_g_file_find_async (workdir,
+                         "*.cmake",
+                         cancellable,
+                         load_find_files_cb,
+                         g_steal_pointer (&task));
 
   IDE_EXIT;
 }
 
+static gboolean
+gbp_cmake_toolchain_provider_load_finish (IdeToolchainProvider  *provider,
+                                          GAsyncResult          *result,
+                                          GError               **error)
+{
+  GbpCMakeToolchainProvider *self = (GbpCMakeToolchainProvider *)provider;
+  g_autoptr(GPtrArray) toolchains = NULL;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_CMAKE_TOOLCHAIN_PROVIDER (self));
+  g_assert (IDE_IS_TASK (result));
+  g_assert (ide_task_is_valid (IDE_TASK (result), provider));
+
+  toolchains = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+  if (toolchains == NULL)
+    return FALSE;
+
+  g_clear_pointer (&self->toolchains, g_ptr_array_unref);
+  self->toolchains = g_ptr_array_ref (toolchains);
+
+  for (guint i = 0; i < toolchains->len; i++)
+    {
+      IdeToolchain *toolchain = g_ptr_array_index (toolchains, i);
+
+      g_assert (IDE_IS_TOOLCHAIN (toolchain));
+
+      ide_toolchain_provider_emit_added (provider, toolchain);
+    }
+
+  return TRUE;
+}
+
 void
 gbp_cmake_toolchain_provider_unload (IdeToolchainProvider  *provider,
                                      IdeToolchainManager   *manager)
@@ -199,13 +197,14 @@ gbp_cmake_toolchain_provider_unload (IdeToolchainProvider  *provider,
   g_assert (GBP_IS_CMAKE_TOOLCHAIN_PROVIDER (self));
   g_assert (IDE_IS_TOOLCHAIN_MANAGER (manager));
 
-  g_clear_object (&self->manager);
+  g_clear_pointer (&self->toolchains, g_ptr_array_unref);
 }
 
 static void
 toolchain_provider_iface_init (IdeToolchainProviderInterface *iface)
 {
-  iface->load = gbp_cmake_toolchain_provider_load;
+  iface->load_async = gbp_cmake_toolchain_provider_load_async;
+  iface->load_finish = gbp_cmake_toolchain_provider_load_finish;
   iface->unload = gbp_cmake_toolchain_provider_unload;
 }
 
diff --git a/src/plugins/cmake/gbp-cmake-toolchain.c b/src/plugins/cmake/gbp-cmake-toolchain.c
index 339ddfe04..5b13400c7 100644
--- a/src/plugins/cmake/gbp-cmake-toolchain.c
+++ b/src/plugins/cmake/gbp-cmake-toolchain.c
@@ -31,6 +31,7 @@ struct _GbpCMakeToolchain
   gchar                  *archiver;
   gchar                  *pkg_config;
   GHashTable             *compilers;
+  GCancellable           *verify_cancellable;
 };
 
 G_DEFINE_TYPE (GbpCMakeToolchain, gbp_cmake_toolchain, IDE_TYPE_TOOLCHAIN)
@@ -190,13 +191,11 @@ gbp_cmake_toolchain_get_tool_for_language (IdeToolchain  *toolchain,
   return NULL;
 }
 
-static void
-gbp_cmake_toolchain_verify_worker (IdeTask      *task,
-                                   gpointer      source_object,
-                                   gpointer      task_data,
-                                   GCancellable *cancellable)
+/* It is far easier and more reliable to get the variables from cmake itself,
+ * Here is a small projects that exports the content of the cross-file */
+gboolean
+gbp_cmake_toolchain_verify (GbpCMakeToolchain *self)
 {
-  GbpCMakeToolchain *self = source_object;
   g_autoptr(GError) error = NULL;
   g_autofree gchar *tmp_dir = NULL;
   g_autofree gchar *toolchain_arg = NULL;
@@ -205,7 +204,10 @@ gbp_cmake_toolchain_verify_worker (IdeTask      *task,
 
   g_assert (GBP_IS_CMAKE_TOOLCHAIN (self));
 
-  tmp_dir = _gbp_cmake_toolchain_deploy_temporary_cmake (cancellable);
+  g_clear_object (&self->verify_cancellable);
+  self->verify_cancellable = g_cancellable_new ();
+
+  tmp_dir = _gbp_cmake_toolchain_deploy_temporary_cmake (self->verify_cancellable);
   toolchain_arg = g_strdup_printf ("-DCMAKE_TOOLCHAIN_FILE=%s", self->file_path);
 
   cmake_launcher = ide_subprocess_launcher_new 
(G_SUBPROCESS_FLAGS_STDOUT_SILENCE|G_SUBPROCESS_FLAGS_STDERR_SILENCE);
@@ -213,66 +215,20 @@ gbp_cmake_toolchain_verify_worker (IdeTask      *task,
   ide_subprocess_launcher_push_argv (cmake_launcher, ".");
   ide_subprocess_launcher_push_argv (cmake_launcher, toolchain_arg);
   ide_subprocess_launcher_set_cwd (cmake_launcher, tmp_dir);
-  cmake_subprocess = ide_subprocess_launcher_spawn (cmake_launcher, cancellable, &error);
-  if (!ide_subprocess_wait_check (cmake_subprocess, cancellable, &error))
+  cmake_subprocess = ide_subprocess_launcher_spawn (cmake_launcher, self->verify_cancellable, &error);
+  if (!ide_subprocess_wait_check (cmake_subprocess, self->verify_cancellable, &error))
     {
-      ide_task_return_new_error (task,
-                                 G_IO_ERROR,
-                                 G_IO_ERROR_INVALID_FILENAME,
-                                 "Error Testing CMake Cross-compilation file : %s",
-                                 self->file_path);
+      g_debug ("Error Testing CMake Cross-compilation file : %s", self->file_path);
       return;
     }
 
   if (!_gbp_cmake_toolchain_parse_keyfile (self, tmp_dir))
     {
-      ide_task_return_new_error (task,
-                                 G_IO_ERROR,
-                                 G_IO_ERROR_INVALID_FILENAME,
-                                 "Error Testing CMake Cross-compilation file : %s",
-                                 self->file_path);
+      g_debug ("Error Testing CMake Cross-compilation file : %s", self->file_path);
       return;
     }
 
-  ide_task_return_boolean (task, TRUE);
-}
-
-/* It is far easier and more reliable to get the variables from cmake itself,
- * Here is a small projects that exports the content of the cross-file */
-void
-gbp_cmake_toolchain_verify_async (GbpCMakeToolchain    *self,
-                                  GCancellable         *cancellable,
-                                  GAsyncReadyCallback   callback,
-                                  gpointer              user_data)
-{
-  g_autoptr(IdeTask) task = NULL;
-
-  IDE_ENTRY;
-
-  g_assert (GBP_IS_CMAKE_TOOLCHAIN (self));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  task = ide_task_new (self, cancellable, callback, user_data);
-  ide_task_run_in_thread (task, gbp_cmake_toolchain_verify_worker);
-
-  IDE_EXIT;
-}
-
-gboolean
-gbp_cmake_toolchain_verify_finish (GbpCMakeToolchain  *self,
-                                   GAsyncResult       *result,
-                                   GError            **error)
-{
-  IdeTask *task = (IdeTask *)result;
-  gboolean ret;
-
-  IDE_ENTRY;
-
-  g_return_val_if_fail (GBP_IS_CMAKE_TOOLCHAIN (self), FALSE);
-
-  ret = ide_task_propagate_boolean (task, error);
-
-  IDE_RETURN (ret);
+  return TRUE;
 }
 
 static void
diff --git a/src/plugins/cmake/gbp-cmake-toolchain.h b/src/plugins/cmake/gbp-cmake-toolchain.h
index d19e9874c..f886e4c44 100644
--- a/src/plugins/cmake/gbp-cmake-toolchain.h
+++ b/src/plugins/cmake/gbp-cmake-toolchain.h
@@ -32,12 +32,6 @@ GbpCMakeToolchain  *gbp_cmake_toolchain_new           (IdeContext           *con
 const gchar        *gbp_cmake_toolchain_get_file_path (GbpCMakeToolchain    *self);
 void                gbp_cmake_toolchain_set_file_path (GbpCMakeToolchain    *self,
                                                        const gchar          *file_path);
-void                gbp_cmake_toolchain_verify_async  (GbpCMakeToolchain    *self,
-                                                       GCancellable         *cancellable,
-                                                       GAsyncReadyCallback   callback,
-                                                       gpointer              user_data);
-gboolean            gbp_cmake_toolchain_verify_finish (GbpCMakeToolchain    *self,
-                                                       GAsyncResult         *result,
-                                                       GError              **error);
+gboolean            gbp_cmake_toolchain_verify        (GbpCMakeToolchain    *self);
 
 G_END_DECLS
diff --git a/src/plugins/meson/gbp-meson-toolchain-provider.c 
b/src/plugins/meson/gbp-meson-toolchain-provider.c
index 9be994ab0..1199faf6d 100644
--- a/src/plugins/meson/gbp-meson-toolchain-provider.c
+++ b/src/plugins/meson/gbp-meson-toolchain-provider.c
@@ -26,147 +26,247 @@
 struct _GbpMesonToolchainProvider
 {
   IdeObject            parent_instance;
-  IdeToolchainManager *manager;
-  GCancellable        *loading_cancellable;
+  GPtrArray           *toolchains;
 };
 
-void
-meson_toolchain_provider_search_folder (GbpMesonToolchainProvider  *self,
-                                        GFile                      *file);
-
-void
-meson_toolchain_provider_add_crossfile (GbpMesonToolchainProvider  *self,
-                                        GFile                      *file)
+typedef struct
 {
-  IdeContext *context;
-  g_autoptr(GbpMesonToolchain) toolchain = NULL;
-
-  g_assert (GBP_IS_MESON_TOOLCHAIN_PROVIDER (self));
-  g_assert (G_IS_FILE (file));
+  GList     *folders;
+  GPtrArray *found_files;
+  IdeTask   *task;
+} FileSearching;
 
-  context = ide_object_get_context (IDE_OBJECT (self->manager));
-  toolchain = gbp_meson_toolchain_new (context, file);
-  ide_toolchain_manager_add (self->manager, IDE_TOOLCHAIN (toolchain));
-}
 
-void
-meson_toolchain_enumerate_children_cb (GObject      *object,
-                                       GAsyncResult *result,
-                                       gpointer      user_data)
+static void
+gbp_meson_toolchain_provider_load_worker (IdeTask      *task,
+                                          gpointer      source_object,
+                                          gpointer      task_data,
+                                          GCancellable *cancellable)
 {
-  GbpMesonToolchainProvider *self = (GbpMesonToolchainProvider *)user_data;
-  GFile *dir = (GFile *)object;
-  g_autoptr(GError) error = NULL;
-  g_autoptr(GPtrArray) infos = NULL;
+  GbpMesonToolchainProvider *self = source_object;
+  g_autoptr(GPtrArray) toolchains = NULL;
+  IdeContext *context;
+  GPtrArray *files = task_data;
 
-  g_assert (G_IS_FILE (dir));
-  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
   g_assert (GBP_IS_MESON_TOOLCHAIN_PROVIDER (self));
+  g_assert (files != NULL);
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  infos = ide_g_file_get_children_finish (dir, result, &error);
+  context = ide_object_get_context (IDE_OBJECT (self));
+  toolchains = g_ptr_array_new_with_free_func (g_object_unref);
 
-  if (infos == NULL)
-    return;
-
-  for (guint i = 0; i < infos->len; i++)
+  for (guint i = 0; i < files->len; i++)
     {
-      GFileInfo *file_info = g_ptr_array_index (infos, i);
-      GFileType file_type = g_file_info_get_file_type (file_info);
-
-      if (file_type == G_FILE_TYPE_REGULAR)
+      GFile *file = g_ptr_array_index (files, i);
+      g_autoptr(GFileInfo) file_info = NULL;
+      g_autoptr(GError) file_error = NULL;
+      const gchar *content_type;
+
+      g_assert (G_IS_FILE (file));
+
+      file_info = g_file_query_info (file,
+                                     G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                                     G_FILE_QUERY_INFO_NONE,
+                                     cancellable,
+                                     &file_error);
+      content_type = g_file_info_get_content_type (file_info);
+      if (g_content_type_is_mime_type (content_type, "text/plain"))
         {
-          const gchar *content_type = g_file_info_get_content_type (file_info);
+          g_autoptr(GKeyFile) keyfile = g_key_file_new ();
+          g_autofree gchar *path = g_file_get_path (file);
+          g_autoptr(GError) keyfile_error = NULL;
 
-          if (g_content_type_is_mime_type (content_type, "text/plain"))
+          if (g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &keyfile_error))
             {
-              const gchar *name = g_file_info_get_name (file_info);
-              g_autoptr(GFile) child = g_file_get_child (dir, name);
-              g_autoptr(GKeyFile) keyfile = g_key_file_new ();
-              g_autofree gchar *path = g_file_get_path (child);
-              g_autoptr(GError) keyfile_error = NULL;
-
-              if (g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &keyfile_error))
+              if (g_key_file_has_group (keyfile, "binaries") &&
+                  (g_key_file_has_group (keyfile, "host_machine") ||
+                   g_key_file_has_group (keyfile, "target_machine")))
                 {
-                  if (g_key_file_has_group (keyfile, "binaries") &&
-                      (g_key_file_has_group (keyfile, "host_machine") ||
-                       g_key_file_has_group (keyfile, "target_machine")))
-                    meson_toolchain_provider_add_crossfile (self, child);
+                  g_autoptr(GbpMesonToolchain) toolchain = gbp_meson_toolchain_new (context, file);
+                  g_ptr_array_add (toolchains, g_steal_pointer (&toolchain));
                 }
             }
         }
-      else if (file_type == G_FILE_TYPE_DIRECTORY)
-        {
-          const gchar *name = g_file_info_get_name (file_info);
-          g_autoptr(GFile) child = g_file_get_child (dir, name);
+    }
 
-          meson_toolchain_provider_search_folder (self, child);
-        }
+  ide_task_return_pointer (task,
+                           g_steal_pointer (&toolchains),
+                           (GDestroyNotify)g_ptr_array_unref);
+}
+
+void
+meson_toolchain_provider_search_finish (FileSearching *file_searching, GError *error)
+{
+  g_autoptr(IdeTask) task = NULL;
+  g_autoptr(GPtrArray) ret = NULL;
+
+  task = file_searching->task;
+  ret = file_searching->found_files;
+  g_list_free_full (file_searching->folders, g_object_unref);
+  g_slice_free (FileSearching, file_searching);
+
+  if (error != NULL)
+    {
+      ide_task_return_error (task, error);
+      return;
     }
+
+  ide_task_set_task_data (task, g_steal_pointer (&ret), (GDestroyNotify)g_ptr_array_unref);
+  ide_task_run_in_thread (task, gbp_meson_toolchain_provider_load_worker);
 }
 
 void
-meson_toolchain_provider_search_folder (GbpMesonToolchainProvider  *self,
-                                        GFile                      *file)
+add_all_files (GFile *array, GPtrArray *dest_array)
 {
-  g_assert (GBP_IS_MESON_TOOLCHAIN_PROVIDER (self));
+  g_assert (G_IS_FILE (array));
+  g_assert (dest_array != NULL);
+  g_ptr_array_add (dest_array, g_object_ref (array));
+}
+
+void
+meson_toolchain_provider_search_iterate (GObject      *object,
+                                         GAsyncResult *result,
+                                         gpointer      user_data)
+{
+  GFile *file = (GFile *)object;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GPtrArray) ret = NULL;
+  FileSearching *file_searching = user_data;
+
   g_assert (G_IS_FILE (file));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (file_searching != NULL);
+  g_assert (IDE_IS_TASK (file_searching->task));
+
+  ret = ide_g_file_find_finish (file, result, &error);
+  IDE_PTR_ARRAY_SET_FREE_FUNC (ret, g_object_unref);
+
+  if (ret == NULL)
+    {
+      meson_toolchain_provider_search_finish (file_searching, g_steal_pointer (&error));
+      return;
+    }
 
-  ide_g_file_get_children_async (file,
-                                 G_FILE_ATTRIBUTE_STANDARD_NAME","
-                                 G_FILE_ATTRIBUTE_STANDARD_TYPE","
-                                 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
-                                 G_FILE_QUERY_INFO_NONE,
-                                 G_PRIORITY_LOW,
-                                 self->loading_cancellable,
-                                 meson_toolchain_enumerate_children_cb,
-                                 self);
+  g_ptr_array_foreach (ret, (GFunc)add_all_files, file_searching->found_files);
+  file_searching->folders = g_list_remove (file_searching->folders, file);
+  if (file_searching->folders != NULL)
+    {
+      ide_g_file_find_async (file_searching->folders->data,
+                             "*",
+                             ide_task_get_cancellable (file_searching->task),
+                             meson_toolchain_provider_search_iterate,
+                             file_searching);
+    }
+  else
+    {
+      meson_toolchain_provider_search_finish (file_searching, NULL);
+    }
 }
 
 void
-gbp_meson_toolchain_provider_load (IdeToolchainProvider  *provider,
-                                   IdeToolchainManager   *manager)
+meson_toolchain_provider_search_init (GbpMesonToolchainProvider *self,
+                                      GCancellable              *cancellable,
+                                      GAsyncReadyCallback        callback,
+                                      gpointer                   user_data)
 {
-  GbpMesonToolchainProvider *self = (GbpMesonToolchainProvider *) provider;
-  IdeContext *context;
-  const gchar * const *system_data_dirs;
+  GList *folders = NULL;
   g_autoptr(GFile) project_folder = NULL;
-  g_autoptr(GFile) user_folder = NULL;
+  g_autoptr (IdeTask) task = NULL;
   g_autofree gchar *user_folder_path = NULL;
-
-  IDE_ENTRY;
+  const gchar * const *system_data_dirs;
+  IdeContext *context;
+  FileSearching *file_searching;
 
   g_assert (GBP_IS_MESON_TOOLCHAIN_PROVIDER (self));
-  g_assert (IDE_IS_TOOLCHAIN_MANAGER (manager));
-
-  self->manager = g_object_ref (manager);
-
-  context = ide_object_get_context (IDE_OBJECT (manager));
-  g_return_if_fail (IDE_IS_CONTEXT (context));
-  if (!GBP_IS_MESON_BUILD_SYSTEM (ide_context_get_build_system (context)))
-    return;
 
-  self->loading_cancellable = g_cancellable_new ();
+  context = ide_object_get_context (IDE_OBJECT (self));
 
-  /* Starting with version 0.44.0, Meson supported embedded cross-files */
   system_data_dirs = g_get_system_data_dirs ();
   for (gint i = 0; system_data_dirs[i] != NULL; i++)
     {
       g_autofree gchar *subfolder = g_build_filename (system_data_dirs[i], "meson", "cross", NULL);
-      g_autoptr(GFile) file = g_file_new_for_path (subfolder);
 
-      meson_toolchain_provider_search_folder (self, file);
+      folders = g_list_append (folders, g_file_new_for_path (subfolder));
     }
 
   user_folder_path = g_build_filename (g_get_user_data_dir (), "meson", "cross", NULL);
-  user_folder = g_file_new_for_path (user_folder_path);
-  meson_toolchain_provider_search_folder (self, user_folder);
+  folders = g_list_append (folders, g_file_new_for_path (user_folder_path));
 
   project_folder = g_file_get_parent (ide_context_get_project_file (context));
-  meson_toolchain_provider_search_folder (self, project_folder);
+  folders = g_list_append (folders, g_steal_pointer(&project_folder));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, meson_toolchain_provider_search_init);
+  ide_task_set_priority (task, G_PRIORITY_LOW);
+
+  file_searching = g_slice_new0 (FileSearching);
+  file_searching->task = g_steal_pointer (&task);
+  file_searching->folders = folders;
+  file_searching->found_files = g_ptr_array_new ();
+  IDE_PTR_ARRAY_SET_FREE_FUNC (file_searching->found_files, g_object_unref);
+
+  /* Unfortunately there is no file extension for this */
+  ide_g_file_find_async (g_list_first (folders)->data,
+                         "*",
+                         cancellable,
+                         meson_toolchain_provider_search_iterate,
+                         file_searching);
+}
+
+static void
+gbp_meson_toolchain_provider_load_async (IdeToolchainProvider     *provider,
+                                         GCancellable             *cancellable,
+                                         GAsyncReadyCallback       callback,
+                                         gpointer                  user_data)
+{
+  GbpMesonToolchainProvider *self = (GbpMesonToolchainProvider *)provider;
+  g_autoptr(IdeTask) task = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_MESON_TOOLCHAIN_PROVIDER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  meson_toolchain_provider_search_init (self, cancellable, callback, user_data);
 
   IDE_EXIT;
 }
 
+static gboolean
+gbp_meson_toolchain_provider_load_finish (IdeToolchainProvider  *provider,
+                                          GAsyncResult          *result,
+                                          GError               **error)
+{
+  GbpMesonToolchainProvider *self = (GbpMesonToolchainProvider *)provider;
+  g_autoptr(GPtrArray) toolchains = NULL;
+
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (GBP_IS_MESON_TOOLCHAIN_PROVIDER (self));
+  g_assert (IDE_IS_TASK (result));
+  g_assert (ide_task_is_valid (IDE_TASK (result), provider));
+
+  toolchains = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+  if (toolchains == NULL)
+    return FALSE;
+
+  g_clear_pointer (&self->toolchains, g_ptr_array_unref);
+  self->toolchains = g_ptr_array_ref (toolchains);
+
+  for (guint i = 0; i < toolchains->len; i++)
+    {
+      IdeToolchain *toolchain = g_ptr_array_index (toolchains, i);
+
+      g_assert (IDE_IS_TOOLCHAIN (toolchain));
+
+      ide_toolchain_provider_emit_added (provider, toolchain);
+    }
+
+  return TRUE;
+}
+
 void
 gbp_meson_toolchain_provider_unload (IdeToolchainProvider  *provider,
                                      IdeToolchainManager   *manager)
@@ -176,13 +276,14 @@ gbp_meson_toolchain_provider_unload (IdeToolchainProvider  *provider,
   g_assert (GBP_IS_MESON_TOOLCHAIN_PROVIDER (self));
   g_assert (IDE_IS_TOOLCHAIN_MANAGER (manager));
 
-  g_clear_object (&self->manager);
+  g_clear_pointer (&self->toolchains, g_ptr_array_unref);
 }
 
 static void
 toolchain_provider_iface_init (IdeToolchainProviderInterface *iface)
 {
-  iface->load = gbp_meson_toolchain_provider_load;
+  iface->load_async = gbp_meson_toolchain_provider_load_async;
+  iface->load_finish = gbp_meson_toolchain_provider_load_finish;
   iface->unload = gbp_meson_toolchain_provider_unload;
 }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]