[gnome-builder/wip/gtk4-port] libide/foundry: cleanup run_async implementation



commit f303e3641578f3709cc8d2022d30e397e03d05a1
Author: Christian Hergert <chergert redhat com>
Date:   Fri Jun 17 16:52:04 2022 -0700

    libide/foundry: cleanup run_async implementation
    
    We can clean a lot of this up by using run/finish pairs internally now that
    we can rely on device-manager to do deploy-strategy for us and what not.
    
    We still need to remove IdeRunner use, but this at least gets things into
    shape where that is a lot easier to do.
    
    We also start tracking the IdeRunCommand as part of the process even if we
    are not using it yet.

 src/libide/foundry/ide-run-manager.c | 627 +++++++++++++++++------------------
 1 file changed, 303 insertions(+), 324 deletions(-)
---
diff --git a/src/libide/foundry/ide-run-manager.c b/src/libide/foundry/ide-run-manager.c
index f009d8dac..921a2c15c 100644
--- a/src/libide/foundry/ide-run-manager.c
+++ b/src/libide/foundry/ide-run-manager.c
@@ -41,6 +41,7 @@
 #include "ide-build-target.h"
 #include "ide-config-manager.h"
 #include "ide-config.h"
+#include "ide-deploy-strategy.h"
 #include "ide-device-manager.h"
 #include "ide-foundry-compat.h"
 #include "ide-run-command.h"
@@ -63,6 +64,7 @@ struct _IdeRunManager
   GList                   *handlers;
 
   IdeRunner               *current_runner;
+  IdeRunCommand           *current_run_command;
 
   /* Keep track of last change sequence from the file monitor
    * so that we can maybe skip past install phase and make
@@ -71,17 +73,12 @@ struct _IdeRunManager
   guint64                  last_change_seq;
   guint64                  pending_last_change_seq;
 
-  /* The id of the default run command to execute or NULL if we should
-   * discover it each time we try to run.
-   *
-   * TODO: We probably need a way to determine if an install is required
-   *       to run a particular command, as for some that may not be necessary
-   *       (like running tests).
-   */
   char                    *default_run_command;
 
-  guint                    busy : 1;
+  guint                    busy;
+
   guint                    messages_debug_all : 1;
+  guint                    has_installed_once : 1;
 };
 
 typedef struct
@@ -268,6 +265,63 @@ ide_run_handler_info_free (gpointer data)
   g_slice_free (IdeRunHandlerInfo, info);
 }
 
+static void
+ide_run_manager_update_action_enabled (IdeRunManager *self)
+{
+  IdeBuildManager *build_manager;
+  IdeContext *context;
+  gboolean can_build;
+
+  g_assert (IDE_IS_RUN_MANAGER (self));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  build_manager = ide_build_manager_from_context (context);
+  can_build = ide_build_manager_get_can_build (build_manager);
+
+  ide_run_manager_set_action_enabled (self, "run",
+                                      self->busy == 0 && can_build == TRUE);
+  ide_run_manager_set_action_enabled (self, "run-with-handler",
+                                      self->busy == 0 && can_build == TRUE);
+  ide_run_manager_set_action_enabled (self, "stop", self->busy > 0);
+}
+
+
+static void
+ide_run_manager_mark_busy (IdeRunManager *self)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_RUN_MANAGER (self));
+
+  self->busy++;
+
+  if (self->busy == 1)
+    {
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BUSY]);
+      ide_run_manager_update_action_enabled (self);
+    }
+
+  IDE_EXIT;
+}
+
+static void
+ide_run_manager_unmark_busy (IdeRunManager *self)
+{
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_RUN_MANAGER (self));
+
+  self->busy--;
+
+  if (self->busy == 0)
+    {
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BUSY]);
+      ide_run_manager_update_action_enabled (self);
+    }
+
+  IDE_EXIT;
+}
+
 static void
 ide_run_manager_dispose (GObject *object)
 {
@@ -280,6 +334,9 @@ ide_run_manager_dispose (GObject *object)
   g_clear_object (&self->cancellable);
   ide_clear_and_destroy_object (&self->build_target);
 
+  g_clear_object (&self->current_run_command);
+  g_clear_object (&self->current_runner);
+
   ide_clear_and_destroy_object (&self->run_command_providers);
 
   g_list_free_full (self->handlers, ide_run_handler_info_free);
@@ -288,26 +345,6 @@ ide_run_manager_dispose (GObject *object)
   G_OBJECT_CLASS (ide_run_manager_parent_class)->dispose (object);
 }
 
