[gnome-builder/wip/chergert/deviced] pipeline: simplify bootstrap process



commit 90b7911c634a6bdef8409c27018a28bc95654839
Author: Christian Hergert <chergert redhat com>
Date:   Sun Mar 4 14:12:28 2018 -0800

    pipeline: simplify bootstrap process
    
    Instead of passing multiple parameters around, we just pass the pipeline
    now, for which components can get the data they're interested in.
    
    To ensure that we have arch available early, we now get the device info
    when invalidating the pipeline. This ensures that the runtime manager can
    give proper arch info to the providers (who might translate that to get
    the right flatpak runtime, etc).

 src/libide/buildsystem/ide-build-manager.c         |  93 +++++--
 src/libide/buildsystem/ide-build-pipeline.c        |  40 ++-
 src/libide/buildsystem/ide-build-private.h         |  21 +-
 src/libide/runtimes/ide-runtime-manager.c          | 286 +++++----------------
 src/libide/runtimes/ide-runtime-manager.h          |  37 +--
 src/libide/runtimes/ide-runtime-private.h          |  36 +++
 src/libide/runtimes/ide-runtime-provider.c         |  58 +++--
 src/libide/runtimes/ide-runtime-provider.h         |   6 +-
 src/plugins/flatpak/gbp-flatpak-runtime-provider.c | 146 +++--------
 9 files changed, 280 insertions(+), 443 deletions(-)
---
diff --git a/src/libide/buildsystem/ide-build-manager.c b/src/libide/buildsystem/ide-build-manager.c
index 7b3488006..1298f329e 100644
--- a/src/libide/buildsystem/ide-build-manager.c
+++ b/src/libide/buildsystem/ide-build-manager.c
@@ -37,6 +37,7 @@
 #include "diagnostics/ide-diagnostics-manager.h"
 #include "runtimes/ide-runtime.h"
 #include "runtimes/ide-runtime-manager.h"
+#include "runtimes/ide-runtime-private.h"
 
 /**
  * SECTION:ide-build-manager
@@ -323,11 +324,10 @@ ide_build_manager_ensure_runtime_cb (GObject      *object,
                                      gpointer      user_data)
 {
   IdeRuntimeManager *runtime_manager = (IdeRuntimeManager *)object;
-  g_autoptr(IdeRuntime) runtime = NULL;
-  g_autoptr(GTask) task = user_data;
   g_autoptr(GError) error = NULL;
-  IdeBuildManager *self;
+  g_autoptr(GTask) task = user_data;
   IdeBuildPipeline *pipeline;
+  IdeBuildManager *self;
   GCancellable *cancellable;
 
   IDE_ENTRY;
@@ -342,11 +342,9 @@ ide_build_manager_ensure_runtime_cb (GObject      *object,
   g_assert (IDE_IS_BUILD_MANAGER (self));
   g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
-  runtime = ide_runtime_manager_ensure_config_finish (runtime_manager, result, &error);
-
-  if (runtime == NULL)
+  if (!_ide_runtime_manager_prepare_finish (runtime_manager, result, &error))
     {
-      g_message ("Failed to locate runtime: %s", error->message);
+      g_message ("Failed to prepare runtime: %s", error->message);
       IDE_GOTO (failure);
     }
 
@@ -359,8 +357,6 @@ ide_build_manager_ensure_runtime_cb (GObject      *object,
   if (g_task_return_error_if_cancelled (task))
     IDE_GOTO (failure);
 
-  _ide_build_pipeline_set_runtime (pipeline, runtime);
-
   cancellable = g_task_get_cancellable (task);
 
   /* This will cause plugins to load on the pipeline. */
@@ -377,7 +373,7 @@ ide_build_manager_ensure_runtime_cb (GObject      *object,
 
   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PIPELINE]);
 
-  g_task_return_pointer (task, g_steal_pointer (&runtime), g_object_unref);
+  g_task_return_boolean (task, TRUE);
 
   IDE_EXIT;
 
@@ -394,12 +390,59 @@ failure:
   IDE_EXIT;
 }
 
