[gnome-builder] pipeline: allow chaining neighboring stages



commit 512717de0c1bf1b047dbb6251f3fed12657f426d
Author: Christian Hergert <chergert redhat com>
Date:   Fri Feb 24 21:19:27 2017 -0800

    pipeline: allow chaining neighboring stages
    
    If we have two stages next to each other during execution that can be
    executed as a single step, then we should avoid doing two steps. The one
    to think about here is "make all" and then "make install". Not ideal. We
    try not to be too aggressive here because we don't want to install if that
    phase was not requested.

 libide/buildsystem/ide-build-pipeline.c |   48 +++++++++++++++++++++++++++++++
 libide/buildsystem/ide-build-stage.c    |   33 +++++++++++++++++++++
 libide/buildsystem/ide-build-stage.h    |   17 +++++++++++
 3 files changed, 98 insertions(+), 0 deletions(-)
---
diff --git a/libide/buildsystem/ide-build-pipeline.c b/libide/buildsystem/ide-build-pipeline.c
index a947725..4549bd3 100644
--- a/libide/buildsystem/ide-build-pipeline.c
+++ b/libide/buildsystem/ide-build-pipeline.c
@@ -1087,6 +1087,47 @@ ide_build_pipeline_stage_execute_cb (GObject      *object,
 }
 
 static void
+ide_build_pipeline_try_chain (IdeBuildPipeline *self,
+                              IdeBuildStage    *stage,
+                              guint             position)
+{
+  g_assert (IDE_IS_BUILD_PIPELINE (self));
+  g_assert (IDE_IS_BUILD_STAGE (stage));
+
+  for (; position < self->pipeline->len; position++)
+    {
+      const PipelineEntry *entry = &g_array_index (self->pipeline, PipelineEntry, position);
+      gboolean chained;
+
+      /*
+       * Ignore all future stages if they were not requested by the current
+       * pipeline execution.
+       */
+      if (((entry->phase & IDE_BUILD_PHASE_MASK) & self->requested_mask) == 0)
+        return;
+
+      chained = ide_build_stage_chain (stage, entry->stage);
+
+      IDE_TRACE_MSG ("Checking if %s chains to stage[%d] (%s) = %s",
+                     G_OBJECT_TYPE_NAME (stage),
+                     position,
+                     G_OBJECT_TYPE_NAME (entry->stage),
+                     chained ? "yes" : "no");
+
+      if (!chained)
+        return;
+
+      /*
+       * NOTE: We do not mark the chained stage as completed as that is left
+       *       up to the chain implementation. We simply let self->position
+       *       be advanced to point at the index of the cained entry.
+       */
+
+      self->position = position;
+    }
+}
+
+static void
 ide_build_pipeline_tick_execute (IdeBuildPipeline *self,
                                  GTask            *task)
 {
@@ -1138,6 +1179,13 @@ ide_build_pipeline_tick_execute (IdeBuildPipeline *self,
         {
           self->current_stage = entry->stage;
 
+          /*
+           * We might be able to chain upcoming stages to this stage and avoid
+           * duplicate work. This will also advance self->position based on
+           * how many stages were chained.
+           */
+          ide_build_pipeline_try_chain (self, entry->stage, self->position + 1);
+
           _ide_build_stage_execute_with_query_async (entry->stage,
                                                      self,
                                                      cancellable,
diff --git a/libide/buildsystem/ide-build-stage.c b/libide/buildsystem/ide-build-stage.c
index cf8e133..7f19728 100644
--- a/libide/buildsystem/ide-build-stage.c
+++ b/libide/buildsystem/ide-build-stage.c
@@ -50,6 +50,7 @@ enum {
 };
 
 enum {
+  CHAIN,
   QUERY,
   REAP,
   N_SIGNALS
@@ -229,6 +230,13 @@ ide_build_stage_real_clean_finish (IdeBuildStage  *self,
   return g_task_propagate_boolean (G_TASK (result), error);
 }
 
+static gboolean
+ide_build_stage_real_chain (IdeBuildStage *self,
+                            IdeBuildStage *next)
+{
+  return FALSE;
+}
+
 static void
 ide_build_stage_finalize (GObject *object)
 {
@@ -313,6 +321,7 @@ ide_build_stage_class_init (IdeBuildStageClass *klass)
   klass->execute_finish = ide_build_stage_real_execute_finish;
   klass->clean_async = ide_build_stage_real_clean_async;
   klass->clean_finish = ide_build_stage_real_clean_finish;
+  klass->chain = ide_build_stage_real_chain;
 
   /**
    * IdeBuildStage:completed:
@@ -378,6 +387,16 @@ ide_build_stage_class_init (IdeBuildStageClass *klass)
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
+  signals [CHAIN] =
+    g_signal_new ("chain",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (IdeBuildStageClass, chain),
+                  g_signal_accumulator_true_handled,
+                  NULL,
+                  NULL,
+                  G_TYPE_BOOLEAN, 1, IDE_TYPE_BUILD_STAGE);
+
   signals [QUERY] =
     g_signal_new_class_handler ("query",
                                 G_TYPE_FROM_CLASS (klass),
@@ -897,3 +916,17 @@ ide_build_stage_emit_reap (IdeBuildStage      *self,
 
   IDE_EXIT;
 }
+
+gboolean
+ide_build_stage_chain (IdeBuildStage *self,
+                       IdeBuildStage *next)
+{
+  gboolean ret = FALSE;
+
+  g_return_val_if_fail (IDE_IS_BUILD_STAGE (self), FALSE);
+  g_return_val_if_fail (IDE_IS_BUILD_STAGE (next), FALSE);
+
+  g_signal_emit (self, signals[CHAIN], 0, next, &ret);
+
+  return ret;
+}
diff --git a/libide/buildsystem/ide-build-stage.h b/libide/buildsystem/ide-build-stage.h
index 2a799b5..32370f1 100644
--- a/libide/buildsystem/ide-build-stage.h
+++ b/libide/buildsystem/ide-build-stage.h
@@ -141,6 +141,21 @@ struct _IdeBuildStageClass
   void     (*reap)           (IdeBuildStage        *self,
                               IdeDirectoryReaper   *reaper);
 
+
+  /**
+   * IdeBuildStage:chain:
+   *
+   * We might want to be able to "chain" multiple stages into a single stage
+   * so that we can avoid duplicate work. For example, if we have a "make"
+   * stage immediately follwed by a "make install" stage, it does not make
+   * sense to perform them both individually.
+   *
+   * Returns: %TRUE if @next's work was chained into @self for the next
+   *    execution of the pipeline.
+   */
+  gboolean (*chain)          (IdeBuildStage        *self,
+                              IdeBuildStage        *next);
+
   gpointer _reserved1;
   gpointer _reserved2;
   gpointer _reserved3;
@@ -193,6 +208,8 @@ void           ide_build_stage_clean_async      (IdeBuildStage        *self,
 gboolean       ide_build_stage_clean_finish     (IdeBuildStage        *self,
                                                  GAsyncResult         *result,
                                                  GError              **error);
+gboolean       ide_build_stage_chain            (IdeBuildStage        *self,
+                                                 IdeBuildStage        *next);
 void           ide_build_stage_pause            (IdeBuildStage        *self);
 void           ide_build_stage_unpause          (IdeBuildStage        *self);
 void           ide_build_stage_emit_reap        (IdeBuildStage        *self,


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