[gnome-builder/wip/gtk4-port] libide/foundry: take default-build-target into account



commit 7a389fca101e069e7b22cbf6a4183eee9e805320
Author: Christian Hergert <chergert redhat com>
Date:   Tue May 10 15:02:57 2022 -0700

    libide/foundry: take default-build-target into account
    
    If the build manager has a default build target and a regular build
    request was made, we should try to resolve the default build target and
    provide it to the build pipeline.
    
    We ignore this on things like install as that target will need things to
    be built anyway and so a target would need to be ignored.

 src/libide/foundry/ide-build-manager.c | 170 ++++++++++++++++++++++++++-------
 1 file changed, 134 insertions(+), 36 deletions(-)
---
diff --git a/src/libide/foundry/ide-build-manager.c b/src/libide/foundry/ide-build-manager.c
index 5fcb2185d..b53e26319 100644
--- a/src/libide/foundry/ide-build-manager.c
+++ b/src/libide/foundry/ide-build-manager.c
@@ -108,6 +108,14 @@ struct _IdeBuildManager
   guint             has_configured : 1;
 };
 
+typedef struct
+{
+  IdePipeline      *pipeline;
+  GPtrArray        *targets;
+  char             *default_target;
+  IdePipelinePhase  phase;
+} BuildState;
+
 static void initable_iface_init                           (GInitableIface  *iface);
 static void ide_build_manager_set_can_build               (IdeBuildManager *self,
                                                            gboolean         can_build);
@@ -165,6 +173,15 @@ enum {
 static GParamSpec *properties [N_PROPS];
 static guint signals [N_SIGNALS];
 
+static void
+build_state_free (BuildState *state)
+{
+  g_clear_pointer (&state->default_target, g_free);
+  g_clear_pointer (&state->targets, g_ptr_array_unref);
+  g_clear_object (&state->pipeline);
+  g_slice_free (BuildState, state);
+}
+
 static void
 ide_build_manager_action_default_build_target (IdeBuildManager *self,
                                                GVariant        *param)
@@ -1458,49 +1475,127 @@ failure:
 }
 
 static void
-ide_build_manager_save_all_cb (GObject      *object,
-                               GAsyncResult *result,
-                               gpointer      user_data)
+ide_build_manager_build_list_targets_cb (GObject      *object,
+                                         GAsyncResult *result,
+                                         gpointer      user_data)
 {
-  IdeBufferManager *buffer_manager = (IdeBufferManager *)object;
+  IdeBuildManager *self = (IdeBuildManager *)object;
+  g_autoptr(GListModel) targets = NULL;
   g_autoptr(IdeTask) task = user_data;
   g_autoptr(GError) error = NULL;
-  IdeBuildManager *self;
-  GCancellable *cancellable;
-  GPtrArray *targets;
-  IdePipelinePhase phase;
+  BuildState *state;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager));
+  g_assert (IDE_IS_BUILD_MANAGER (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (IDE_IS_TASK (task));
 
-  self = ide_task_get_source_object (task);
-  cancellable = ide_task_get_cancellable (task);
-  targets = ide_task_get_task_data (task);
+  state = ide_task_get_task_data (task);
 
-  g_assert (IDE_IS_BUILD_MANAGER (self));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+  g_assert (state != NULL);
+  g_assert (state->targets == NULL);
+  g_assert (state->default_target != NULL);
+  g_assert (IDE_IS_PIPELINE (state->pipeline));
 
-  if (!ide_buffer_manager_save_all_finish (buffer_manager, result, &error))
+  if ((targets = ide_build_manager_list_targets_finish (self, result, &error)))
     {
-      ide_task_return_error (task, g_steal_pointer (&error));
-      IDE_EXIT;
+      guint n_items = g_list_model_get_n_items (targets);
+
+      for (guint i = 0; i < n_items; i++)
+        {
+          g_autoptr(IdeBuildTarget) target = g_list_model_get_item (targets, i);
+          const char *name = ide_build_target_get_name (target);
+
+          if (g_strcmp0 (name, state->default_target) == 0)
+            {
+              state->targets = g_ptr_array_new_with_free_func (g_object_unref);
+              g_ptr_array_add (state->targets, g_steal_pointer (&target));
+              break;
+            }
+        }
     }
 
-  phase = ide_pipeline_get_requested_phase (self->pipeline);
+  if (error != NULL && !ide_error_ignore (error))
+    g_warning ("Failed to list build targets: %s", error->message);
 
-  ide_pipeline_build_targets_async (self->pipeline,
-                                    phase,
-                                    targets,
-                                    cancellable,
+  ide_pipeline_build_targets_async (state->pipeline,
+                                    state->phase,
+                                    state->targets,
+                                    ide_task_get_cancellable (task),
                                     ide_build_manager_build_targets_cb,
-                                    g_steal_pointer (&task));
+                                    g_object_ref (task));
+
+  IDE_EXIT;
+}
+
+static void
+ide_build_manager_build_after_save (IdeTask *task)
+{
+  IdeBuildManager *self;
+  BuildState *state;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_TASK (task));
+
+  self = ide_task_get_source_object (task);
+  state = ide_task_get_task_data (task);
+
+  g_assert (IDE_IS_BUILD_MANAGER (self));
+  g_assert (state != NULL);
+  g_assert (IDE_IS_PIPELINE (state->pipeline));
+
+  /* If a default build target was preferred instead of the build system
+   * default then we need to go fetch that from the build target providers.
+   * However, we can only do this if we are just building. Anything requiring
+   * us to install means that we have to do regular builds as that will happen
+   * anyway as part of the install process.
+   */
+  if (state->targets == NULL &&
+      state->default_target != NULL &&
+      state->phase < IDE_PIPELINE_PHASE_INSTALL)
+    ide_build_manager_list_targets_async (self,
+                                          ide_task_get_cancellable (task),
+                                          ide_build_manager_build_list_targets_cb,
+                                          g_object_ref (task));
+  else
+    ide_pipeline_build_targets_async (state->pipeline,
+                                      state->phase,
+                                      state->targets,
+                                      ide_task_get_cancellable (task),
+                                      ide_build_manager_build_targets_cb,
+                                      g_object_ref (task));
+
+  IDE_EXIT;
+}
+
+static void
+ide_build_manager_save_all_cb (GObject      *object,
+                               GAsyncResult *result,
+                               gpointer      user_data)
+{
+  IdeBufferManager *buffer_manager = (IdeBufferManager *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  IdeBuildManager *self;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager));
+  g_assert (IDE_IS_TASK (task));
+
+  self = ide_task_get_source_object (task);
 
   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HAS_DIAGNOSTICS]);
   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LAST_BUILD_TIME]);
   g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNNING_TIME]);
 