+static void
+ide_build_manager_device_get_info_cb (GObject      *object,
+                                      GAsyncResult *result,
+                                      gpointer      user_data)
+{
+  IdeDevice *device = (IdeDevice *)object;
+  g_autoptr(IdeDeviceInfo) info = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GTask) task = user_data;
+  IdeRuntimeManager *runtime_manager;
+  IdeBuildPipeline *pipeline;
+  IdeContext *context;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_DEVICE (device));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  pipeline = g_task_get_task_data (task);
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+
+  context = ide_object_get_context (IDE_OBJECT (pipeline));
+  g_assert (IDE_IS_CONTEXT (context));
+
+  runtime_manager = ide_context_get_runtime_manager (context);
+  g_assert (IDE_IS_RUNTIME_MANAGER (runtime_manager));
+
+  if (!(info = ide_device_get_info_finish (device, result, &error)))
+    {
+      ide_context_warning (context,
+                           _("Failed to get device information: %s"),
+                           error->message);
+      g_task_return_error (task, g_steal_pointer (&task));
+      IDE_EXIT;
+    }
+
+  _ide_build_pipeline_set_device_info (pipeline, info);
+
+  _ide_runtime_manager_prepare_async (runtime_manager,
+                                      pipeline,
+                                      g_task_get_cancellable (task),
+                                      ide_build_manager_ensure_runtime_cb,
+                                      g_object_ref (task));
+
+  IDE_EXIT;
+}
+
 static void
 ide_build_manager_invalidate_pipeline (IdeBuildManager *self)
 {
-  IdeConfigurationManager *config_manager;
   g_autoptr(GTask) task = NULL;
-  IdeRuntimeManager *runtime_manager;
+  IdeConfigurationManager *config_manager;
   IdeDeviceManager *device_manager;
   IdeConfiguration *config;
   IdeContext *context;
@@ -446,7 +489,6 @@ ide_build_manager_invalidate_pipeline (IdeBuildManager *self)
 
   config_manager = ide_context_get_configuration_manager (context);
   device_manager = ide_context_get_device_manager (context);
-  runtime_manager = ide_context_get_runtime_manager (context);
 
   config = ide_configuration_manager_get_current (config_manager);
   device = ide_device_manager_get_device (device_manager);
@@ -468,23 +510,22 @@ ide_build_manager_invalidate_pipeline (IdeBuildManager *self)
   dzl_signal_group_set_target (self->pipeline_signals, self->pipeline);
 
   /*
-   * This next part of the pipeline setup is asynchronous, as we need to
-   * make sure that the pipeline's runtime is available before we setup
-   * the pipeline. That could mean that we have to install it.
-   *
-   * We setup a cancellable so that we can cancel the setup operation in
-   * case a further configuration change comes through and we need to
-   * tear down the pipeline immediately.
+   * Create a task to manage our async pipeline initialization state.
    */
   task = g_task_new (self, self->cancellable, NULL, NULL);
   g_task_set_task_data (task, g_object_ref (self->pipeline), g_object_unref);
   g_task_set_priority (task, G_PRIORITY_LOW);
-  ide_runtime_manager_ensure_config_async (runtime_manager,
-                                           config,
-                                           device,
-                                           self->cancellable,
-                                           ide_build_manager_ensure_runtime_cb,
-                                           g_steal_pointer (&task));
+
+  /*
+   * Next, we need to get information on the build device, which may require
+   * connecting to it. So we will query that information (so we can get
+   * arch/kernel/system too). We might need that when bootstrapping the
+   * runtime (if it's missing) among other things.
+   */
+  ide_device_get_info_async (device,
+                             self->cancellable,
+                             ide_build_manager_device_get_info_cb,
+                             g_steal_pointer (&task));
 
   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ERROR_COUNT]);
   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HAS_DIAGNOSTICS]);
diff --git a/src/libide/buildsystem/ide-build-pipeline.c b/src/libide/buildsystem/ide-build-pipeline.c
index 7c5eb45ae..b7f4b31c3 100644
--- a/src/libide/buildsystem/ide-build-pipeline.c
+++ b/src/libide/buildsystem/ide-build-pipeline.c
@@ -1062,6 +1062,31 @@ ide_build_pipeline_load (IdeBuildPipeline *self)
   IDE_EXIT;
 }
 
+void
+_ide_build_pipeline_set_device_info (IdeBuildPipeline *self,
+                                     IdeDeviceInfo    *info)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_BUILD_PIPELINE (self));
+  g_assert (IDE_IS_DEVICE_INFO (info));
+
+  g_clear_pointer (&self->arch, g_free);
+  g_clear_pointer (&self->kernel, g_free);
+  g_clear_pointer (&self->system, g_free);
+  g_clear_pointer (&self->system_type, g_free);
+
+  g_object_get (info,
+                "arch", &self->arch,
+                "kernel", &self->kernel,
+                "system", &self->system,
+                NULL);
+
+  self->system_type = ide_create_host_triplet (self->arch, self->kernel, self->system);
+
+  IDE_EXIT;
+}
+
 static void
 ide_build_pipeline_load_get_info_cb (GObject      *object,
                                      GAsyncResult *result,
@@ -1087,20 +1112,7 @@ ide_build_pipeline_load_get_info_cb (GObject      *object,
   if (g_cancellable_is_cancelled (self->cancellable))
     IDE_EXIT;
 
-  g_assert (self->arch == NULL);
-  g_assert (self->kernel == NULL);
-  g_assert (self->system == NULL);
-  g_assert (self->system_type == NULL);
-
-  g_object_get (info,
-                "arch", &self->arch,
-                "kernel", &self->kernel,
-                "system", &self->system,
-                NULL);
-
-  self->system_type = ide_create_host_triplet (self->arch,
-                                               self->kernel,
-                                               self->system);
+  _ide_build_pipeline_set_device_info (self, info);
 
   ide_build_pipeline_load (self);
 }
diff --git a/src/libide/buildsystem/ide-build-private.h b/src/libide/buildsystem/ide-build-private.h
index 606d7f07c..0c04833a5 100644
--- a/src/libide/buildsystem/ide-build-private.h
+++ b/src/libide/buildsystem/ide-build-private.h
@@ -21,18 +21,21 @@
 #include <vte/vte.h>
 
 #include "buildsystem/ide-build-pipeline.h"
+#include "devices/ide-device-info.h"
 #include "runtimes/ide-runtime.h"
 
 G_BEGIN_DECLS
 
-void _ide_build_pipeline_cancel       (IdeBuildPipeline *self);
-void _ide_build_pipeline_set_runtime  (IdeBuildPipeline *self,
-                                       IdeRuntime       *runtime);
-void _ide_build_pipeline_set_message  (IdeBuildPipeline *self,
-                                       const gchar      *message);
-void _ide_build_pipeline_mark_broken  (IdeBuildPipeline *self);
-void _ide_build_pipeline_set_pty_size (IdeBuildPipeline *self,
-                                       guint             rows,
-                                       guint             columns);
+void _ide_build_pipeline_cancel          (IdeBuildPipeline *self);
+void _ide_build_pipeline_set_runtime     (IdeBuildPipeline *self,
+                                          IdeRuntime       *runtime);
+void _ide_build_pipeline_set_message     (IdeBuildPipeline *self,
+                                          const gchar      *message);
+void _ide_build_pipeline_mark_broken     (IdeBuildPipeline *self);
+void _ide_build_pipeline_set_device_info (IdeBuildPipeline *pipeline,
+                                          IdeDeviceInfo    *info);
+void _ide_build_pipeline_set_pty_size    (IdeBuildPipeline *self,
+                                          guint             rows,
+                                          guint             columns);
 
 G_END_DECLS
diff --git a/src/libide/runtimes/ide-runtime-manager.c b/src/libide/runtimes/ide-runtime-manager.c
index 783397aa4..556720731 100644
--- a/src/libide/runtimes/ide-runtime-manager.c
+++ b/src/libide/runtimes/ide-runtime-manager.c
@@ -24,6 +24,7 @@
 #include "ide-context.h"
 #include "ide-debug.h"
 
+#include "buildsystem/ide-build-private.h"
 #include "config/ide-configuration.h"
 #include "devices/ide-device.h"
 #include "runtimes/ide-runtime.h"
@@ -44,6 +45,12 @@ typedef struct
   IdeRuntimeProvider *provider;
 } InstallLookup;
 