-static void
-ide_run_manager_update_action_enabled (IdeRunManager *self)
-{
-  IdeBuildManager *build_manager;
-  IdeContext *context;
-  gboolean can_build;
-
-  g_assert (IDE_IS_RUN_MANAGER (self));
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-  build_manager = ide_build_manager_from_context (context);
-  can_build = ide_build_manager_get_can_build (build_manager);
-
-  ide_run_manager_set_action_enabled (self, "run",
-                                      self->busy == FALSE && can_build == TRUE);
-  ide_run_manager_set_action_enabled (self, "run-with-handler",
-                                      self->busy == FALSE && can_build == TRUE);
-  ide_run_manager_set_action_enabled (self, "stop", self->busy == TRUE);
-}
-
 static void
 ide_run_manager_notify_can_build (IdeRunManager   *self,
                                   GParamSpec      *pspec,
@@ -491,7 +528,7 @@ ide_run_manager_get_busy (IdeRunManager *self)
 {
   g_return_val_if_fail (IDE_IS_RUN_MANAGER (self), FALSE);
 
-  return self->busy;
+  return self->busy > 0;
 }
 
 static gboolean
@@ -514,43 +551,6 @@ ide_run_manager_check_busy (IdeRunManager  *self,
   return FALSE;
 }
 
-static void
-ide_run_manager_run_cb (GObject      *object,
-                        GAsyncResult *result,
-                        gpointer      user_data)
-{
-  IdeRunner *runner = (IdeRunner *)object;
-  g_autoptr(IdeTask) task = user_data;
-  g_autoptr(GError) error = NULL;
-  IdeRunManager *self;
-
-  IDE_ENTRY;
-
-  g_assert (IDE_IS_RUNNER (runner));
-  g_assert (IDE_IS_TASK (task));
-
-  self = ide_task_get_source_object (task);
-
-  if (self->notif != NULL)
-    {
-      ide_notification_withdraw (self->notif);
-      g_clear_object (&self->notif);
-    }
-
-  g_clear_object (&self->current_runner);
-
-  if (!ide_runner_run_finish (runner, result, &error))
-    ide_task_return_error (task, g_steal_pointer (&error));
-  else
-    ide_task_return_boolean (task, TRUE);
-
-  g_signal_emit (self, signals [STOPPED], 0);
-
-  ide_object_destroy (IDE_OBJECT (runner));
-
-  IDE_EXIT;
-}
-
 static void
 copy_builtin_envvars (IdeEnvironment *environment)
 {
@@ -690,74 +690,160 @@ get_action_state_bool (IdeRunManager *self,
 }
 
 static void
-create_runner_cb (GObject      *object,
-                  GAsyncResult *result,
-                  gpointer      user_data)
+ide_run_manager_install_cb (GObject      *object,
+                            GAsyncResult *result,
+                            gpointer      user_data)
 {
-  IdeRunManager *self;
-  IdeDeviceManager *device_manager = (IDE_DEVICE_MANAGER (object));
+  IdeBuildManager *build_manager = (IdeBuildManager *)object;
   g_autoptr(IdeTask) task = user_data;
   g_autoptr(GError) error = NULL;
-  g_autofree gchar *name = NULL;
-  g_autofree gchar *title = NULL;
-  IdeBuildTarget *build_target;
-  IdeContext *context;
-  IdeConfigManager *config_manager;
-  IdeConfig *config;
-  IdeEnvironment *environment;
-  IdeRuntime *runtime;
-  g_autoptr(IdeRunner) runner = NULL;
-  GCancellable *cancellable;
-  const char *color_scheme;
-  const char *run_opts;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_DEVICE_MANAGER (device_manager));
+  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
   g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (IDE_IS_TASK (task));
 
-  self = ide_task_get_source_object (task);
+  if (!ide_build_manager_build_finish (build_manager, result, &error))
+    ide_task_return_error (task, g_steal_pointer (&error));
+  else
+    ide_task_return_boolean (task, TRUE);
+
+  IDE_EXIT;
+}
+
+static void
+ide_run_manager_install_async (IdeRunManager       *self,
+                               GCancellable        *cancellable,
+                               GAsyncReadyCallback  callback,
+                               gpointer             user_data)
+{
+  g_autoptr(IdeContext) context = NULL;
+  g_autoptr(GSettings) project_settings = NULL;
+  g_autoptr(IdeTask) task = NULL;
+  IdeBuildManager *build_manager;
+  IdeVcsMonitor *monitor;
+  guint64 sequence = 0;
+
+  IDE_ENTRY;
+
   g_assert (IDE_IS_RUN_MANAGER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  runner = ide_device_manager_create_runner_finish (device_manager, result, &error);
+  context = ide_object_ref_context (IDE_OBJECT (self));
 
-  if (error != NULL)
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, ide_run_manager_install_async);
+
+  project_settings = ide_context_ref_project_settings (context);
+  if (!g_settings_get_boolean (project_settings, "install-before-run"))
     {
-      ide_task_return_error (task, g_steal_pointer (&error));
+      ide_task_return_boolean (task, TRUE);
       IDE_EXIT;
     }
 
-  build_target = ide_task_get_task_data (task);
-  context = ide_object_get_context (IDE_OBJECT (self));
+  monitor = ide_vcs_monitor_from_context (context);
+  if (monitor != NULL)
+    sequence = ide_vcs_monitor_get_sequence (monitor);
 
-  g_assert (IDE_IS_BUILD_TARGET (build_target));
-  g_assert (IDE_IS_CONTEXT (context));
+  if (self->has_installed_once && sequence == self->last_change_seq)
+    {
+      ide_task_return_boolean (task, TRUE);
+      IDE_EXIT;
+    }
 
-  config_manager = ide_config_manager_from_context (context);
-  config = ide_config_manager_get_current (config_manager);
-  runtime = ide_config_get_runtime (config);
+  self->pending_last_change_seq = sequence;
 
-  if (runner == NULL)
-    {
-      if (runtime == NULL)
-        {
-          ide_task_return_new_error (task,
-                                     IDE_RUNTIME_ERROR,
-                                     IDE_RUNTIME_ERROR_NO_SUCH_RUNTIME,
-                                     "%s “%s”",
-                                     _("Failed to locate runtime"),
-                                     ide_config_get_runtime_id (config));
-          IDE_EXIT;
-        }
+  build_manager = ide_build_manager_from_context (context);
+  ide_build_manager_build_async (build_manager,
+                                 IDE_PIPELINE_PHASE_INSTALL,
+                                 NULL,
+                                 cancellable,
+                                 ide_run_manager_install_cb,
+                                 g_steal_pointer (&task));
+
+  IDE_EXIT;
+}
+
+static gboolean
+ide_run_manager_install_finish (IdeRunManager  *self,
+                                GAsyncResult   *result,
+                                GError        **error)
+{
+  gboolean ret;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_RUN_MANAGER (self));
+  g_assert (IDE_IS_TASK (result));
 
-      runner = ide_runtime_create_runner (runtime, build_target);
+  ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
+
+static void
+ide_run_manager_run_runner_run_cb (GObject      *object,
+                                   GAsyncResult *result,
+                                   gpointer      user_data)
+{
+  IdeRunner *runner = (IdeRunner *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  IdeRunManager *self;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_RUNNER (runner));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  self = ide_task_get_source_object (task);
+
+  g_assert (IDE_IS_RUN_MANAGER (self));
+
+  if (self->notif != NULL)
+    {
+      ide_notification_withdraw (self->notif);
+      g_clear_object (&self->notif);
     }
 
-  cancellable = ide_task_get_cancellable (task);
+  g_clear_object (&self->current_runner);
+
+  if (!ide_runner_run_finish (runner, result, &error))
+    ide_task_return_error (task, g_steal_pointer (&error));
+  else
+    ide_task_return_boolean (task, TRUE);
+
+  g_signal_emit (self, signals[STOPPED], 0);
+
+  ide_object_destroy (IDE_OBJECT (runner));
 
+  IDE_EXIT;
+}
+
+static gboolean
+ide_run_manager_prepare_runner (IdeRunManager  *self,
+                                IdeRunner      *runner,
+                                GError        **error)
+{
+  g_autofree char *title = NULL;
+  IdeConfigManager *config_manager;
+  IdeEnvironment *environment;
+  IdeContext *context;
+  const char *color_scheme;
+  const char *run_opts;
+  const char *name;
+  IdeConfig *config;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_RUN_MANAGER (self));
   g_assert (IDE_IS_RUNNER (runner));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  config_manager = ide_config_manager_from_context (context);
+  config = ide_config_manager_get_current (config_manager);
 
   /* Add our run arguments if specified in the config. */
   if (NULL != (run_opts = ide_config_get_run_opts (config)))
@@ -787,11 +873,11 @@ create_runner_cb (GObject      *object,
 
   if (ide_runner_get_failed (runner))
     {
-      ide_task_return_new_error (task,
-                                 IDE_RUNTIME_ERROR,
-                                 IDE_RUNTIME_ERROR_SPAWN_FAILED,
-                                 "Failed to execute the application");
-      IDE_EXIT;
+      g_set_error (error,
+                   IDE_RUNTIME_ERROR,
+                   IDE_RUNTIME_ERROR_SPAWN_FAILED,
+                   "Failed to execute the application");
+      IDE_RETURN (FALSE);
     }
 
   if (self->notif != NULL)
@@ -801,7 +887,7 @@ create_runner_cb (GObject      *object,
     }
 
   self->notif = ide_notification_new ();
-  name = ide_build_target_get_name (build_target);
+  name = ide_run_command_get_display_name (self->current_run_command);
   /* translators: %s is replaced with the name of the users executable */
   title = g_strdup_printf (_("Running %s…"), name);
   ide_notification_set_title (self->notif, title);
@@ -809,278 +895,148 @@ create_runner_cb (GObject      *object,
 
   g_set_object (&self->current_runner, runner);
 
-  ide_runner_run_async (runner,
-                        cancellable,
-                        ide_run_manager_run_cb,
-                        g_object_ref (task));
-
-  IDE_EXIT;
+  IDE_RETURN (TRUE);
 }
 
 static void
-deploy_cb (GObject      *object,
-           GAsyncResult *result,
-           gpointer      user_data)
+ide_run_manager_run_create_runner_cb (GObject      *object,
+                                      GAsyncResult *result,
+                                      gpointer      user_data)
 {
   IdeDeviceManager *device_manager = (IdeDeviceManager *)object;
-  IdeBuildManager *build_manager;
-  IdeContext *context;
-  IdePipeline *pipeline;
-  IdeRunManager *self;
+  g_autoptr(IdeRunner) runner = NULL;
   g_autoptr(IdeTask) task = user_data;
   g_autoptr(GError) error = NULL;
+  IdeRunManager *self;
 
   IDE_ENTRY;
 
+  g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_DEVICE_MANAGER (device_manager));
+  g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (IDE_IS_TASK (task));
 
-  if (!ide_device_manager_deploy_finish (device_manager, result, &error))
+  self = ide_task_get_source_object (task);
+
+  g_assert (IDE_IS_RUN_MANAGER (self));
+
+  if (!(runner = ide_device_manager_create_runner_finish (device_manager, result, &error)) ||
+      !ide_run_manager_prepare_runner (self, runner, &error))
     {
       ide_task_return_error (task, g_steal_pointer (&error));
       IDE_EXIT;
     }
 
-  self = ide_task_get_source_object (task);
-  g_assert (IDE_IS_RUN_MANAGER (self));
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-  g_assert (IDE_IS_CONTEXT (context));
-
-  build_manager = ide_build_manager_from_context (context);
-  pipeline = ide_build_manager_get_pipeline (build_manager);
-
-  ide_device_manager_create_runner_async (device_manager,
-                                          pipeline,
-                                          ide_task_get_cancellable (task),
-                                          create_runner_cb,
-                                          g_object_ref (task));
+  ide_runner_run_async (runner,
+                        ide_task_get_cancellable (task),
+                        ide_run_manager_run_runner_run_cb,
+                        g_object_ref (task));
 
   IDE_EXIT;
 }
 
 static void
-do_run_async (IdeRunManager *self,
-              IdeTask       *task)
+ide_run_manager_run_deploy_cb (GObject      *object,
+                               GAsyncResult *result,
+                               gpointer      user_data)
 {
-  IdeBuildManager *build_manager;
-  IdeContext *context;
-  IdeDeviceManager *device_manager;
+  IdeDeviceManager *device_manager = (IdeDeviceManager *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
   IdePipeline *pipeline;
-  GCancellable *cancellable;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_RUN_MANAGER (self));
+  g_assert (IDE_IS_MAIN_THREAD ());
+  g_assert (IDE_IS_DEVICE_MANAGER (device_manager));
+  g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (IDE_IS_TASK (task));
 
-  context = ide_object_get_context (IDE_OBJECT (self));
-  g_assert (IDE_IS_CONTEXT (context));
-
-  build_manager = ide_build_manager_from_context (context);
-  pipeline = ide_build_manager_get_pipeline (build_manager);
-  device_manager = ide_device_manager_from_context (context);
+  pipeline = ide_task_get_task_data (task);
 
-  cancellable = ide_task_get_cancellable (task);
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_assert (IDE_IS_PIPELINE (pipeline));
 
-  ide_device_manager_deploy_async (device_manager,
-                                   pipeline,
-                                   cancellable,
-                                   deploy_cb,
-                                   g_object_ref (task));
+  if (!ide_device_manager_deploy_finish (device_manager, result, &error))
+    ide_task_return_error (task, g_steal_pointer (&error));
+  else
+    ide_device_manager_create_runner_async (device_manager,
+                                            pipeline,
+                                            ide_task_get_cancellable (task),
+                                            ide_run_manager_run_create_runner_cb,
+                                            g_object_ref (task));
 
   IDE_EXIT;
 }
 
 static void
-ide_run_manager_run_discover_cb (GObject      *object,
-                                 GAsyncResult *result,
-                                 gpointer      user_data)
+ide_run_manager_run_discover_run_command_cb (GObject      *object,
+                                             GAsyncResult *result,
+                                             gpointer      user_data)
 {
   IdeRunManager *self = (IdeRunManager *)object;
-  g_autoptr(IdeBuildTarget) build_target = NULL;
+  g_autoptr(IdeRunCommand) run_command = NULL;
   g_autoptr(IdeTask) task = user_data;
   g_autoptr(GError) error = NULL;
+  IdeDeviceManager *device_manager;
+  IdePipeline *pipeline;
+  IdeContext *context;
 
   IDE_ENTRY;
 
+  g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_RUN_MANAGER (self));
   g_assert (G_IS_ASYNC_RESULT (result));
-
-  build_target = ide_run_manager_discover_default_target_finish (self, result, &error);
-
-  if (build_target == NULL)
-    {
-      ide_task_return_error (task, g_steal_pointer (&error));
-      IDE_EXIT;
-    }
-
-  ide_run_manager_set_build_target (self, build_target);
-
-  ide_task_set_task_data (task, g_steal_pointer (&build_target), g_object_unref);
-
-  do_run_async (self, task);
-
-  IDE_EXIT;
-}
-
-static void
-ide_run_manager_install_cb (GObject      *object,
-                            GAsyncResult *result,
-                            gpointer      user_data)
-{
-  IdeBuildManager *build_manager = (IdeBuildManager *)object;
-  g_autoptr(IdeTask) task = user_data;
-  g_autoptr(GError) error = NULL;
-  IdeRunManager *self;
-  IdeBuildTarget *build_target;
-  GCancellable *cancellable;
-
-  IDE_ENTRY;
-
-  g_assert (IDE_IS_BUILD_MANAGER (build_manager));
   g_assert (IDE_IS_TASK (task));
 
-  self = ide_task_get_source_object (task);
-  g_assert (IDE_IS_RUN_MANAGER (self));
-
-  if (!ide_build_manager_build_finish (build_manager, result, &error))
-    {
-      /* We want to let the consumer know there was a build error
-       * (but don't need to pass the specific error code) so that
-       * they have an error code to check against.
-       */
-      ide_task_return_new_error (task,
-                                 IDE_RUNTIME_ERROR,
-                                 IDE_RUNTIME_ERROR_BUILD_FAILED,
-                                 /* translators: %s is replaced with the specific error reason */
-                                 _("The build target failed to build: %s"),
-                                 error->message);
-      IDE_EXIT;
-    }
-
-  self->last_change_seq = self->pending_last_change_seq;
-
-  build_target = ide_run_manager_get_build_target (self);
-
-  if (build_target == NULL)
+  if (!(run_command = ide_run_manager_discover_run_command_finish (self, result, &error)))
     {
-      cancellable = ide_task_get_cancellable (task);
-      g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-      ide_run_manager_discover_default_target_async (self,
-                                                     cancellable,
-                                                     ide_run_manager_run_discover_cb,
-                                                     g_steal_pointer (&task));
+      ide_task_return_error (task, g_steal_pointer (&error));
       IDE_EXIT;
     }
 
-  ide_task_set_task_data (task, g_object_ref (build_target), g_object_unref);
+  g_set_object (&self->current_run_command, run_command);
 
-  do_run_async (self, task);
-
-  IDE_EXIT;
-}
+  pipeline = ide_task_get_task_data (task);
+  g_assert (IDE_IS_PIPELINE (pipeline));
 
-static void
-ide_run_manager_task_completed (IdeRunManager *self,
-                                GParamSpec    *pspec,
-                                IdeTask       *task)
-{
-  IDE_ENTRY;
-
-  g_assert (IDE_IS_RUN_MANAGER (self));
-  g_assert (pspec != NULL);
-  g_assert (IDE_IS_TASK (task));
+  context = ide_object_get_context (IDE_OBJECT (pipeline));
+  g_assert (IDE_IS_CONTEXT (context));
 
-  self->busy = FALSE;
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+  device_manager = ide_device_manager_from_context (context);
+  g_assert (IDE_IS_DEVICE_MANAGER (device_manager));
 
-  ide_run_manager_update_action_enabled (self);
+  ide_device_manager_deploy_async (device_manager,
+                                   pipeline,
+                                   ide_task_get_cancellable (task),
+                                   ide_run_manager_run_deploy_cb,
+                                   g_object_ref (task));
 
   IDE_EXIT;
 }
 
 static void
-ide_run_manager_do_install_before_run (IdeRunManager *self,
-                                       IdeTask       *task)
+ide_run_manager_run_install_cb (GObject      *object,
+                                GAsyncResult *result,
+                                gpointer      user_data)
 {
-  g_autoptr(IdeContext) context = NULL;
-  g_autoptr(GSettings) project_settings = NULL;
-  IdeBuildManager *build_manager;
-  IdeVcsMonitor *monitor;
-  guint64 sequence = 0;
+  IdeRunManager *self = (IdeRunManager *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
 
   IDE_ENTRY;
 
   g_assert (IDE_IS_MAIN_THREAD ());
   g_assert (IDE_IS_RUN_MANAGER (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (IDE_IS_TASK (task));
 
-  context = ide_object_ref_context (IDE_OBJECT (self));
-  build_manager = ide_build_manager_from_context (context);
-  monitor = ide_vcs_monitor_from_context (context);
-  project_settings = ide_context_ref_project_settings (context);
-
-  /*
-   * First we need to make sure the target is up to date and installed
-   * so that all the dependent resources are available.
-   */
-
-  self->busy = TRUE;
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
-
-  g_signal_connect_object (task,
-                           "notify::completed",
-                           G_CALLBACK (ide_run_manager_task_completed),
-                           self,
-                           G_CONNECT_SWAPPED);
-
-  if (monitor != NULL)
-    sequence = ide_vcs_monitor_get_sequence (monitor);
-
-  /* If the user requests that we don't do install before running, then they probably
-   * have a work flow that allows them to do that. Just skip build/install and try
-   * to run it directly instead. We do need to do it once however to get the
-   * current build target (although that may change soon).
-   */
-  if (self->build_target != NULL &&
-      !g_settings_get_boolean (project_settings, "install-before-run"))
-    {
-      g_debug ("Skipping install phase as requested in project settings");
-      ide_run_manager_update_action_enabled (self);
-      ide_task_set_task_data (task, g_object_ref (self->build_target), g_object_unref);
-      do_run_async (self, task);
-      IDE_EXIT;
-    }
-
-  /*
-   * If we detect that nothing has changed in the project directory since the
-   * last time we ran, we can avoid installing the project. This will not help
-   * in situations where external resources have changed outside of builders
-   * control, but users can simply force a Build in that case.
-   */
-  if (self->build_target != NULL && sequence == self->last_change_seq)
-    {
-      g_debug ("Skipping install phase as no files appear to have changed "
-               "(sequence %"G_GUINT64_FORMAT")", sequence);
-      ide_run_manager_update_action_enabled (self);
-      ide_task_set_task_data (task, g_object_ref (self->build_target), g_object_unref);
-      do_run_async (self, task);
-      IDE_EXIT;
-    }
-
-  self->pending_last_change_seq = sequence;
-
-  ide_build_manager_build_async (build_manager,
-                                 IDE_PIPELINE_PHASE_INSTALL,
-                                 NULL,
-                                 ide_task_get_cancellable (task),
-                                 ide_run_manager_install_cb,
-                                 g_object_ref (task));
-
-  ide_run_manager_update_action_enabled (self);
+  if (!ide_run_manager_install_finish (self, result, &error))
+    ide_task_return_error (task, g_steal_pointer (&error));
+  else
+    ide_run_manager_discover_run_command_async (self,
+                                                ide_task_get_cancellable (task),
+                                                ide_run_manager_run_discover_run_command_cb,
+                                                g_object_ref (task));
 
   IDE_EXIT;
 }
@@ -1095,6 +1051,9 @@ ide_run_manager_run_async (IdeRunManager       *self,
   g_autoptr(IdeTask) task = NULL;
   g_autoptr(GCancellable) local_cancellable = NULL;
   g_autoptr(GError) error = NULL;
+  IdeBuildManager *build_manager;
+  IdePipeline *pipeline;
+  IdeContext *context;
 
   IDE_ENTRY;
 
@@ -1106,12 +1065,10 @@ ide_run_manager_run_async (IdeRunManager       *self,
 
   if (cancellable == NULL)
     cancellable = local_cancellable = g_cancellable_new ();
-
   ide_cancellable_chain (cancellable, self->cancellable);
 
   task = ide_task_new (self, cancellable, callback, user_data);
   ide_task_set_source_tag (task, ide_run_manager_run_async);
-  ide_task_set_priority (task, G_PRIORITY_LOW);
 
   if (ide_task_return_error_if_cancelled (task))
     IDE_EXIT;
@@ -1122,10 +1079,32 @@ ide_run_manager_run_async (IdeRunManager       *self,
       IDE_EXIT;
     }
 
-  if (build_target != NULL)
-    ide_run_manager_set_build_target (self, build_target);
+  ide_run_manager_mark_busy (self);
+  g_signal_connect_object (task,
+                           "notify::completed",
+                           G_CALLBACK (ide_run_manager_unmark_busy),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  build_manager = ide_build_manager_from_context (context);
+  pipeline = ide_build_manager_get_pipeline (build_manager);
+
+  if (pipeline == NULL)
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_NOT_FOUND,
+                                 "A pipeline cannot be found");
+      IDE_EXIT;
+    }
+
+  ide_task_set_task_data (task, g_object_ref (pipeline), g_object_unref);
 
-  ide_run_manager_do_install_before_run (self, task);
+  ide_run_manager_install_async (self,
+                                 cancellable,
+                                 ide_run_manager_run_install_cb,
+                                 g_steal_pointer (&task));
 
   IDE_EXIT;
 }


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