+  if (!ide_buffer_manager_save_all_finish (buffer_manager, result, &error))
+    ide_task_return_error (task, g_steal_pointer (&error));
+  else
+    ide_build_manager_build_after_save (task);
+
   IDE_EXIT;
 }
 
@@ -1530,8 +1625,7 @@ ide_build_manager_build_async (IdeBuildManager     *self,
                                gpointer             user_data)
 {
   g_autoptr(IdeTask) task = NULL;
-  IdeBufferManager *buffer_manager;
-  IdeContext *context;
+  BuildState *state;
 
   IDE_ENTRY;
 
@@ -1546,9 +1640,6 @@ ide_build_manager_build_async (IdeBuildManager     *self,
   ide_task_set_priority (task, G_PRIORITY_LOW);
   ide_task_set_return_on_cancel (task, TRUE);
 
-  if (targets != NULL)
-    ide_task_set_task_data (task, _g_ptr_array_copy_objects (targets), g_ptr_array_unref);
-
   if (self->pipeline == NULL ||
       self->can_build == FALSE ||
       !ide_pipeline_is_ready (self->pipeline))
@@ -1566,6 +1657,17 @@ ide_build_manager_build_async (IdeBuildManager     *self,
       IDE_EXIT;
     }
 
+  /* Setup our state for the build process. We try to cache everything
+   * we need up front so that we don't need to deal with races between
+   * asynchronous operations.
+   */
+  state = g_slice_new0 (BuildState);
+  state->phase = phase;
+  state->default_target = g_strdup (self->default_build_target);
+  state->targets = targets ? _g_ptr_array_copy_objects (targets) : NULL;
+  state->pipeline = g_object_ref (self->pipeline);
+  ide_task_set_task_data (task, state, build_state_free);
+
   /*
    * Only update our "build time" if we are advancing to IDE_PIPELINE_PHASE_BUILD,
    * we don't really care about "builds" for configure stages and less.
@@ -1589,8 +1691,9 @@ ide_build_manager_build_async (IdeBuildManager     *self,
    */
   if ((phase & IDE_PIPELINE_PHASE_MASK) >= IDE_PIPELINE_PHASE_BUILD)
     {
-      context = ide_object_get_context (IDE_OBJECT (self));
-      buffer_manager = ide_buffer_manager_from_context (context);
+      IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
+      IdeBufferManager *buffer_manager = ide_buffer_manager_from_context (context);
+
       ide_buffer_manager_save_all_async (buffer_manager,
                                          NULL,
                                          ide_build_manager_save_all_cb,
@@ -1598,12 +1701,7 @@ ide_build_manager_build_async (IdeBuildManager     *self,
       IDE_EXIT;
     }
 
-  ide_pipeline_build_targets_async (self->pipeline,
-                                    phase,
-                                    targets,
-                                    cancellable,
-                                    ide_build_manager_build_targets_cb,
-                                    g_steal_pointer (&task));
+  ide_build_manager_build_after_save (task);
 
   IDE_EXIT;
 }


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