+typedef struct
+{
+  IdeBuildPipeline *pipeline;
+  gchar            *runtime_id;
+} PrepareState;
+
 static void list_model_iface_init (GListModelInterface *iface);
 static void initable_iface_init   (GInitableIface      *iface);
 
@@ -51,6 +58,14 @@ G_DEFINE_TYPE_EXTENDED (IdeRuntimeManager, ide_runtime_manager, IDE_TYPE_OBJECT,
                         G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, list_model_iface_init)
                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init))
 
+static void
+prepare_state_free (PrepareState *state)
+{
+  g_clear_object (&state->pipeline);
+  g_clear_pointer (&state->runtime_id, g_free);
+  g_slice_free (PrepareState, state);
+}
+
 static void
 ide_runtime_manager_extension_added (PeasExtensionSet *set,
                                      PeasPluginInfo   *plugin_info,
@@ -280,165 +295,9 @@ install_lookup_cb (PeasExtensionSet   *set,
 }
 
 static void
-ide_runtime_manager_install_cb (GObject      *object,
+ide_runtime_manager_prepare_cb (GObject      *object,
                                 GAsyncResult *result,
                                 gpointer      user_data)
-{
-  IdeRuntimeProvider *provider = (IdeRuntimeProvider *)object;
-  IdeRuntimeManager *self;
-  g_autoptr(GTask) task = user_data;
-  g_autoptr(GError) error = NULL;
-  IdeRuntime *runtime;
-  const gchar *runtime_id;
-
-  IDE_ENTRY;
-
-  g_assert (G_IS_ASYNC_RESULT (result));
-  g_assert (G_IS_TASK (task));
-
-  if (!ide_runtime_provider_install_finish (provider, result, &error))
-    {
-      g_task_return_error (task, g_steal_pointer (&error));
-      IDE_EXIT;
-    }
-
-  self = g_task_get_source_object (task);
-  runtime_id = g_task_get_task_data (task);
-
-  g_assert (IDE_IS_RUNTIME_MANAGER (self));
-  g_assert (runtime_id != NULL);
-
-  runtime = ide_runtime_manager_get_runtime (self, runtime_id);
-
-  if (runtime == NULL)
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_FAILED,
-                               "Runtime provider returned success but did not register runtime %s",
-                               runtime_id);
-      IDE_EXIT;
-    }
-
-  g_task_return_pointer (task, g_object_ref (runtime), g_object_unref);
-
-  IDE_EXIT;
-}
-
-/**
- * ide_runtime_manager_ensure_async:
- * @self: An #IdeRuntimeManager
- * @runtime_id: the id for an expected runtime
- * @cancellable: (nullable): a #GCancellable or %NULL
- * @callback: a callback to call after execution
- * @user_data: user data for @callback
- *
- * This function will asynchronously check if a runtime is installed.
- *
- * If it is not installed, it will check to see if any runtime provider
- * can provide the runtime by installing it. If so, the runtime will be
- * installed.
- *
- * Call ide_runtime_manager_ensure_finish() to get the resulting runtime
- * or a #GError in case of failure.
- */
-void
-ide_runtime_manager_ensure_async (IdeRuntimeManager   *self,
-                                  const gchar         *runtime_id,
-                                  GCancellable        *cancellable,
-                                  GAsyncReadyCallback  callback,
-                                  gpointer             user_data)
-{
-  g_autoptr(GTask) task = NULL;
-  InstallLookup lookup = {
-    .runtime_id = runtime_id,
-    .provider = NULL
-  };
-
-  IDE_ENTRY;
-
-  g_return_if_fail (IDE_IS_RUNTIME_MANAGER (self));
-  g_return_if_fail (runtime_id != NULL);
-  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  task = g_task_new (self, cancellable, callback, user_data);
-  g_task_set_source_tag (task, ide_runtime_manager_ensure_async);
-  g_task_set_task_data (task, g_strdup (runtime_id), g_free);
-
-  /*
-   * It would be tempting to just return early here if we could locate
-   * the runtime as already registered. But that isn't enough since we
-   * might need to also install an SDK.
-   */
-
-  peas_extension_set_foreach (self->extensions,
-                              (PeasExtensionSetForeachFunc) install_lookup_cb,
-                              &lookup);
-
-  if (lookup.provider == NULL)
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_NOT_SUPPORTED,
-                               "Failed to locate provider for runtime: %s",
-                               runtime_id);
-      IDE_EXIT;
-    }
-
-  ide_runtime_provider_install_async (lookup.provider,
-                                      runtime_id,
-                                      cancellable,
-                                      ide_runtime_manager_install_cb,
-                                      g_steal_pointer (&task));
-
-  IDE_EXIT;
-}
-
-/**
- * ide_runtime_manager_ensure_finish:
- * @self: an #IdeRuntimeManager
- * @result: a #GAsyncResult
- * @error: a location for a #GError or %NULL
- *
- * Completes an asynchronous request to ide_runtime_manager_ensure_async()
- *
- * Returns: (transfer full): An #IdeRuntime or %NULL.
- */
-IdeRuntime *
-ide_runtime_manager_ensure_finish (IdeRuntimeManager  *self,
-                                   GAsyncResult       *result,
-                                   GError            **error)
-{
-  g_autoptr(GError) local_error = NULL;
-  IdeRuntime *ret;
-
-  g_return_val_if_fail (IDE_IS_RUNTIME_MANAGER (self), NULL);
-  g_return_val_if_fail (G_IS_TASK (result), NULL);
-
-  ret = g_task_propagate_pointer (G_TASK (result), &local_error);
-
-  /*
-   * If we got NOT_SUPPORTED error, and the runtime already exists,
-   * then we can synthesize a successful result to the caller.
-   */
-  if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
-    {
-      const gchar *runtime_id = g_task_get_task_data (G_TASK (result));
-      ret = ide_runtime_manager_get_runtime (self, runtime_id);
-      if (ret != NULL)
-        return ret;
-    }
-
-  if (error != NULL)
-    *error = g_steal_pointer (&local_error);
-
-  return ret;
-}
-
-static void
-ide_runtime_manager_ensure_config_cb (GObject      *object,
-                                      GAsyncResult *result,
-                                      gpointer      user_data)
 {
   IdeRuntimeProvider *provider = (IdeRuntimeProvider *)object;
   g_autoptr(IdeRuntime) runtime = NULL;
@@ -463,52 +322,44 @@ ide_runtime_manager_ensure_config_cb (GObject      *object,
   IDE_EXIT;
 }
 
-/**
- * ide_runtime_manager_ensure_config_async:
- * @self: a #IdeRuntimeManager
- * @configuration: an #IdeConfiguration
- * @cancellable: (nullable): a #GCancellable or %NULL
- * @callback: a #GAsyncReadyCallback to execute upon completion
- * @user_data: closure data for @callback
- *
- * Ensures that the runtime or multiple runtimes that may be necessary to
- * build the configuration are installed.
- *
- * Since: 3.28
- */
 void
-ide_runtime_manager_ensure_config_async (IdeRuntimeManager   *self,
-                                         IdeConfiguration    *configuration,
-                                         IdeDevice           *device,
-                                         GCancellable        *cancellable,
-                                         GAsyncReadyCallback  callback,
-                                         gpointer             user_data)
+_ide_runtime_manager_prepare_async (IdeRuntimeManager   *self,
+                                    IdeBuildPipeline    *pipeline,
+                                    GCancellable        *cancellable,
+                                    GAsyncReadyCallback  callback,
+                                    gpointer             user_data)
 {
   g_autoptr(GTask) task = NULL;
+  IdeConfiguration *config;
+  PrepareState *state;
   const gchar *runtime_id;
   InstallLookup lookup = { 0 };
 
   IDE_ENTRY;
 
   g_return_if_fail (IDE_IS_RUNTIME_MANAGER (self));
-  g_return_if_fail (IDE_IS_CONFIGURATION (configuration));
-  g_return_if_fail (IDE_IS_DEVICE (device));
+  g_return_if_fail (IDE_IS_BUILD_PIPELINE (pipeline));
   g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  runtime_id = ide_configuration_get_runtime_id (configuration);
+  config = ide_build_pipeline_get_configuration (pipeline);
+  runtime_id = ide_configuration_get_runtime_id (config);
 
   task = g_task_new (self, cancellable, callback, user_data);
-  g_task_set_source_tag (task, ide_runtime_manager_ensure_config_async);
+  g_task_set_source_tag (task, _ide_runtime_manager_prepare_async);
   g_task_set_priority (task, G_PRIORITY_LOW);
-  g_task_set_task_data (task, g_strdup (runtime_id), g_free);
+
+  state = g_slice_new0 (PrepareState);
+  state->runtime_id = g_strdup (runtime_id);
+  state->pipeline = g_object_ref (pipeline);
+  g_task_set_task_data (task, state, (GDestroyNotify)prepare_state_free);
 
   if (runtime_id == NULL)
     {
       g_task_return_new_error (task,
                                G_IO_ERROR,
                                G_IO_ERROR_FAILED,
-                               "Configuration does not have specified runtime");
-      return;
+                               "Configuration lacks runtime specification");
+      IDE_EXIT;
     }
 
   /*
@@ -523,48 +374,36 @@ ide_runtime_manager_ensure_config_async (IdeRuntimeManager   *self,
                               &lookup);
 
   if (lookup.provider == NULL)
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_NOT_SUPPORTED,
-                               "Failed to locate provider for runtime: %s",
-                               runtime_id);
-      IDE_EXIT;
-    }
-
-  ide_runtime_provider_bootstrap_async (lookup.provider,
-                                        configuration,
-                                        device,
-                                        cancellable,
-                                        ide_runtime_manager_ensure_config_cb,
-                                        g_steal_pointer (&task));
+    g_task_return_new_error (task,
+                             G_IO_ERROR,
+                             G_IO_ERROR_NOT_SUPPORTED,
+                             "Failed to locate provider for runtime: %s",
+                             runtime_id);
+  else
+    ide_runtime_provider_bootstrap_async (lookup.provider,
+                                          pipeline,
+                                          cancellable,
+                                          ide_runtime_manager_prepare_cb,
+                                          g_steal_pointer (&task));
 
   IDE_EXIT;
 }
 
-/**
- * ide_runtime_manager_ensure_config_finish:
- * @self: a #IdeRuntimeManager
- * @result: a #GAsyncResult provided to callback
- * @error: a location for a #GError or %NULL
- *
- * Completes an asynchronous request to ide_runtime_manager_ensure_config_async().
- *
- * Returns: (transfer full): an #IdeRuntime
- *
- * Since: 3.28
- */
-IdeRuntime *
-ide_runtime_manager_ensure_config_finish (IdeRuntimeManager  *self,
-                                          GAsyncResult       *result,
-                                          GError            **error)
+gboolean
+_ide_runtime_manager_prepare_finish (IdeRuntimeManager  *self,
+                                     GAsyncResult       *result,
+                                     GError            **error)
 {
+  g_autoptr(IdeRuntime) ret = NULL;
   g_autoptr(GError) local_error = NULL;
-  IdeRuntime *ret;
+  PrepareState *state;
 
-  g_return_val_if_fail (IDE_IS_RUNTIME_MANAGER (self), NULL);
-  g_return_val_if_fail (G_IS_TASK (result), NULL);
+  IDE_ENTRY;
+
+  g_return_val_if_fail (IDE_IS_RUNTIME_MANAGER (self), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
 
+  state = g_task_get_task_data (G_TASK (result));
   ret = g_task_propagate_pointer (G_TASK (result), &local_error);
 
   /*
@@ -573,16 +412,17 @@ ide_runtime_manager_ensure_config_finish (IdeRuntimeManager  *self,
    */
   if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
     {
-      const gchar *runtime_id = g_task_get_task_data (G_TASK (result));
-      ret = ide_runtime_manager_get_runtime (self, runtime_id);
-      if (ret != NULL)
-        return ret;
+      if ((ret = ide_runtime_manager_get_runtime (self, state->runtime_id)))
+        g_clear_error (&local_error);
     }
 
   if (error != NULL)
     *error = g_steal_pointer (&local_error);
 
-  g_return_val_if_fail (!ret || IDE_IS_RUNTIME (ret), NULL);
+  g_return_val_if_fail (!ret || IDE_IS_RUNTIME (ret), FALSE);
+
+  if (IDE_IS_RUNTIME (ret))
+    _ide_build_pipeline_set_runtime (state->pipeline, ret);
 
-  return ret;
+  IDE_RETURN (ret != NULL);
 }
diff --git a/src/libide/runtimes/ide-runtime-manager.h b/src/libide/runtimes/ide-runtime-manager.h
index 650c2e13e..44c9b60cc 100644
--- a/src/libide/runtimes/ide-runtime-manager.h
+++ b/src/libide/runtimes/ide-runtime-manager.h
@@ -18,9 +18,8 @@
 
 #pragma once
 
-#include "ide-version-macros.h"
-
 #include "ide-object.h"
+#include "ide-version-macros.h"
 
 G_BEGIN_DECLS
 
@@ -28,36 +27,14 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeRuntimeManager, ide_runtime_manager, IDE, RUNTIME_MANAGER, IdeObject)
 
-void        _ide_runtime_manager_unload              (IdeRuntimeManager    *self) G_GNUC_INTERNAL;
-IDE_AVAILABLE_IN_ALL
-IdeRuntime *ide_runtime_manager_get_runtime          (IdeRuntimeManager    *self,
-                                                      const gchar          *id);
-IDE_AVAILABLE_IN_ALL
-void        ide_runtime_manager_add                  (IdeRuntimeManager    *self,
-                                                      IdeRuntime           *runtime);
 IDE_AVAILABLE_IN_ALL
-void        ide_runtime_manager_remove               (IdeRuntimeManager    *self,
-                                                      IdeRuntime           *runtime);
+IdeRuntime *ide_runtime_manager_get_runtime (IdeRuntimeManager    *self,
+                                             const gchar          *id);
 IDE_AVAILABLE_IN_ALL
-void        ide_runtime_manager_ensure_async         (IdeRuntimeManager    *self,
-                                                      const gchar          *runtime_id,
-                                                      GCancellable         *cancellable,
-                                                      GAsyncReadyCallback   callback,
-                                                      gpointer              user_data);
+void        ide_runtime_manager_add         (IdeRuntimeManager    *self,
+                                             IdeRuntime           *runtime);
 IDE_AVAILABLE_IN_ALL
-IdeRuntime *ide_runtime_manager_ensure_finish        (IdeRuntimeManager    *self,
-                                                      GAsyncResult         *result,
-                                                      GError              **error);
-IDE_AVAILABLE_IN_3_28
-void        ide_runtime_manager_ensure_config_async  (IdeRuntimeManager    *self,
-                                                      IdeConfiguration     *configuration,
-                                                      IdeDevice            *device,
-                                                      GCancellable         *cancellable,
-                                                      GAsyncReadyCallback   callback,
-                                                      gpointer              user_data);
-IDE_AVAILABLE_IN_3_28
-IdeRuntime *ide_runtime_manager_ensure_config_finish (IdeRuntimeManager    *self,
-                                                      GAsyncResult         *result,
-                                                      GError              **error);
+void        ide_runtime_manager_remove      (IdeRuntimeManager    *self,
+                                             IdeRuntime           *runtime);
 
 G_END_DECLS
diff --git a/src/libide/runtimes/ide-runtime-private.h b/src/libide/runtimes/ide-runtime-private.h
new file mode 100644
index 000000000..f6e38044e
--- /dev/null
+++ b/src/libide/runtimes/ide-runtime-private.h
@@ -0,0 +1,36 @@
+/* ide-runtime-private.h
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "buildsystem/ide-build-pipeline.h"
+#include "runtimes/ide-runtime-manager.h"
+
+G_BEGIN_DECLS
+
+void     _ide_runtime_manager_unload         (IdeRuntimeManager    *self);
+void     _ide_runtime_manager_prepare_async  (IdeRuntimeManager    *self,
+                                              IdeBuildPipeline     *pipeline,
+                                              GCancellable         *cancellable,
+                                              GAsyncReadyCallback   callback,
+                                              gpointer              user_data);
+gboolean _ide_runtime_manager_prepare_finish (IdeRuntimeManager    *self,
+                                              GAsyncResult         *result,
+                                              GError              **error);
+
+G_END_DECLS
diff --git a/src/libide/runtimes/ide-runtime-provider.c b/src/libide/runtimes/ide-runtime-provider.c
index f23856f19..c87bafc36 100644
--- a/src/libide/runtimes/ide-runtime-provider.c
+++ b/src/libide/runtimes/ide-runtime-provider.c
@@ -19,9 +19,10 @@
 #define G_LOG_DOMAIN "ide-runtime-provider"
 
 #include "ide-context.h"
+#include "ide-debug.h"
 
+#include "buildsystem/ide-build-pipeline.h"
 #include "config/ide-configuration.h"
-#include "devices/ide-device.h"
 #include "runtimes/ide-runtime.h"
 #include "runtimes/ide-runtime-manager.h"
 #include "runtimes/ide-runtime-provider.h"
@@ -110,41 +111,42 @@ ide_runtime_provider_real_bootstrap_cb (GObject      *object,
 
 void
 ide_runtime_provider_real_bootstrap_async (IdeRuntimeProvider  *self,
-                                           IdeConfiguration    *configuration,
-                                           IdeDevice           *device,
+                                           IdeBuildPipeline    *pipeline,
                                            GCancellable        *cancellable,
                                            GAsyncReadyCallback  callback,
                                            gpointer             user_data)
 {
   g_autoptr(GTask) task = NULL;
+  IdeConfiguration *config;
   const gchar *runtime_id;
 
+  IDE_ENTRY;
+
   g_assert (IDE_IS_RUNTIME_PROVIDER (self));
-  g_assert (IDE_IS_CONFIGURATION (configuration));
-  g_assert (IDE_IS_DEVICE (device));
-  g_assert (!cancellable || IDE_IS_CONFIGURATION (configuration));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
   task = g_task_new (self, cancellable, callback, user_data);
   g_task_set_source_tag (task, ide_runtime_provider_real_bootstrap_async);
   g_task_set_priority (task, G_PRIORITY_LOW);
 
-  runtime_id = ide_configuration_get_runtime_id (configuration);
+  config = ide_build_pipeline_get_configuration (pipeline);
+  runtime_id = ide_configuration_get_runtime_id (config);
   g_task_set_task_data (task, g_strdup (runtime_id), g_free);
 
   if (runtime_id == NULL)
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_FAILED,
-                               "No runtime provided to install");
-      return;
-    }
+    g_task_return_new_error (task,
+                             G_IO_ERROR,
+                             G_IO_ERROR_FAILED,
+                             "No runtime provided to install");
+  else
+    ide_runtime_provider_install_async (self,
+                                        runtime_id,
+                                        cancellable,
+                                        ide_runtime_provider_real_bootstrap_cb,
+                                        g_steal_pointer (&task));
 
-  ide_runtime_provider_install_async (self,
-                                      runtime_id,
-                                      cancellable,
-                                      ide_runtime_provider_real_bootstrap_cb,
-                                      g_steal_pointer (&task));
+  IDE_EXIT;
 }
 
 IdeRuntime *
@@ -227,15 +229,16 @@ ide_runtime_provider_install_finish (IdeRuntimeProvider  *self,
 /**
  * ide_runtime_provider_bootstrap_async:
  * @self: a #IdeRuntimeProvider
- * @configuration: an #IdeConfiguration
- * @device: an #IdeDevice
+ * @pipeline: an #IdeBuildPipeline
  * @cancellable: (nullable): a #GCancellable or %NULL
  * @callback: a #GAsyncReadyCallback or %NULL
  * @user_data: closure data for @callback
  *
  * This function allows to the runtime provider to install dependent runtimes
  * similar to ide_runtime_provider_install_async(), but with the added benefit
- * that it can access the configuration for additional information.
+ * that it can access the pipeline for more information. For example, it may
+ * want to check the architecture of the pipeline, or the connected device for
+ * tweaks as to what runtime to use.
  *
  * Some runtime providers like Flatpak might use this to locate SDK extensions
  * and install those too.
@@ -246,18 +249,16 @@ ide_runtime_provider_install_finish (IdeRuntimeProvider  *self,
  */
 void
 ide_runtime_provider_bootstrap_async (IdeRuntimeProvider  *self,
-                                      IdeConfiguration    *configuration,
-                                      IdeDevice           *device,
+                                      IdeBuildPipeline    *pipeline,
                                       GCancellable        *cancellable,
                                       GAsyncReadyCallback  callback,
                                       gpointer             user_data)
 {
   g_return_if_fail (IDE_IS_RUNTIME_PROVIDER (self));
-  g_return_if_fail (IDE_IS_CONFIGURATION (configuration));
-  g_return_if_fail (IDE_IS_DEVICE (device));
+  g_return_if_fail (IDE_IS_BUILD_PIPELINE (pipeline));
   g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  IDE_RUNTIME_PROVIDER_GET_IFACE (self)->bootstrap_async (self, configuration, device, cancellable, 
callback, user_data);
+  IDE_RUNTIME_PROVIDER_GET_IFACE (self)->bootstrap_async (self, pipeline, cancellable, callback, user_data);
 }
 
 /**
@@ -268,6 +269,9 @@ ide_runtime_provider_bootstrap_async (IdeRuntimeProvider  *self,
  *
  * Completes the asynchronous request to bootstrap.
  *
+ * The resulting runtime will be set as the runtime to use for the build
+ * pipeline.
+ *
  * Returns: (transfer full): an #IdeRuntime if successful; otherwise %NULL
  *   and @error is set.
  *
diff --git a/src/libide/runtimes/ide-runtime-provider.h b/src/libide/runtimes/ide-runtime-provider.h
index c14a1e24f..75877f68c 100644
--- a/src/libide/runtimes/ide-runtime-provider.h
+++ b/src/libide/runtimes/ide-runtime-provider.h
@@ -49,8 +49,7 @@ struct _IdeRuntimeProviderInterface
                                    GAsyncResult         *result,
                                    GError              **error);
   void        (*bootstrap_async)  (IdeRuntimeProvider   *self,
-                                   IdeConfiguration     *configuration,
-                                   IdeDevice            *device,
+                                   IdeBuildPipeline     *pipeline,
                                    GCancellable         *cancellable,
                                    GAsyncReadyCallback   callback,
                                    gpointer              user_data);
@@ -80,8 +79,7 @@ gboolean    ide_runtime_provider_install_finish   (IdeRuntimeProvider   *self,
                                                    GError              **error);
 IDE_AVAILABLE_IN_3_28
 void        ide_runtime_provider_bootstrap_async  (IdeRuntimeProvider   *self,
-                                                   IdeConfiguration     *configuration,
-                                                   IdeDevice            *device,
+                                                   IdeBuildPipeline     *pipeline,
                                                    GCancellable         *cancellable,
                                                    GAsyncReadyCallback   callback,
                                                    gpointer              user_data);
diff --git a/src/plugins/flatpak/gbp-flatpak-runtime-provider.c 
b/src/plugins/flatpak/gbp-flatpak-runtime-provider.c
index cc28ca53a..5217d7e01 100644
--- a/src/plugins/flatpak/gbp-flatpak-runtime-provider.c
+++ b/src/plugins/flatpak/gbp-flatpak-runtime-provider.c
@@ -46,8 +46,6 @@ typedef struct
 typedef struct
 {
   IdeConfiguration *config;
-  IdeDevice        *device;
-  IdeDeviceInfo    *info;
   gchar            *runtime_id;
   gchar            *name;
   gchar            *arch;
@@ -79,8 +77,6 @@ bootstrap_state_free (gpointer data)
   g_assert (state != NULL);
 
   g_clear_object (&state->config);
-  g_clear_object (&state->device);
-  g_clear_object (&state->info);
   g_clear_pointer (&state->runtime_id, g_free);
   g_clear_pointer (&state->name, g_free);
   g_clear_pointer (&state->arch, g_free);
@@ -577,13 +573,9 @@ gbp_flatpak_runtime_provider_bootstrap_cb (GObject      *object,
     {
       g_autofree gchar *runtime_id = NULL;
       IdeRuntimeManager *runtime_manager;
-      const gchar *arch;
       IdeContext *context;
       IdeRuntime *runtime;
 
-      if (!(arch = ide_device_info_get_arch (state->info)))
-        arch = state->arch;
-
       runtime_id = g_strdup_printf ("flatpak:%s/%s/%s",
                                     state->name,
                                     state->arch,
@@ -604,58 +596,55 @@ gbp_flatpak_runtime_provider_bootstrap_cb (GObject      *object,
 }
 
 static void
-bootstrap_get_info_cb (GObject      *object,
-                       GAsyncResult *result,
-                       gpointer      user_data)
+gbp_flatpak_runtime_provider_bootstrap_async (IdeRuntimeProvider  *provider,
+                                              IdeBuildPipeline    *pipeline,
+                                              GCancellable        *cancellable,
+                                              GAsyncReadyCallback  callback,
+                                              gpointer             user_data)
 {
-  IdeDevice *device = (IdeDevice *)object;
-  g_autoptr(IdeDeviceInfo) info = NULL;
-  g_autoptr(GError) error = NULL;
-  g_autoptr(GTask) task = user_data;
-  GbpFlatpakRuntimeProvider *self;
+  GbpFlatpakRuntimeProvider *self = (GbpFlatpakRuntimeProvider *)provider;
+  g_autofree gchar *name = NULL;
+  g_autofree gchar *arch = NULL;
+  g_autofree gchar *branch = NULL;
+  g_autoptr(GTask) task = NULL;
+  IdeConfiguration *config;
   BootstrapState *state;
-  GCancellable *cancellable;
-  const gchar *arch;
+  const gchar *runtime_id;
+  const gchar *build_arch;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_MAIN_THREAD ());
-  g_assert (IDE_DEVICE (device));
-  g_assert (G_IS_ASYNC_RESULT (result));
-  g_assert (G_IS_TASK (task));
-
-  cancellable = g_task_get_cancellable (task);
-  state = g_task_get_task_data (task);
-  self = g_task_get_source_object (task);
-
   g_assert (GBP_IS_FLATPAK_RUNTIME_PROVIDER (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-  g_assert (state != NULL);
-  g_assert (IDE_IS_DEVICE (state->device));
-  g_assert (IDE_IS_CONFIGURATION (state->config));
-
-  if (!(info = ide_device_get_info_finish (device, result, &error)))
-    {
-      g_task_return_error (task, g_steal_pointer (&error));
-      IDE_EXIT;
-    }
 
-  g_set_object (&state->info, info);
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, gbp_flatpak_runtime_provider_bootstrap_async);
+  g_task_set_priority (task, G_PRIORITY_LOW);
 
-  arch = ide_device_info_get_arch (info);
+  build_arch = ide_build_pipeline_get_arch (pipeline);
+  config = ide_build_pipeline_get_configuration (pipeline);
+  runtime_id = ide_configuration_get_runtime_id (config);
 
-  if (arch != NULL)
+  if (runtime_id == NULL ||
+      !g_str_has_prefix (runtime_id, "flatpak:") ||
+      !gbp_flatpak_split_id (runtime_id + strlen ("flatpak:"), &name, &arch, &branch))
     {
-      g_free (state->arch);
-      g_free (state->runtime_id);
-
-      state->arch = g_strdup (arch);
-      state->runtime_id = g_strdup_printf ("flatpak:%s/%s/%s",
-                                           state->name,
-                                           state->arch,
-                                           state->branch);
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_NOT_FOUND,
+                               "No runtime available");
+      IDE_EXIT;
     }
 
+  state = g_slice_new0 (BootstrapState);
+  state->config = g_object_ref (config);
+  state->runtime_id = g_strdup_printf ("flatpak:%s/%s/%s", name, build_arch, branch);
+  state->name = g_steal_pointer (&name);
+  state->branch = g_steal_pointer (&branch);
+  state->arch = g_strdup (build_arch);
+  g_task_set_task_data (task, state, bootstrap_state_free);
+
   if (GBP_IS_FLATPAK_MANIFEST (state->config))
     {
       g_autofree gchar *platform_id = NULL;
@@ -707,69 +696,6 @@ bootstrap_get_info_cb (GObject      *object,
   IDE_EXIT;
 }
 
-static void
-gbp_flatpak_runtime_provider_bootstrap_async (IdeRuntimeProvider  *provider,
-                                              IdeConfiguration    *configuration,
-                                              IdeDevice           *device,
-                                              GCancellable        *cancellable,
-                                              GAsyncReadyCallback  callback,
-                                              gpointer             user_data)
-{
-  GbpFlatpakRuntimeProvider *self = (GbpFlatpakRuntimeProvider *)provider;
-  g_autofree gchar *name = NULL;
-  g_autofree gchar *arch = NULL;
-  g_autofree gchar *branch = NULL;
-  g_autoptr(GTask) task = NULL;
-  BootstrapState *state;
-  const gchar *runtime_id;
-
-  IDE_ENTRY;
-
-  g_assert (GBP_IS_FLATPAK_RUNTIME_PROVIDER (self));
-  g_assert (IDE_IS_CONFIGURATION (configuration));
-  g_assert (IDE_IS_DEVICE (device));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  runtime_id = ide_configuration_get_runtime_id (configuration);
-
-  task = g_task_new (self, cancellable, callback, user_data);
-  g_task_set_source_tag (task, gbp_flatpak_runtime_provider_bootstrap_async);
-  g_task_set_priority (task, G_PRIORITY_LOW);
-
-  if (runtime_id == NULL ||
-      !g_str_has_prefix (runtime_id, "flatpak:") ||
-      !gbp_flatpak_split_id (runtime_id + strlen ("flatpak:"), &name, &arch, &branch))
-    {
-      g_task_return_new_error (task,
-                               G_IO_ERROR,
-                               G_IO_ERROR_NOT_FOUND,
-                               "No runtime available");
-      IDE_EXIT;
-    }
-
-  state = g_slice_new0 (BootstrapState);
-  state->config = g_object_ref (configuration);
-  state->device = g_object_ref (device);
-  state->runtime_id = g_strdup (runtime_id);
-  state->name = g_steal_pointer (&name);
-  state->branch = g_steal_pointer (&branch);
-  state->arch = g_steal_pointer (&arch);
-  g_task_set_task_data (task, state, bootstrap_state_free);
-
-  /*
-   * First thing we need to do is connect to the device and get information
-   * about what sort of system it is. We might need to alter architecture
-   * we're building for.
-   */
-
-  ide_device_get_info_async (device,
-                             cancellable,
-                             bootstrap_get_info_cb,
-                             g_steal_pointer (&task));
-
-  IDE_EXIT;
-}
-
 static IdeRuntime *
 gbp_flatpak_runtime_provider_bootstrap_finish (IdeRuntimeProvider  *provider,
                                                GAsyncResult        *result,



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