[gnome-builder/wip/chergert/pipeline-merge: 31/78] build-manager: port to IdeBuildPipeline



commit f318efc597842e6364d6210ed9d67dd08ca31ca8
Author: Christian Hergert <chergert redhat com>
Date:   Fri Feb 3 13:50:12 2017 -0800

    build-manager: port to IdeBuildPipeline
    
    This moves the build manager to use the new IdeBuildPipeline. We can drop
    a bunch of things such as IdeBuildResult and IdeBuilder with this design.

 libide/Makefile.am                            |    9 -
 libide/buildsystem/ide-build-manager.c        | 1242 ++++++++++++++-----------
 libide/buildsystem/ide-build-manager.h        |   53 +-
 libide/buildsystem/ide-build-result-addin.c   |   60 --
 libide/buildsystem/ide-build-result-addin.h   |   47 -
 libide/buildsystem/ide-build-result.c         |  868 -----------------
 libide/buildsystem/ide-build-result.h         |   89 --
 libide/buildsystem/ide-build-system.c         |  252 +++---
 libide/buildsystem/ide-build-system.h         |   35 +-
 libide/buildsystem/ide-builder.c              |  465 ---------
 libide/buildsystem/ide-builder.h              |  126 ---
 libide/buildsystem/ide-simple-builder.c       |  172 ----
 libide/buildsystem/ide-simple-builder.h       |   47 -
 libide/directory/ide-directory-build-system.c |   23 -
 libide/ide-context.c                          |   22 +
 libide/ide-enums.c.in                         |    1 -
 libide/ide.h                                  |    4 -
 libide/runner/ide-run-manager.c               |   16 +-
 libide/runtimes/ide-runtime.c                 |  159 ----
 libide/runtimes/ide-runtime.h                 |   48 -
 libide/workbench/ide-omni-bar.c               |   99 +-
 21 files changed, 958 insertions(+), 2879 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index f59585c..02cecc4 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -40,16 +40,12 @@ libide_1_0_la_public_headers =                            \
        buildsystem/ide-build-stage-launcher.h            \
        buildsystem/ide-build-stage-mkdirs.h              \
        buildsystem/ide-build-stage-transfer.h            \
-       buildsystem/ide-build-result-addin.h              \
-       buildsystem/ide-build-result.h                    \
        buildsystem/ide-build-system.h                    \
        buildsystem/ide-build-target.h                    \
-       buildsystem/ide-builder.h                         \
        buildsystem/ide-configuration-manager.h           \
        buildsystem/ide-configuration.h                   \
        buildsystem/ide-environment-variable.h            \
        buildsystem/ide-environment.h                     \
-       buildsystem/ide-simple-builder.h                  \
        devices/ide-device-manager.h                      \
        devices/ide-device-provider.h                     \
        devices/ide-device.h                              \
@@ -215,16 +211,12 @@ libide_1_0_la_public_sources =                            \
        buildsystem/ide-build-stage-launcher.c            \
        buildsystem/ide-build-stage-mkdirs.c              \
        buildsystem/ide-build-stage-transfer.c            \
-       buildsystem/ide-build-result-addin.c              \
-       buildsystem/ide-build-result.c                    \
        buildsystem/ide-build-system.c                    \
        buildsystem/ide-build-target.c                    \
-       buildsystem/ide-builder.c                         \
        buildsystem/ide-configuration-manager.c           \
        buildsystem/ide-configuration.c                   \
        buildsystem/ide-environment-variable.c            \
        buildsystem/ide-environment.c                     \
-       buildsystem/ide-simple-builder.c                  \
        devices/ide-device-manager.c                      \
        devices/ide-device-provider.c                     \
        devices/ide-device.c                              \
@@ -621,7 +613,6 @@ glib_enum_headers =                        \
        buffers/ide-buffer.h               \
        buildsystem/ide-build-log.h        \
        buildsystem/ide-build-pipeline.h   \
-       buildsystem/ide-build-result.h     \
        devices/ide-device.h               \
        diagnostics/ide-diagnostic.h       \
        doap/ide-doap.h                    \
diff --git a/libide/buildsystem/ide-build-manager.c b/libide/buildsystem/ide-build-manager.c
index 1ab9679..4e6d869 100644
--- a/libide/buildsystem/ide-build-manager.c
+++ b/libide/buildsystem/ide-build-manager.c
@@ -1,6 +1,6 @@
 /* ide-build-manager.c
  *
- * Copyright (C) 2016 Christian Hergert <chergert redhat com>
+ * Copyright (C) 2016-2017 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
@@ -18,44 +18,36 @@
 
 #define G_LOG_DOMAIN "ide-build-manager"
 
-#include <egg-signal-group.h>
-#include <glib/gi18n.h>
-
 #include "ide-context.h"
 #include "ide-debug.h"
 
 #include "buffers/ide-buffer-manager.h"
-#include "buildsystem/ide-builder.h"
 #include "buildsystem/ide-build-manager.h"
-#include "buildsystem/ide-build-result.h"
-#include "buildsystem/ide-build-system.h"
-#include "buildsystem/ide-build-target.h"
-#include "buildsystem/ide-configuration.h"
+#include "buildsystem/ide-build-pipeline.h"
 #include "buildsystem/ide-configuration-manager.h"
+#include "buildsystem/ide-configuration.h"
 
 struct _IdeBuildManager
 {
-  IdeObject             parent_instance;
+  IdeObject         parent_instance;
 
-  EggSignalGroup       *signals;
-  IdeBuildResult       *build_result;
-  GCancellable         *cancellable;
-  GDateTime            *last_build_time;
-  GSimpleActionGroup   *actions;
+  IdeBuildPipeline *pipeline;
+  GDateTime        *last_build_time;
+  GCancellable     *cancellable;
+  GActionGroup     *actions;
 
-  guint                 has_diagnostics : 1;
-  guint                 saving : 1;
-};
+  GTimer           *running_time;
 
-typedef struct
-{
-  IdeBuilder *builder;
-  IdeBuilderBuildFlags build_flags;
-} BuildState;
+  guint             diagnostic_count;
 
-static void action_group_iface_init (GActionGroupInterface *iface);
+  guint             timer_source;
+};
+
+static void initable_iface_init     (GInitableIface *);
+static void action_group_iface_init (GActionGroupInterface *);
 
 G_DEFINE_TYPE_EXTENDED (IdeBuildManager, ide_build_manager, IDE_TYPE_OBJECT, 0,
+                        G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
                         G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP, action_group_iface_init))
 
 enum {
@@ -78,175 +70,287 @@ enum {
 static GParamSpec *properties [N_PROPS];
 static guint signals [N_SIGNALS];
 
-static void
-build_state_free (gpointer data)
+static gboolean
+timer_callback (gpointer data)
 {
-  BuildState *state = data;
+  IdeBuildManager *self = data;
 
-  if (state != NULL)
-    {
-      g_clear_object (&state->builder);
-      g_slice_free (BuildState, state);
-    }
+  g_assert (IDE_IS_BUILD_MANAGER (self));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNNING_TIME]);
+
+  return G_SOURCE_CONTINUE;
 }
 
 static void
-ide_build_manager__build_result__notify_mode (IdeBuildManager *self,
-                                              GParamSpec      *mode_pspec,
-                                              IdeBuildResult  *build_result)
+ide_build_manager_start_timer (IdeBuildManager *self)
 {
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  IDE_ENTRY;
+
   g_assert (IDE_IS_BUILD_MANAGER (self));
+  g_assert (self->timer_source == 0);
 
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MESSAGE]);
+  if (self->running_time != NULL)
+    g_timer_start (self->running_time);
+  else
+    self->running_time = g_timer_new ();
+
+  /*
+   * We use the EggFrameSource for our timer callback because we only want to
+   * update at a rate somewhat close to a typical monitor refresh rate.
+   * Additionally, we want to handle drift (which that source does) so that we
+   * don't constantly fall behind.
+   */
+  self->timer_source = g_timeout_add_seconds (1, timer_callback, self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNNING_TIME]);
+
+  IDE_EXIT;
 }
 
 static void
-ide_build_manager__build_result__notify_running (IdeBuildManager *self,
-                                                 GParamSpec      *running_pspec,
-                                                 IdeBuildResult  *build_result)
+ide_build_manager_stop_timer (IdeBuildManager *self)
 {
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  IDE_ENTRY;
+
   g_assert (IDE_IS_BUILD_MANAGER (self));
 
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+  g_timer_stop (self->running_time);
+  ide_clear_source (&self->timer_source);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNNING_TIME]);
+
+  IDE_EXIT;
 }
 
 static void
-ide_build_manager__build_result__notify_running_time (IdeBuildManager *self,
-                                                      GParamSpec      *running_time_pspec,
-                                                      IdeBuildResult  *build_result)
+ide_build_manager_handle_diagnostic (IdeBuildManager  *self,
+                                     IdeDiagnostic    *diagnostic,
+                                     IdeBuildPipeline *pipeline)
 {
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  IDE_ENTRY;
+
   g_assert (IDE_IS_BUILD_MANAGER (self));
+  g_assert (diagnostic != NULL);
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNNING_TIME]);
+  self->diagnostic_count++;
+
+  if (self->diagnostic_count == 1)
+    g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HAS_DIAGNOSTICS]);
+
+  IDE_EXIT;
 }
 
 static void
-ide_build_manager__build_result__diagnostic (IdeBuildManager *self,
-                                             IdeDiagnostic   *diagnostic,
-                                             IdeBuildResult  *build_result)
+ide_build_manager_notify_busy (IdeBuildManager  *self,
+                               GParamSpec       *pspec,
+                               IdeBuildPipeline *pipeline)
 {
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
-  g_assert (diagnostic != NULL);
+  IDE_ENTRY;
+
   g_assert (IDE_IS_BUILD_MANAGER (self));
+  g_assert (G_IS_PARAM_SPEC (pspec));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
-  if (self->has_diagnostics == FALSE)
-    {
-      self->has_diagnostics = TRUE;
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HAS_DIAGNOSTICS]);
-    }
+  if (pipeline == self->pipeline)
+    g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+
+  IDE_EXIT;
 }
 
 static void
-ide_build_manager_build_activate (GSimpleAction *action,
-                                  GVariant      *parameter,
-                                  gpointer       user_data)
+ide_build_manager_notify_message (IdeBuildManager  *self,
+                                  GParamSpec       *pspec,
+                                  IdeBuildPipeline *pipeline)
 {
-  IdeBuildManager *self = user_data;
+  IDE_ENTRY;
 
-  g_assert (G_IS_SIMPLE_ACTION (action));
   g_assert (IDE_IS_BUILD_MANAGER (self));
+  g_assert (G_IS_PARAM_SPEC (pspec));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
-  ide_build_manager_build_async (self,
-                                 NULL,
-                                 IDE_BUILDER_BUILD_FLAGS_NONE,
-                                 NULL,
-                                 NULL,
-                                 NULL);
+  if (pipeline == self->pipeline)
+    g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MESSAGE]);
+
+  IDE_EXIT;
 }
 
 static void
-ide_build_manager_rebuild_activate (GSimpleAction *action,
-                                    GVariant      *parameter,
-                                    gpointer       user_data)
+ide_build_manager_pipeline_started (IdeBuildManager  *self,
+                                    IdeBuildPipeline *pipeline)
 {
-  IdeBuildManager *self = user_data;
+  IDE_ENTRY;
 
-  g_assert (G_IS_SIMPLE_ACTION (action));
   g_assert (IDE_IS_BUILD_MANAGER (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
-  ide_build_manager_build_async (self,
-                                 NULL,
-                                 IDE_BUILDER_BUILD_FLAGS_FORCE_CLEAN,
-                                 NULL,
-                                 NULL,
-                                 NULL);
+  g_signal_emit (self, signals [BUILD_STARTED], 0, pipeline);
+
+  IDE_EXIT;
 }
 
 static void
-ide_build_manager_cancel_activate (GSimpleAction *action,
-                                   GVariant      *parameter,
-                                   gpointer       user_data)
+ide_build_manager_pipeline_finished (IdeBuildManager  *self,
+                                     gboolean          failed,
+                                     IdeBuildPipeline *pipeline)
 {
-  IdeBuildManager *self = user_data;
+  IDE_ENTRY;
 
-  g_assert (G_IS_SIMPLE_ACTION (action));
   g_assert (IDE_IS_BUILD_MANAGER (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
-  ide_build_manager_cancel (self);
+  if (failed)
+    g_signal_emit (self, signals [BUILD_FAILED], 0, pipeline);
+  else
+    g_signal_emit (self, signals [BUILD_FINISHED], 0, pipeline);
+
+  IDE_EXIT;
 }
 
 static void
-ide_build_manager_clean_activate (GSimpleAction *action,
-                                  GVariant      *parameter,
-                                  gpointer       user_data)
+ide_build_manager_invalidate_pipeline (IdeBuildManager *self)
 {
-  IdeBuildManager *self = user_data;
+  IdeConfigurationManager *config_manager;
+  g_autoptr(GError) error = NULL;
+  IdeConfiguration *config;
+  IdeContext *context;
+
+  IDE_ENTRY;
 
-  g_assert (G_IS_SIMPLE_ACTION (action));
   g_assert (IDE_IS_BUILD_MANAGER (self));
 
-  ide_build_manager_build_async (self,
-                                 NULL,
-                                 (IDE_BUILDER_BUILD_FLAGS_FORCE_CLEAN |
-                                  IDE_BUILDER_BUILD_FLAGS_NO_BUILD),
-                                 NULL,
-                                 NULL,
+  IDE_TRACE_MSG ("Reloading pipeline due to configuration change");
+
+  if (self->cancellable != NULL)
+    ide_build_manager_cancel (self);
+
+  g_clear_object (&self->pipeline);
+  g_clear_pointer (&self->running_time, g_timer_destroy);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  config_manager = ide_context_get_configuration_manager (context);
+  config = ide_configuration_manager_get_current (config_manager);
+
+  /*
+   * We want to set the pipeline before connecting things using the GInitable
+   * interface so that we can access the builddir from
+   * IdeRuntime.create_launcher() during pipeline addin initialization.
+   */
+  self->pipeline = g_object_new (IDE_TYPE_BUILD_PIPELINE,
+                                 "context", context,
+                                 "configuration", config,
                                  NULL);
+
+  g_signal_connect_object (self->pipeline,
+                           "diagnostic",
+                           G_CALLBACK (ide_build_manager_handle_diagnostic),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (self->pipeline,
+                           "notify::busy",
+                           G_CALLBACK (ide_build_manager_notify_busy),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (self->pipeline,
+                           "notify::message",
+                           G_CALLBACK (ide_build_manager_notify_message),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (self->pipeline,
+                           "started",
+                           G_CALLBACK (ide_build_manager_pipeline_started),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (self->pipeline,
+                           "finished",
+                           G_CALLBACK (ide_build_manager_pipeline_finished),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  self->diagnostic_count = 0;
+
+  g_clear_object (&self->cancellable);
+
+  /* This will cause plugins to load on the pipeline. */
+  if (!g_initable_init (G_INITABLE (self->pipeline), NULL, &error))
+    g_warning ("Failure to initialize pipeline: %s", error->message);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+  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_MESSAGE]);
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNNING_TIME]);
+
+  IDE_EXIT;
 }
 
-static void
-ide_build_manager__build_result__notify_failed (IdeBuildManager *self,
-                                                GParamSpec      *pspec,
-                                                IdeBuildResult  *build_result)
+static gboolean
+initable_init (GInitable     *initable,
+               GCancellable  *cancellable,
+               GError       **error)
 {
+  IdeBuildManager *self = (IdeBuildManager *)initable;
+  IdeConfigurationManager *config_manager;
+  IdeContext *context;
+
+  IDE_ENTRY;
+
   g_assert (IDE_IS_BUILD_MANAGER (self));
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  config_manager = ide_context_get_configuration_manager (context);
+
+  g_signal_connect_object (config_manager,
+                           "invalidate",
+                           G_CALLBACK (ide_build_manager_invalidate_pipeline),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  ide_build_manager_invalidate_pipeline (self);
 
-  if (ide_build_result_get_failed (build_result))
-    g_signal_emit (self, signals [BUILD_FAILED], 0, build_result);
+  IDE_RETURN (TRUE);
 }
 
 static void
-ide_build_manager_real_build_started (IdeBuildManager *self,
-                                      IdeBuildResult  *build_result)
+ide_build_manager_real_build_started (IdeBuildManager  *self,
+                                      IdeBuildPipeline *pipeline)
 {
   g_assert (IDE_IS_BUILD_MANAGER (self));
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+  ide_build_manager_start_timer (self);
 }
 
 static void
-ide_build_manager_real_build_failed (IdeBuildManager *self,
-                                     IdeBuildResult  *build_result)
+ide_build_manager_real_build_failed (IdeBuildManager  *self,
+                                     IdeBuildPipeline *pipeline)
 {
   g_assert (IDE_IS_BUILD_MANAGER (self));
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+  ide_build_manager_stop_timer (self);
 }
 
 static void
-ide_build_manager_real_build_finished (IdeBuildManager *self,
-                                       IdeBuildResult  *build_result)
+ide_build_manager_real_build_finished (IdeBuildManager  *self,
+                                       IdeBuildPipeline *pipeline)
 {
   g_assert (IDE_IS_BUILD_MANAGER (self));
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
 
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+  ide_build_manager_stop_timer (self);
+}
+
+static void
+initable_iface_init (GInitableIface *iface)
+{
+  iface->init = initable_init;
 }
 
 static void
@@ -254,11 +358,12 @@ ide_build_manager_finalize (GObject *object)
 {
   IdeBuildManager *self = (IdeBuildManager *)object;
 
-  g_clear_object (&self->build_result);
-  g_clear_object (&self->signals);
-  g_clear_object (&self->actions);
+  g_clear_object (&self->pipeline);
   g_clear_object (&self->cancellable);
   g_clear_pointer (&self->last_build_time, g_date_time_unref);
+  g_clear_pointer (&self->running_time, g_timer_destroy);
+
+  ide_clear_source (&self->timer_source);
 
   G_OBJECT_CLASS (ide_build_manager_parent_class)->finalize (object);
 }
@@ -277,22 +382,22 @@ ide_build_manager_get_property (GObject    *object,
       g_value_set_boolean (value, ide_build_manager_get_busy (self));
       break;
 
-    case PROP_LAST_BUILD_TIME:
-      g_value_set_boxed (value, ide_build_manager_get_last_build_time (self));
-      break;
-
-    case PROP_HAS_DIAGNOSTICS:
-      g_value_set_boolean (value, self->has_diagnostics);
-      break;
-
     case PROP_MESSAGE:
       g_value_take_string (value, ide_build_manager_get_message (self));
       break;
 
+    case PROP_LAST_BUILD_TIME:
+      g_value_set_boxed (value, ide_build_manager_get_last_build_time (self));
+      break;
+
     case PROP_RUNNING_TIME:
       g_value_set_int64 (value, ide_build_manager_get_running_time (self));
       break;
 
+    case PROP_HAS_DIAGNOSTICS:
+      g_value_set_boolean (value, self->diagnostic_count > 0);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -306,511 +411,453 @@ ide_build_manager_class_init (IdeBuildManagerClass *klass)
   object_class->finalize = ide_build_manager_finalize;
   object_class->get_property = ide_build_manager_get_property;
 
+  /**
+   * IdeBuildManager:busy:
+   *
+   * The "busy" property indicates if there is currently a build
+   * executing. This can be bound to UI elements to display to the
+   * user that a build is active (and therefore other builds cannot
+   * be activated at the moment).
+   */
   properties [PROP_BUSY] =
     g_param_spec_boolean ("busy",
                           "Busy",
-                          "If the build manager is busy building",
+                          "If a build is actively executing",
                           FALSE,
-                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
-  properties [PROP_LAST_BUILD_TIME] =
-    g_param_spec_boxed ("last-build-time",
-                        "Last Build Time",
-                        "The time the last build was submitted",
-                        G_TYPE_DATE_TIME,
-                        (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
+  /**
+   * IdeBuildManager:has-diagnostics:
+   *
+   * The "has-diagnostics" property indicates that there have been
+   * diagnostics found during the last execution of the build pipeline.
+   */
   properties [PROP_HAS_DIAGNOSTICS] =
     g_param_spec_boolean ("has-diagnostics",
                           "Has Diagnostics",
-                          "If the build result has diagnostics",
+                          "Has Diagnostics",
                           FALSE,
-                          (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+                          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
+  /**
+   * IdeBuildManager:last-build-time:
+   *
+   * The "last-build-time" property contains a #GDateTime of the time
+   * the last build request was submitted.
+   */
+  properties [PROP_LAST_BUILD_TIME] =
+    g_param_spec_boxed ("last-build-time",
+                        "Last Build Time",
+                        "The time of the last build request",
+                        G_TYPE_DATE_TIME,
+                        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * IdeBuildManager:message:
+   *
+   * The "message" property contains a string message describing
+   * the current state of the build process. This may be bound to
+   * UI elements to notify the user of the buid progress.
+   */
   properties [PROP_MESSAGE] =
     g_param_spec_string ("message",
                          "Message",
                          "The current build message",
                          NULL,
-                         (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
+                         G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * IdeBuildManager:running-time:
+   *
+   * The "running-time" property can be bound by UI elements that
+   * want to track how long the current build has taken. g_object_notify()
+   * is called on a regular interval during the build so that the UI
+   * elements may automatically update.
+   *
+   * The value of this property is a #GTimeSpan, which are 64-bit signed
+   * integers with microsecond precision. See %G_USEC_PER_SEC for a constant
+   * to tranform this to seconds.
+   */
   properties [PROP_RUNNING_TIME] =
     g_param_spec_int64 ("running-time",
                         "Running Time",
-                        "The duration of the build as a GTimeSpan",
+                        "The amount of elapsed time performing the current build",
                         0,
                         G_MAXINT64,
                         0,
-                        (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+                        G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 
+  /**
+   * IdeBuildManager::build-started:
+   * @self: An #IdeBuildManager
+   * @pipeline: An #IdeBuildPipeline
+   *
+   * The "build-started" signal is emitted when a new build has started.
+   * The build may be an incremental build. The @pipeline instance is
+   * the build pipeline which is being executed.
+   */
   signals [BUILD_STARTED] =
     g_signal_new_class_handler ("build-started",
                                 G_TYPE_FROM_CLASS (klass),
                                 G_SIGNAL_RUN_LAST,
                                 G_CALLBACK (ide_build_manager_real_build_started),
+                                NULL, NULL,
                                 NULL,
-                                NULL,
-                                NULL,
-                                G_TYPE_NONE, 1, IDE_TYPE_BUILD_RESULT);
-
+                                G_TYPE_NONE, 1, IDE_TYPE_BUILD_PIPELINE);
+
+  /**
+   * IdeBuildManager::build-failed:
+   * @self: An #IdeBuildManager
+   * @pipeline: An #IdeBuildPipeline
+   *
+   * The "build-failed" signal is emitted when a build that was previously
+   * notified via #IdeBuildManager::build-started has failed to complete
+   * successfully.
+   *
+   * Contrast this with #IdeBuildManager::build-finished for a successful
+   * build.
+   */
   signals [BUILD_FAILED] =
     g_signal_new_class_handler ("build-failed",
                                 G_TYPE_FROM_CLASS (klass),
                                 G_SIGNAL_RUN_LAST,
                                 G_CALLBACK (ide_build_manager_real_build_failed),
+                                NULL, NULL,
                                 NULL,
-                                NULL,
-                                NULL,
-                                G_TYPE_NONE, 1, IDE_TYPE_BUILD_RESULT);
-
+                                G_TYPE_NONE, 1, IDE_TYPE_BUILD_PIPELINE);
+
+  /**
+   * IdeBuildManager::build-finished:
+   * @self: An #IdeBuildManager
+   * @pipeline: An #IdeBuildPipeline
+   *
+   * The "build-finished" signal is emitted when a build completed
+   * successfully.
+   */
   signals [BUILD_FINISHED] =
     g_signal_new_class_handler ("build-finished",
                                 G_TYPE_FROM_CLASS (klass),
                                 G_SIGNAL_RUN_LAST,
                                 G_CALLBACK (ide_build_manager_real_build_finished),
+                                NULL, NULL,
                                 NULL,
-                                NULL,
-                                NULL,
-                                G_TYPE_NONE, 1, IDE_TYPE_BUILD_RESULT);
+                                G_TYPE_NONE, 1, IDE_TYPE_BUILD_PIPELINE);
 }
 
 static void
-ide_build_manager_init (IdeBuildManager *self)
+ide_build_manager_action_cancel (GSimpleAction *action,
+                                 GVariant      *param,
+                                 gpointer       user_data)
 {
-  static const GActionEntry action_entries[] = {
-    { "build", ide_build_manager_build_activate },
-    { "cancel", ide_build_manager_cancel_activate },
-    { "clean", ide_build_manager_clean_activate },
-    { "rebuild", ide_build_manager_rebuild_activate },
-  };
-
-  self->signals = egg_signal_group_new (IDE_TYPE_BUILD_RESULT);
-
-  egg_signal_group_connect_object (self->signals,
-                                   "notify::failed",
-                                   G_CALLBACK (ide_build_manager__build_result__notify_failed),
-                                   self,
-                                   G_CONNECT_SWAPPED);
-
-  egg_signal_group_connect_object (self->signals,
-                                   "notify::mode",
-                                   G_CALLBACK (ide_build_manager__build_result__notify_mode),
-                                   self,
-                                   G_CONNECT_SWAPPED);
-
-  egg_signal_group_connect_object (self->signals,
-                                   "notify::running",
-                                   G_CALLBACK (ide_build_manager__build_result__notify_running),
-                                   self,
-                                   G_CONNECT_SWAPPED);
-
-  egg_signal_group_connect_object (self->signals,
-                                   "notify::running-time",
-                                   G_CALLBACK (ide_build_manager__build_result__notify_running_time),
-                                   self,
-                                   G_CONNECT_SWAPPED);
+  IdeBuildManager *self = user_data;
 
-  egg_signal_group_connect_object (self->signals,
-                                   "diagnostic",
-                                   G_CALLBACK (ide_build_manager__build_result__diagnostic),
-                                   self,
-                                   G_CONNECT_SWAPPED);
+  IDE_ENTRY;
 
-  self->actions = g_simple_action_group_new ();
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (IDE_IS_BUILD_MANAGER (self));
 
-  g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
-                                   action_entries,
-                                   G_N_ELEMENTS (action_entries),
-                                   self);
+  ide_build_manager_cancel (self);
 
-  g_object_bind_property (self,
-                          "busy",
-                          g_action_map_lookup_action (G_ACTION_MAP (self->actions), "build"),
-                          "enabled",
-                          G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
-
-  g_object_bind_property (self,
-                          "busy",
-                          g_action_map_lookup_action (G_ACTION_MAP (self->actions), "rebuild"),
-                          "enabled",
-                          G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
-
-  g_object_bind_property (self,
-                          "busy",
-                          g_action_map_lookup_action (G_ACTION_MAP (self->actions), "clean"),
-                          "enabled",
-                          G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
-
-  g_object_bind_property (self,
-                          "busy",
-                          g_action_map_lookup_action (G_ACTION_MAP (self->actions), "cancel"),
-                          "enabled",
-                          G_BINDING_SYNC_CREATE);
-
-  g_signal_connect_object (self->actions,
-                           "action-enabled-changed",
-                           G_CALLBACK (g_action_group_action_enabled_changed),
-                           self,
-                           G_CONNECT_SWAPPED);
+  IDE_EXIT;
 }
 
 static void
-ide_build_manager_set_build_result (IdeBuildManager *self,
-                                    IdeBuildResult  *build_result)
+ide_build_manager_action_build (GSimpleAction *action,
+                                GVariant      *param,
+                                gpointer       user_data)
 {
+  IdeBuildManager *self = user_data;
+
   IDE_ENTRY;
 
+  g_assert (G_IS_SIMPLE_ACTION (action));
   g_assert (IDE_IS_BUILD_MANAGER (self));
-  g_assert (!build_result || IDE_IS_BUILD_RESULT (build_result));
-
-  if (g_set_object (&self->build_result, build_result))
-    {
-      egg_signal_group_set_target (self->signals, build_result);
-
-      self->has_diagnostics = FALSE;
 
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LAST_BUILD_TIME]);
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MESSAGE]);
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNNING_TIME]);
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HAS_DIAGNOSTICS]);
-
-      g_signal_emit (self, signals [BUILD_STARTED], 0, build_result);
-    }
+  ide_build_manager_execute_async (self, IDE_BUILD_PHASE_BUILD, NULL, NULL, NULL);
 
   IDE_EXIT;
 }
 
-static gboolean
-ide_build_manager_check_busy (IdeBuildManager  *self,
-                              GError          **error)
+static void
+ide_build_manager_action_rebuild (GSimpleAction *action,
+                                  GVariant      *param,
+                                  gpointer       user_data)
 {
+  IdeBuildManager *self = user_data;
+
+  IDE_ENTRY;
+
+  g_assert (G_IS_SIMPLE_ACTION (action));
   g_assert (IDE_IS_BUILD_MANAGER (self));
 
-  if (ide_build_manager_get_busy (self))
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_BUSY,
-                   "%s",
-                   _("A build is already in progress"));
-      return TRUE;
-    }
+  ide_build_manager_rebuild_async (self, IDE_BUILD_PHASE_BUILD, NULL, NULL, NULL);
 
-  return FALSE;
+  IDE_EXIT;
 }
 
-static IdeBuilder *
-ide_build_manager_get_builder (IdeBuildManager  *self,
-                               GError          **error)
+static void
+ide_build_manager_action_clean (GSimpleAction *action,
+                                GVariant      *param,
+                                gpointer       user_data)
 {
-  IdeConfigurationManager *config_manager;
-  IdeConfiguration *config;
-  IdeBuildSystem *build_system;
-  IdeContext *context;
-
-  g_assert (IDE_IS_BUILD_MANAGER (self));
+  IdeBuildManager *self = user_data;
 
-  context = ide_object_get_context (IDE_OBJECT (self));
+  IDE_ENTRY;
 
-  config_manager = ide_context_get_configuration_manager (context);
-  config = ide_configuration_manager_get_current (config_manager);
+  g_assert (G_IS_SIMPLE_ACTION (action));
+  g_assert (IDE_IS_BUILD_MANAGER (self));
 
-  build_system = ide_context_get_build_system (context);
+  ide_build_manager_clean_async (self, IDE_BUILD_PHASE_BUILD, NULL, NULL, NULL);
 
-  return ide_build_system_get_builder (build_system, config, error);
+  IDE_EXIT;
 }
 
 static void
-ide_build_manager_build_cb (GObject      *object,
-                            GAsyncResult *result,
-                            gpointer      user_data)
+ide_build_manager_init (IdeBuildManager *self)
 {
-  IdeBuilder *builder = (IdeBuilder *)object;
-  g_autoptr(IdeBuildResult) build_result = NULL;
-  g_autoptr(GTask) task = user_data;
-  IdeBuildManager *self;
-  GError *error = NULL;
+  static GActionEntry actions[] = {
+    { "build", ide_build_manager_action_build },
+    { "cancel", ide_build_manager_action_cancel },
+    { "clean", ide_build_manager_action_clean },
+    { "rebuild", ide_build_manager_action_rebuild },
+  };
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BUILDER (builder));
-  g_assert (G_IS_TASK (task));
-
-  self = g_task_get_source_object (task);
-  build_result = ide_builder_build_finish (builder, result, &error);
-
-  g_assert (IDE_IS_BUILD_MANAGER (self));
-  g_assert (!build_result || IDE_IS_BUILD_RESULT (build_result));
+  self->actions = G_ACTION_GROUP (g_simple_action_group_new ());
 
-  if (self->build_result != NULL)
-    g_signal_emit (self, signals [BUILD_FINISHED], 0, self->build_result);
-
-  if (build_result == NULL)
-    {
-      IDE_TRACE_MSG ("%s", error->message);
-      g_task_return_error (task, error);
-      IDE_GOTO (failure);
-    }
-
-  g_task_return_boolean (task, TRUE);
+  g_action_map_add_action_entries (G_ACTION_MAP (self->actions),
+                                   actions,
+                                   G_N_ELEMENTS (actions),
+                                   self);
 
-failure:
   IDE_EXIT;
 }
 
-static void
-ide_build_manager_build_save_all_cb (GObject      *object,
-                                     GAsyncResult *result,
-                                     gpointer      user_data)
+/**
+ * ide_build_manager_get_busy:
+ * @self: An #IdeBuildManager
+ *
+ * Gets if the #IdeBuildManager is currently busy building the
+ * project.
+ *
+ * See #IdeBuildManager:busy for more information.
+ */
+gboolean
+ide_build_manager_get_busy (IdeBuildManager *self)
 {
-  IdeBufferManager *buffer_manager = (IdeBufferManager *)object;
-  g_autoptr(IdeBuildResult) build_result = NULL;
-  g_autoptr(GError) error = NULL;
-  g_autoptr(GTask) task = user_data;
-  IdeBuildManager *self = NULL;
-  GCancellable *cancellable;
-  BuildState *state;
+  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), FALSE);
 
-  IDE_ENTRY;
+  if G_LIKELY (self->pipeline != NULL)
+    return ide_build_pipeline_get_busy (self->pipeline);
 
-  g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager));
-  g_assert (G_IS_ASYNC_RESULT (result));
-  g_assert (G_IS_TASK (task));
+  return FALSE;
+}
 
-  if (!ide_buffer_manager_save_all_finish (buffer_manager, result, &error))
-    {
-      g_task_return_error (task, g_steal_pointer (&error));
-      IDE_GOTO (failure);
-    }
+/**
+ * ide_build_manager_get_message:
+ * @self: An #IdeBuildManager
+ *
+ * This function returns the current build message as a string.
+ *
+ * See #IdeBuildManager:message for more information.
+ *
+ * Returns: (transfer full): A string containing the build message or %NULL
+ */
+gchar *
+ide_build_manager_get_message (IdeBuildManager *self)
+{
+  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), NULL);
 
-  self = g_task_get_source_object (task);
-  g_assert (IDE_IS_BUILD_MANAGER (self));
+  if G_LIKELY (self->pipeline != NULL)
+    return ide_build_pipeline_get_message (self->pipeline);
 
-  state = g_task_get_task_data (task);
-  g_assert (state != NULL);
-  g_assert (IDE_IS_BUILDER (state->builder));
+  return NULL;
+}
 
-  cancellable = g_task_get_cancellable (task);
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+/**
+ * ide_build_manager_get_last_build_time:
+ * @self: An #IdeBuildManager
+ *
+ * This function returns a #GDateTime of the last build request. If
+ * there has not yet been a build request, this will return %NULL.
+ *
+ * See #IdeBuildManager:last-build-time for more information.
+ *
+ * Returns: (nullable) (transfer none): A #GDateTime or %NULL.
+ */
+GDateTime *
+ide_build_manager_get_last_build_time (IdeBuildManager *self)
+{
+  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), NULL);
 
-  ide_builder_build_async (state->builder,
-                           state->build_flags,
-                           &build_result,
-                           cancellable,
-                           ide_build_manager_build_cb,
-                           g_steal_pointer (&task));
+  return self->last_build_time;
+}
 
-  ide_build_manager_set_build_result (self, build_result);
+/**
+ * ide_build_manager_get_running_time:
+ *
+ * Gets the amount of elapsed time of the current build as a
+ * #GTimeSpan.
+ *
+ * Returns: A #GTimeSpan containing the elapsed time of the build.
+ */
+GTimeSpan
+ide_build_manager_get_running_time (IdeBuildManager *self)
+{
+  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), 0);
 
-failure:
-  if (self != NULL)
-    {
-      self->saving = FALSE;
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
-    }
+  if (self->running_time != NULL)
+    return g_timer_elapsed (self->running_time, NULL) * G_TIME_SPAN_SECOND;
 
-  IDE_EXIT;
+  return 0;
 }
 
+/**
+ * ide_build_manager_cancel:
+ * @self: An #IdeBuildManager
+ *
+ * This function will cancel any in-flight builds.
+ *
+ * You may also activate this using the "cancel" #GAction provided
+ * by the #GActionGroup interface.
+ */
 void
-ide_build_manager_build_async (IdeBuildManager      *self,
-                               IdeBuildTarget       *build_target,
-                               IdeBuilderBuildFlags  build_flags,
-                               GCancellable         *cancellable,
-                               GAsyncReadyCallback   callback,
-                               gpointer              user_data)
+ide_build_manager_cancel (IdeBuildManager *self)
 {
-  g_autoptr(GTask) task = NULL;
-  g_autoptr(GCancellable) local_cancellable = NULL;
-  g_autoptr(GError) error = NULL;
-  g_autoptr(IdeBuilder) builder = NULL;
-  IdeBufferManager *buffer_manager;
-  IdeContext *context;
-  BuildState *state;
+  g_autoptr(GCancellable) cancellable = NULL;
 
   IDE_ENTRY;
 
   g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
-  g_return_if_fail (!build_target || IDE_IS_BUILD_TARGET (build_target));
-  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  if (cancellable == NULL)
-    cancellable = local_cancellable = g_cancellable_new ();
 
-  task = g_task_new (self, cancellable, callback, user_data);
-  g_task_set_source_tag (task, ide_build_manager_build_async);
+  cancellable = g_steal_pointer (&self->cancellable);
 
-  if (ide_build_manager_check_busy (self, &error))
+  if (cancellable != NULL && !g_cancellable_is_cancelled (cancellable))
     {
-      g_task_return_error (task, g_steal_pointer (&error));
-      IDE_EXIT;
+      g_debug ("Cancelling build due to user request");
+      g_cancellable_cancel (cancellable);
     }
 
-  if (NULL == (builder = ide_build_manager_get_builder (self, &error)))
-    {
-      g_task_return_error (task, g_steal_pointer (&error));
-      IDE_EXIT;
-    }
-
-  state = g_slice_new0 (BuildState);
-  state->builder = g_steal_pointer (&builder);
-  state->build_flags = build_flags;
-  g_task_set_task_data (task, state, build_state_free);
-
-  g_set_object (&self->cancellable, cancellable);
-
-  /*
-   * Before we start any builds, we want to ensure that all of our buffers
-   * have been saved. So first request that the buffer manager take care
-   * of that for us.
-   */
-  self->saving = TRUE;
-  context = ide_object_get_context (IDE_OBJECT (self));
-  buffer_manager = ide_context_get_buffer_manager (context);
-  ide_buffer_manager_save_all_async (buffer_manager,
-                                     cancellable,
-                                     ide_build_manager_build_save_all_cb,
-                                     g_steal_pointer (&task));
-
-  /*
-   * Update our last build time.
-   */
-  g_clear_pointer (&self->last_build_time, g_date_time_unref);
-  self->last_build_time = g_date_time_new_now_local ();
-  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LAST_BUILD_TIME]);
-
   IDE_EXIT;
 }
 
-gboolean
-ide_build_manager_build_finish (IdeBuildManager  *self,
-                                GAsyncResult     *result,
-                                GError          **error)
+/**
+ * ide_build_manager_get_pipeline:
+ * @self: An #IdeBuildManager
+ *
+ * This function gets the current build pipeline. The pipeline will be
+ * reloaded as build configurations change.
+ *
+ * Returns: (transfer none) (nullable): An #IdeBuildPipeline.
+ */
+IdeBuildPipeline *
+ide_build_manager_get_pipeline (IdeBuildManager *self)
 {
-  gboolean ret;
-
-  IDE_ENTRY;
-
-  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), FALSE);
-  g_return_val_if_fail (G_IS_TASK (result), FALSE);
-  g_return_val_if_fail (g_task_is_valid (G_TASK (result), self), FALSE);
-
-  ret = g_task_propagate_boolean (G_TASK (result), error);
+  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), NULL);
 
-  IDE_RETURN (ret);
+  return self->pipeline;
 }
 
 static void
-ide_build_manager_install_cb (GObject      *object,
+ide_build_manager_execute_cb (GObject      *object,
                               GAsyncResult *result,
                               gpointer      user_data)
 {
-  IdeBuilder *builder = (IdeBuilder *)object;
-  g_autoptr(IdeBuildResult) build_result = NULL;
-  g_autoptr(GTask) task = user_data;
+  IdeBuildPipeline *pipeline = (IdeBuildPipeline *)object;
   IdeBuildManager *self;
-  GError *error = NULL;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
 
   IDE_ENTRY;
 
-  g_assert (IDE_IS_BUILDER (builder));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
 
   self = g_task_get_source_object (task);
-  build_result = ide_builder_install_finish (builder, result, &error);
-
   g_assert (IDE_IS_BUILD_MANAGER (self));
-  g_assert (!build_result || IDE_IS_BUILD_RESULT (build_result));
 
-  if (self->build_result != NULL)
-    g_signal_emit (self, signals [BUILD_FINISHED], 0, self->build_result);
-
-  if (build_result == NULL)
+  if (!ide_build_pipeline_execute_finish (pipeline, result, &error))
     {
-      g_task_return_error (task, error);
+      g_task_return_error (task, g_steal_pointer (&error));
       IDE_GOTO (failure);
     }
 
   g_task_return_boolean (task, TRUE);
 
 failure:
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+
   IDE_EXIT;
 }
 
 static void
-ide_build_manager_install_save_all_cb (GObject      *object,
-                                       GAsyncResult *result,
-                                       gpointer      user_data)
+ide_build_manager_save_all_cb (GObject      *object,
+                               GAsyncResult *result,
+                               gpointer      user_data)
 {
   IdeBufferManager *buffer_manager = (IdeBufferManager *)object;
-  g_autoptr(IdeBuildResult) build_result = NULL;
-  g_autoptr(GError) error = NULL;
   g_autoptr(GTask) task = user_data;
-  IdeBuildManager *self = NULL;
+  g_autoptr(GError) error = NULL;
+  IdeBuildManager *self;
   GCancellable *cancellable;
-  BuildState *state;
 
   IDE_ENTRY;
 
   g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager));
-  g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (G_IS_TASK (task));
 
-  if (!ide_buffer_manager_save_all_finish (buffer_manager, result, &error))
-    {
-      g_task_return_error (task, g_steal_pointer (&error));
-      IDE_GOTO (failure);
-    }
-
   self = g_task_get_source_object (task);
-  g_assert (IDE_IS_BUILD_MANAGER (self));
-
-  state = g_task_get_task_data (task);
-  g_assert (state != NULL);
-  g_assert (IDE_IS_BUILDER (state->builder));
-
   cancellable = g_task_get_cancellable (task);
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  /*
-   * We might be able to save some build time if we can limit the target
-   * that needs to be installed. However, it's unclear that we want that
-   * because it could result in incomplete installation unless the build
-   * system compensates for it.
-   */
-
-  ide_builder_install_async (state->builder,
-                             &build_result,
-                             cancellable,
-                             ide_build_manager_install_cb,
-                             g_steal_pointer (&task));
 
-  ide_build_manager_set_build_result (self, build_result);
+  g_assert (IDE_IS_BUILD_MANAGER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-failure:
-  if (self != NULL)
+  if (!ide_buffer_manager_save_all_finish (buffer_manager, result, &error))
     {
-      self->saving = FALSE;
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+      g_task_return_error (task, g_steal_pointer (&error));
+      IDE_EXIT;
     }
 
+  ide_build_pipeline_execute_async (self->pipeline,
+                                    cancellable,
+                                    ide_build_manager_execute_cb,
+                                    g_steal_pointer (&task));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+  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]);
+
   IDE_EXIT;
 }
 
+/**
+ * ide_build_manager_execute_async:
+ * @self: An #IdeBuildManager
+ * @phase: An #IdeBuildPhase or 0
+ * @cancellable: (nullable): A #GCancellable or %NULL
+ * @callback: A callback to execute upon completion
+ * @user_data: user data for @callback
+ *
+ * This function will request that @phase is completed in the underlying
+ * build pipeline and execute a build. Upon completion, @callback will be
+ * executed and it can determine the success or failure of the operation
+ * using ide_build_manager_execute_finish().
+ */
 void
-ide_build_manager_install_async (IdeBuildManager     *self,
+ide_build_manager_execute_async (IdeBuildManager     *self,
+                                 IdeBuildPhase        phase,
                                  GCancellable        *cancellable,
                                  GAsyncReadyCallback  callback,
                                  gpointer             user_data)
 {
   g_autoptr(GTask) task = NULL;
-  g_autoptr(IdeBuilder) builder = NULL;
-  g_autoptr(GError) error = NULL;
-  IdeBufferManager *buffer_manager;
   IdeContext *context;
-  BuildState *state;
+  IdeBufferManager *buffer_manager;
 
   IDE_ENTRY;
 
@@ -818,46 +865,81 @@ ide_build_manager_install_async (IdeBuildManager     *self,
   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_build_manager_install_async);
+  g_task_set_source_tag (task, ide_build_manager_execute_async);
 
-  if (ide_build_manager_check_busy (self, &error))
+  if (self->pipeline == NULL)
     {
-      g_task_return_error (task, g_steal_pointer (&error));
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_PENDING,
+                               "Cannot execute pipeline, it has not yet been prepared");
       IDE_EXIT;
     }
 
-  if (NULL == (builder = ide_build_manager_get_builder (self, &error)))
+  if (!ide_build_pipeline_request_phase (self->pipeline, phase))
     {
-      g_task_return_error (task, g_steal_pointer (&error));
+      g_task_return_boolean (task, TRUE);
       IDE_EXIT;
     }
 
-  state = g_slice_new0 (BuildState);
-  state->builder = g_steal_pointer (&builder);
-  g_task_set_task_data (task, state, build_state_free);
   g_set_object (&self->cancellable, cancellable);
 
-  /* Save the buffers before starting the build. */
-  self->saving = TRUE;
-  context = ide_object_get_context (IDE_OBJECT (self));
-  buffer_manager = ide_context_get_buffer_manager (context);
-  ide_buffer_manager_save_all_async (buffer_manager,
-                                     cancellable,
-                                     ide_build_manager_install_save_all_cb,
-                                     g_steal_pointer (&task));
+  if (self->cancellable == NULL)
+    self->cancellable = g_cancellable_new ();
 
   /*
-   * Update our last build time.
+   * Only update our "build time" if we are advancing to IDE_BUILD_PHASE_BUILD,
+   * we don't really care about "builds" for configure stages and less.
    */
-  g_clear_pointer (&self->last_build_time, g_date_time_unref);
-  self->last_build_time = g_date_time_new_now_local ();
+  if ((phase & IDE_BUILD_PHASE_MASK) >= IDE_BUILD_PHASE_BUILD)
+    {
+      g_clear_pointer (&self->last_build_time, g_date_time_unref);
+      self->last_build_time = g_date_time_new_now_local ();
+      self->diagnostic_count = 0;
+    }
+
+  /*
+   * If we are performing a real build (not just something like configure),
+   * then we want to ensure we save all the buffers. We don't want to do this
+   * on every keypress (and execute_async() could be called on every keypress)
+   * for ensuring build flags are up to date.
+   */
+  if ((phase & IDE_BUILD_PHASE_MASK) >= IDE_BUILD_PHASE_BUILD)
+    {
+      context = ide_object_get_context (IDE_OBJECT (self));
+      buffer_manager = ide_context_get_buffer_manager (context);
+      ide_buffer_manager_save_all_async (buffer_manager,
+                                         self->cancellable,
+                                         ide_build_manager_save_all_cb,
+                                         g_steal_pointer (&task));
+      IDE_EXIT;
+    }
+
+  ide_build_pipeline_execute_async (self->pipeline,
+                                    cancellable,
+                                    ide_build_manager_execute_cb,
+                                    g_steal_pointer (&task));
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+  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]);
 
   IDE_EXIT;
 }
 
+/**
+ * ide_build_manager_execute_finish:
+ * @self: An #IdeBuildManager
+ * @result: A #GAsyncResult
+ * @error: A location for a #GError or %NULL
+ *
+ * Completes a request to ide_build_manager_execute_async().
+ *
+ * Returns: %TRUE if successful, otherwise %FALSE and @error is set.
+ */
 gboolean
-ide_build_manager_install_finish (IdeBuildManager  *self,
+ide_build_manager_execute_finish (IdeBuildManager  *self,
                                   GAsyncResult     *result,
                                   GError          **error)
 {
@@ -867,77 +949,103 @@ ide_build_manager_install_finish (IdeBuildManager  *self,
 
   g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), FALSE);
   g_return_val_if_fail (G_IS_TASK (result), FALSE);
-  g_return_val_if_fail (g_task_is_valid (G_TASK (result), self), FALSE);
 
   ret = g_task_propagate_boolean (G_TASK (result), error);
 
   IDE_RETURN (ret);
 }
 
-gboolean
-ide_build_manager_get_busy (IdeBuildManager *self)
+static void
+ide_build_manager_clean_cb (GObject      *object,
+                            GAsyncResult *result,
+                            gpointer      user_data)
 {
-  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), FALSE);
+  IdeBuildPipeline *pipeline = (IdeBuildPipeline *)object;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+  IdeBuildManager *self;
 
-  if (self->saving)
-    return TRUE;
+  IDE_ENTRY;
 
-  if (self->build_result != NULL)
-    return ide_build_result_get_running (self->build_result);
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
 
-  return FALSE;
+  self = g_task_get_source_object (task);
+  g_assert (IDE_IS_BUILD_MANAGER (self));
+
+  if (!ide_build_pipeline_clean_finish (pipeline, result, &error))
+    {
+      g_task_return_error (task, g_steal_pointer (&error));
+      IDE_GOTO (failure);
+    }
+
+  g_task_return_boolean (task, TRUE);
+
+failure:
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
 }
 
 void
-ide_build_manager_cancel (IdeBuildManager *self)
+ide_build_manager_clean_async (IdeBuildManager     *self,
+                               IdeBuildPhase        phase,
+                               GCancellable        *cancellable,
+                               GAsyncReadyCallback  callback,
+                               gpointer             user_data)
 {
+  g_autoptr(GTask) task = NULL;
+
   IDE_ENTRY;
 
   g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
+  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
 
-  if (self->cancellable != NULL)
-    g_cancellable_cancel (self->cancellable);
+  task = g_task_new (self, cancellable, callback, user_data);
+  g_task_set_source_tag (task, ide_build_manager_clean_async);
 
-  IDE_EXIT;
-}
+  if (self->pipeline == NULL)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_PENDING,
+                               "Cannot execute pipeline, it has not yet been prepared");
+      IDE_EXIT;
+    }
 
-gchar *
-ide_build_manager_get_message (IdeBuildManager *self)
-{
-  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), NULL);
+  g_set_object (&self->cancellable, cancellable);
 
-  if (self->build_result != NULL)
-    return ide_build_result_get_mode (self->build_result);
+  if (self->cancellable == NULL)
+    self->cancellable = g_cancellable_new ();
 
-  return g_strdup (_("Ready"));
-}
+  self->diagnostic_count = 0;
 
-/**
- * ide_build_manager_get_last_build_time:
- * @self: An #IdeBuildManager
- *
- * Gets the time the last build was started. This is %NULL until a build
- * has been executed in the context.
- *
- * Returns: (nullable) (transfer none): A #GDateTime or %NULL.
- */
-GDateTime *
-ide_build_manager_get_last_build_time (IdeBuildManager *self)
-{
-  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), NULL);
+  ide_build_pipeline_clean_async (self->pipeline,
+                                  phase,
+                                  self->cancellable,
+                                  ide_build_manager_clean_cb,
+                                  g_steal_pointer (&task));
 
-  return self->last_build_time;
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
+  g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HAS_DIAGNOSTICS]);
+
+  IDE_EXIT;
 }
 
-GTimeSpan
-ide_build_manager_get_running_time (IdeBuildManager *self)
+gboolean
+ide_build_manager_clean_finish (IdeBuildManager  *self,
+                                GAsyncResult     *result,
+                                GError          **error)
 {
-  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), 0);
+  gboolean ret;
+
+  IDE_ENTRY;
+
+  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
 
-  if (self->build_result == NULL)
-    return 0;
+  ret = g_task_propagate_boolean (G_TASK (result), error);
 
-  return ide_build_result_get_running_time (self->build_result);
+  IDE_RETURN (ret);
 }
 
 static gchar **
@@ -1007,3 +1115,83 @@ action_group_iface_init (GActionGroupInterface *iface)
   iface->change_action_state = ide_build_manager_change_action_state;
   iface->activate_action = ide_build_manager_activate_action;
 }
+
+static void
+ide_build_manager_rebuild_cb (GObject      *object,
+                              GAsyncResult *result,
+                              gpointer      user_data)
+{
+  IdeBuildPipeline *pipeline = (IdeBuildPipeline *)object;
+  g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (G_IS_TASK (task));
+
+  if (!ide_build_pipeline_rebuild_finish (pipeline, result, &error))
+    g_task_return_error (task, g_steal_pointer (&error));
+  else
+    g_task_return_boolean (task, TRUE);
+
+  IDE_EXIT;
+}
+
+void
+ide_build_manager_rebuild_async (IdeBuildManager     *self,
+                                 IdeBuildPhase        phase,
+                                 GCancellable        *cancellable,
+                                 GAsyncReadyCallback  callback,
+                                 gpointer             user_data)
+{
+  g_autoptr(GTask) task = NULL;
+
+  IDE_ENTRY;
+
+  g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
+  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_build_manager_rebuild_async);
+
+  if (self->pipeline == NULL)
+    {
+      g_task_return_new_error (task,
+                               G_IO_ERROR,
+                               G_IO_ERROR_PENDING,
+                               "Cannot execute pipeline, it has not yet been prepared");
+      IDE_EXIT;
+    }
+
+  g_set_object (&self->cancellable, cancellable);
+
+  if (self->cancellable == NULL)
+    self->cancellable = g_cancellable_new ();
+
+  ide_build_pipeline_rebuild_async (self->pipeline,
+                                    phase,
+                                    self->cancellable,
+                                    ide_build_manager_rebuild_cb,
+                                    g_steal_pointer (&task));
+
+  IDE_EXIT;
+}
+
+gboolean
+ide_build_manager_rebuild_finish (IdeBuildManager  *self,
+                                  GAsyncResult     *result,
+                                  GError          **error)
+{
+  gboolean ret;
+
+  IDE_ENTRY;
+
+  g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), FALSE);
+  g_return_val_if_fail (G_IS_TASK (result), FALSE);
+
+  ret = g_task_propagate_boolean (G_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
diff --git a/libide/buildsystem/ide-build-manager.h b/libide/buildsystem/ide-build-manager.h
index ffec27e..5cfc2ff 100644
--- a/libide/buildsystem/ide-build-manager.h
+++ b/libide/buildsystem/ide-build-manager.h
@@ -23,7 +23,7 @@
 
 #include "ide-object.h"
 
-#include "buildsystem/ide-builder.h"
+#include "buildsystem/ide-build-pipeline.h"
 
 G_BEGIN_DECLS
 
@@ -31,27 +31,36 @@ G_BEGIN_DECLS
 
 G_DECLARE_FINAL_TYPE (IdeBuildManager, ide_build_manager, IDE, BUILD_MANAGER, IdeObject)
 
-gboolean   ide_build_manager_get_busy            (IdeBuildManager       *self);
-gchar     *ide_build_manager_get_message         (IdeBuildManager       *self);
-GDateTime *ide_build_manager_get_last_build_time (IdeBuildManager       *self);
-GTimeSpan  ide_build_manager_get_running_time    (IdeBuildManager       *self);
-void       ide_build_manager_cancel              (IdeBuildManager       *self);
-void       ide_build_manager_build_async         (IdeBuildManager       *self,
-                                                  IdeBuildTarget        *build_target,
-                                                  IdeBuilderBuildFlags   build_flags,
-                                                  GCancellable          *cancellable,
-                                                  GAsyncReadyCallback    callback,
-                                                  gpointer               user_data);
-gboolean   ide_build_manager_build_finish        (IdeBuildManager       *self,
-                                                  GAsyncResult          *result,
-                                                  GError               **error);
-void       ide_build_manager_install_async       (IdeBuildManager       *self,
-                                                  GCancellable          *cancellable,
-                                                  GAsyncReadyCallback    callback,
-                                                  gpointer               user_data);
-gboolean   ide_build_manager_install_finish      (IdeBuildManager       *self,
-                                                  GAsyncResult          *result,
-                                                  GError               **error);
+gboolean          ide_build_manager_get_busy            (IdeBuildManager       *self);
+gchar            *ide_build_manager_get_message         (IdeBuildManager       *self);
+GDateTime        *ide_build_manager_get_last_build_time (IdeBuildManager       *self);
+GTimeSpan         ide_build_manager_get_running_time    (IdeBuildManager       *self);
+void              ide_build_manager_cancel              (IdeBuildManager       *self);
+IdeBuildPipeline *ide_build_manager_get_pipeline        (IdeBuildManager       *self);
+void              ide_build_manager_rebuild_async       (IdeBuildManager       *self,
+                                                         IdeBuildPhase          phase,
+                                                         GCancellable          *cancellable,
+                                                         GAsyncReadyCallback    callback,
+                                                         gpointer               user_data);
+gboolean          ide_build_manager_rebuild_finish      (IdeBuildManager       *self,
+                                                         GAsyncResult          *result,
+                                                         GError               **error);
+void              ide_build_manager_execute_async       (IdeBuildManager       *self,
+                                                         IdeBuildPhase          phase,
+                                                         GCancellable          *cancellable,
+                                                         GAsyncReadyCallback    callback,
+                                                         gpointer               user_data);
+gboolean          ide_build_manager_execute_finish      (IdeBuildManager       *self,
+                                                         GAsyncResult          *result,
+                                                         GError               **error);
+void              ide_build_manager_clean_async         (IdeBuildManager       *self,
+                                                         IdeBuildPhase          phase,
+                                                         GCancellable          *cancellable,
+                                                         GAsyncReadyCallback    callback,
+                                                         gpointer               user_data);
+gboolean          ide_build_manager_clean_finish        (IdeBuildManager       *self,
+                                                         GAsyncResult          *result,
+                                                         GError               **error);
 
 G_END_DECLS
 
diff --git a/libide/buildsystem/ide-build-system.c b/libide/buildsystem/ide-build-system.c
index b5a9c1a..7fc855a 100644
--- a/libide/buildsystem/ide-build-system.c
+++ b/libide/buildsystem/ide-build-system.c
@@ -19,13 +19,13 @@
 #define G_LOG_DOMAIN "ide-build-system"
 
 #include "ide-context.h"
+#include "ide-debug.h"
 #include "ide-object.h"
 
 #include "buildsystem/ide-build-system.h"
-#include "buildsystem/ide-builder.h"
 #include "buildsystem/ide-configuration.h"
-#include "buildsystem/ide-configuration-manager.h"
 #include "files/ide-file.h"
+#include "projects/ide-project.h"
 
 G_DEFINE_INTERFACE (IdeBuildSystem, ide_build_system, IDE_TYPE_OBJECT)
 
@@ -53,27 +53,61 @@ ide_build_system_get_priority (IdeBuildSystem *self)
   return 0;
 }
 
-static IdeBuilder *
-ide_build_system_real_get_builder (IdeBuildSystem    *self,
-                                   IdeConfiguration  *configuration,
-                                   GError           **error)
+static void
+ide_build_system_real_get_build_flags_async (IdeBuildSystem      *self,
+                                             IdeFile             *file,
+                                             GCancellable        *cancellable,
+                                             GAsyncReadyCallback  callback,
+                                             gpointer             user_data)
 {
-  g_assert (IDE_IS_BUILD_SYSTEM (self));
-  g_assert (IDE_IS_CONFIGURATION (configuration));
+  g_task_report_new_error (self,
+                           callback,
+                           user_data,
+                           ide_build_system_real_get_build_flags_async,
+                           G_IO_ERROR,
+                           G_IO_ERROR_NOT_SUPPORTED,
+                           "Fetching build flags is not supported");
+}
 
-  g_set_error (error,
-               G_IO_ERROR,
-               G_IO_ERROR_NOT_SUPPORTED,
-               "%s() is not supported on %s build system.",
-               G_STRFUNC, G_OBJECT_TYPE_NAME (self));
+static gchar **
+ide_build_system_real_get_build_flags_finish (IdeBuildSystem  *self,
+                                              GAsyncResult    *result,
+                                              GError         **error)
+{
+  return g_task_propagate_pointer (G_TASK (result), error);
+}
 
-  return NULL;
+static void
+ide_build_system_real_get_build_targets_async (IdeBuildSystem      *self,
+                                               GCancellable        *cancellable,
+                                               GAsyncReadyCallback  callback,
+                                               gpointer             user_data)
+{
+  g_task_report_new_error (self,
+                           callback,
+                           user_data,
+                           ide_build_system_real_get_build_targets_async,
+                           G_IO_ERROR,
+                           G_IO_ERROR_NOT_SUPPORTED,
+                           "Fetching build targets is not supported");
+}
+
+static GPtrArray *
+ide_build_system_real_get_build_targets_finish (IdeBuildSystem  *self,
+                                                GAsyncResult    *result,
+                                                GError         **error)
+{
+  return g_task_propagate_pointer (G_TASK (result), error);
 }
 
 static void
 ide_build_system_default_init (IdeBuildSystemInterface *iface)
 {
-  iface->get_builder = ide_build_system_real_get_builder;
+  iface->get_build_flags_async = ide_build_system_real_get_build_flags_async;
+  iface->get_build_flags_finish = ide_build_system_real_get_build_flags_finish;
+  iface->get_build_targets_finish = ide_build_system_real_get_build_targets_finish;
+  iface->get_build_targets_async = ide_build_system_real_get_build_targets_async;
+  iface->get_build_targets_finish = ide_build_system_real_get_build_targets_finish;
 
   properties [PROP_PROJECT_FILE] =
     g_param_spec_object ("project-file",
@@ -161,81 +195,6 @@ ide_build_system_new_finish (GAsyncResult  *result,
   return ret ? IDE_BUILD_SYSTEM (ret) : NULL;
 }
 
-/**
- * ide_build_system_get_builder:
- * @system: The #IdeBuildSystem to perform the build.
- * @configuration: An #IdeConfiguration.
- *
- * This function returns an #IdeBuilder that can be used to perform a
- * build of the project using the configuration specified.
- *
- * See ide_builder_build_async() for more information.
- *
- * Returns: (transfer full): An #IdeBuilder or %NULL and @error is set.
- */
-IdeBuilder *
-ide_build_system_get_builder (IdeBuildSystem    *system,
-                              IdeConfiguration  *configuration,
-                              GError           **error)
-{
-  IdeBuilder *ret;
-
-  g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (system), NULL);
-  g_return_val_if_fail (IDE_IS_CONFIGURATION (configuration), NULL);
-
-  ret = IDE_BUILD_SYSTEM_GET_IFACE (system)->get_builder (system, configuration, error);
-
-  if (ret != NULL)
-    {
-      IdeContext *context;
-
-      context = ide_object_get_context (IDE_OBJECT (system));
-      ide_context_hold_for_object (context, ret);
-    }
-
-  return ret;
-}
-
-static IdeBuilder *
-get_default_builder (IdeBuildSystem  *self,
-                     GError         **error)
-{
-  IdeConfigurationManager *config_manager;
-  IdeConfiguration *config;
-  IdeContext *context;
-
-  g_assert (IDE_IS_BUILD_SYSTEM (self));
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-  g_assert (IDE_IS_CONTEXT (context));
-
-  config_manager = ide_context_get_configuration_manager (context);
-  g_assert (IDE_IS_CONFIGURATION_MANAGER (config_manager));
-
-  config = ide_configuration_manager_get_current (config_manager);
-  g_assert (IDE_IS_CONFIGURATION (config));
-
-  return ide_build_system_get_builder (IDE_BUILD_SYSTEM (self), config, error);
-}
-
-static void
-ide_build_system_get_build_flags_cb (GObject      *object,
-                                     GAsyncResult *result,
-                                     gpointer      user_data)
-{
-  IdeBuilder *builder = (IdeBuilder *)object;
-  g_autoptr(GTask) task = user_data;
-  g_autoptr(GError) error = NULL;
-  g_auto(GStrv) flags = NULL;
-
-  g_assert (IDE_IS_BUILDER (builder));
-
-  if (NULL == (flags = ide_builder_get_build_flags_finish (builder, result, &error)))
-    g_task_return_error (task, g_steal_pointer (&error));
-  else
-    g_task_return_pointer (task, g_steal_pointer (&flags), (GDestroyNotify)g_strfreev);
-}
-
 void
 ide_build_system_get_build_flags_async (IdeBuildSystem      *self,
                                         IdeFile             *file,
@@ -243,28 +202,15 @@ ide_build_system_get_build_flags_async (IdeBuildSystem      *self,
                                         GAsyncReadyCallback  callback,
                                         gpointer             user_data)
 {
-  g_autoptr(GTask) task = NULL;
-  g_autoptr(IdeBuilder) builder = NULL;
-  g_autoptr(GError) error = NULL;
+  IDE_ENTRY;
 
   g_return_if_fail (IDE_IS_BUILD_SYSTEM (self));
   g_return_if_fail (IDE_IS_FILE (file));
   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_build_system_get_build_flags_async);
+  IDE_BUILD_SYSTEM_GET_IFACE (self)->get_build_flags_async (self, file, cancellable, callback, user_data);
 
-  if (NULL == (builder = get_default_builder (self, &error)))
-    {
-      g_task_return_error (task, g_steal_pointer (&error));
-      return;
-    }
-
-  ide_builder_get_build_flags_async (builder,
-                                     file,
-                                     cancellable,
-                                     ide_build_system_get_build_flags_cb,
-                                     g_steal_pointer (&task));
+  IDE_EXIT;
 }
 
 /**
@@ -277,28 +223,16 @@ ide_build_system_get_build_flags_finish (IdeBuildSystem  *self,
                                          GAsyncResult    *result,
                                          GError         **error)
 {
-  g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
-  g_return_val_if_fail (G_IS_TASK (result), NULL);
+  gchar **ret;
 
-  return g_task_propagate_pointer (G_TASK (result), error);
-}
+  IDE_ENTRY;
 
-static void
-ide_build_system_get_build_targets_cb (GObject      *object,
-                                       GAsyncResult *result,
-                                       gpointer      user_data)
-{
-  IdeBuilder *builder = (IdeBuilder *)object;
-  g_autoptr(GTask) task = user_data;
-  g_autoptr(GPtrArray) targets = NULL;
-  g_autoptr(GError) error = NULL;
+  g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
+  g_return_val_if_fail (G_IS_TASK (result), NULL);
 
-  g_assert (IDE_IS_BUILDER (builder));
+  ret = IDE_BUILD_SYSTEM_GET_IFACE (self)->get_build_flags_finish (self, result, error);
 
-  if (NULL == (targets = ide_builder_get_build_targets_finish (builder, result, &error)))
-    g_task_return_error (task, g_steal_pointer (&error));
-  else
-    g_task_return_pointer (task, g_steal_pointer (&targets), (GDestroyNotify)g_ptr_array_unref);
+  IDE_RETURN (ret);
 }
 
 void
@@ -307,26 +241,14 @@ ide_build_system_get_build_targets_async (IdeBuildSystem      *self,
                                           GAsyncReadyCallback  callback,
                                           gpointer             user_data)
 {
-  g_autoptr(GTask) task = NULL;
-  g_autoptr(IdeBuilder) builder = NULL;
-  g_autoptr(GError) error = NULL;
+  IDE_ENTRY;
 
   g_return_if_fail (IDE_IS_BUILD_SYSTEM (self));
   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_build_system_get_build_targets_async);
-
-  if (NULL == (builder = get_default_builder (self, &error)))
-    {
-      g_task_return_error (task, g_steal_pointer (&error));
-      return;
-    }
+  IDE_BUILD_SYSTEM_GET_IFACE (self)->get_build_targets_async (self, cancellable, callback, user_data);
 
-  ide_builder_get_build_targets_async (builder,
-                                       cancellable,
-                                       ide_build_system_get_build_targets_cb,
-                                       g_steal_pointer (&task));
+  IDE_EXIT;
 }
 
 /**
@@ -340,8 +262,58 @@ ide_build_system_get_build_targets_finish (IdeBuildSystem  *self,
                                            GAsyncResult    *result,
                                            GError         **error)
 {
+  GPtrArray *ret;
+
+  IDE_ENTRY;
+
   g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
   g_return_val_if_fail (G_IS_TASK (result), NULL);
 
-  return g_task_propagate_pointer (G_TASK (result), error);
+  ret = IDE_BUILD_SYSTEM_GET_IFACE (self)->get_build_targets_finish (self, result, error);
+
+  IDE_RETURN (ret);
+}
+
+gchar *
+ide_build_system_get_builddir (IdeBuildSystem   *self,
+                               IdeConfiguration *configuration)
+{
+  gchar *ret = NULL;
+
+  IDE_ENTRY;
+
+  g_return_val_if_fail (IDE_IS_BUILD_SYSTEM (self), NULL);
+  g_return_val_if_fail (IDE_IS_CONFIGURATION (configuration), NULL);
+
+  if (IDE_BUILD_SYSTEM_GET_IFACE (self)->get_builddir)
+    ret = IDE_BUILD_SYSTEM_GET_IFACE (self)->get_builddir (self, configuration);
+
+  if (ret == NULL)
+    {
+      g_autofree gchar *name = NULL;
+      const gchar *project_id;
+      const gchar *config_id;
+      const gchar *device_id;
+      const gchar *runtime_id;
+      IdeContext *context;
+      IdeProject *project;
+
+      context = ide_object_get_context (IDE_OBJECT (self));
+      project = ide_context_get_project (context);
+      project_id = ide_project_get_id (project);
+      config_id = ide_configuration_get_id (configuration);
+      device_id = ide_configuration_get_device_id (configuration);
+      runtime_id = ide_configuration_get_runtime_id (configuration);
+
+      name = g_strdup_printf ("%s-%s-%s", config_id, device_id, runtime_id);
+
+      ret = g_build_filename (g_get_user_cache_dir (),
+                              "gnome-builder",
+                              "builds",
+                              project_id,
+                              name,
+                              NULL);
+    }
+
+  IDE_RETURN (ret);
 }
diff --git a/libide/buildsystem/ide-build-system.h b/libide/buildsystem/ide-build-system.h
index b1b779e..1fd05af 100644
--- a/libide/buildsystem/ide-build-system.h
+++ b/libide/buildsystem/ide-build-system.h
@@ -33,13 +33,26 @@ struct _IdeBuildSystemInterface
 {
   GTypeInterface parent_iface;
 
-  gint             (*get_priority) (IdeBuildSystem       *system);
-  IdeBuilder      *(*get_builder)  (IdeBuildSystem       *system,
-                                    IdeConfiguration     *configuration,
-                                    GError              **error);
+  gint        (*get_priority)             (IdeBuildSystem       *self);
+  void        (*get_build_flags_async)    (IdeBuildSystem       *self,
+                                           IdeFile              *file,
+                                           GCancellable         *cancellable,
+                                           GAsyncReadyCallback   callback,
+                                           gpointer              user_data);
+  gchar     **(*get_build_flags_finish)   (IdeBuildSystem       *self,
+                                           GAsyncResult         *result,
+                                           GError              **error);
+  void        (*get_build_targets_async)  (IdeBuildSystem       *self,
+                                           GCancellable         *cancellable,
+                                           GAsyncReadyCallback   callback,
+                                           gpointer              user_data);
+  GPtrArray  *(*get_build_targets_finish) (IdeBuildSystem       *self,
+                                           GAsyncResult         *result,
+                                           GError              **error);
+  gchar      *(*get_builddir)             (IdeBuildSystem       *self,
+                                           IdeConfiguration     *configuration);
 };
 
-gint            ide_build_system_get_priority             (IdeBuildSystem       *self);
 void            ide_build_system_new_async                (IdeContext           *context,
                                                            GFile                *project_file,
                                                            GCancellable         *cancellable,
@@ -47,15 +60,9 @@ void            ide_build_system_new_async                (IdeContext
                                                            gpointer              user_data);
 IdeBuildSystem *ide_build_system_new_finish               (GAsyncResult         *result,
                                                            GError              **error);
-IdeBuilder     *ide_build_system_get_builder              (IdeBuildSystem       *system,
-                                                           IdeConfiguration     *configuration,
-                                                           GError              **error);
-
-/*
- * The following is convenience API for the legacy design to allow
- * querying using the current IdeConfiguration.
- */
-
+gint            ide_build_system_get_priority             (IdeBuildSystem       *self);
+gchar          *ide_build_system_get_builddir             (IdeBuildSystem       *self,
+                                                           IdeConfiguration     *configuration);
 void            ide_build_system_get_build_flags_async    (IdeBuildSystem       *self,
                                                            IdeFile              *file,
                                                            GCancellable         *cancellable,
diff --git a/libide/directory/ide-directory-build-system.c b/libide/directory/ide-directory-build-system.c
index 7a25d9a..54bedaa 100644
--- a/libide/directory/ide-directory-build-system.c
+++ b/libide/directory/ide-directory-build-system.c
@@ -22,9 +22,6 @@
 
 #include "ide-context.h"
 
-#include "buildsystem/ide-configuration-manager.h"
-#include "buildsystem/ide-configuration.h"
-#include "buildsystem/ide-simple-builder.h"
 #include "directory/ide-directory-build-system.h"
 #include "projects/ide-project-file.h"
 #include "projects/ide-project-item.h"
@@ -176,28 +173,8 @@ ide_directory_build_system_get_priority (IdeBuildSystem *build_system)
   return 1000000;
 }
 
-static IdeBuilder *
-ide_directory_build_system_get_builder (IdeBuildSystem    *build_system,
-                                        IdeConfiguration  *configuration,
-                                        GError           **error)
-{
-  IdeDirectoryBuildSystem *self = (IdeDirectoryBuildSystem *)build_system;
-  IdeContext *context;
-
-  g_assert (IDE_IS_DIRECTORY_BUILD_SYSTEM (self));
-  g_assert (IDE_IS_CONFIGURATION (configuration));
-
-  context = ide_object_get_context (IDE_OBJECT (build_system));
-
-  return g_object_new (IDE_TYPE_SIMPLE_BUILDER,
-                       "configuration", configuration,
-                       "context", context,
-                       NULL);
-}
-
 static void
 build_system_init (IdeBuildSystemInterface *iface)
 {
   iface->get_priority = ide_directory_build_system_get_priority;
-  iface->get_builder = ide_directory_build_system_get_builder;
 }
diff --git a/libide/ide-context.c b/libide/ide-context.c
index 693dea8..3b89c90 100644
--- a/libide/ide-context.c
+++ b/libide/ide-context.c
@@ -1463,6 +1463,27 @@ ide_context_init_diagnostics_manager (gpointer             source_object,
 }
 
 static void
+ide_context_init_build_manager (gpointer             source_object,
+                                GCancellable        *cancellable,
+                                GAsyncReadyCallback  callback,
+                                gpointer             user_data)
+{
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GTask) task = NULL;
+  IdeContext *self = source_object;
+
+  g_assert (IDE_IS_CONTEXT (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = g_task_new (self, cancellable, callback, user_data);
+
+  if (!g_initable_init (G_INITABLE (self->build_manager), cancellable, &error))
+    g_task_return_error (task, g_steal_pointer (&error));
+  else
+    g_task_return_boolean (task, TRUE);
+}
+
+static void
 ide_context_init_loaded (gpointer             source_object,
                          GCancellable        *cancellable,
                          GAsyncReadyCallback  callback,
@@ -1507,6 +1528,7 @@ ide_context_init_async (GAsyncInitable      *initable,
                         ide_context_init_search_engine,
                         ide_context_init_runtimes,
                         ide_context_init_configuration_manager,
+                        ide_context_init_build_manager,
                         ide_context_init_diagnostics_manager,
                         ide_context_init_loaded,
                         NULL);
diff --git a/libide/ide-enums.c.in b/libide/ide-enums.c.in
index f6aba69..5013750 100644
--- a/libide/ide-enums.c.in
+++ b/libide/ide-enums.c.in
@@ -7,7 +7,6 @@
 #include "buffers/ide-buffer.h"
 #include "buildsystem/ide-build-log.h"
 #include "buildsystem/ide-build-pipeline.h"
-#include "buildsystem/ide-build-result.h"
 #include "devices/ide-device.h"
 #include "diagnostics/ide-diagnostic.h"
 #include "doap/ide-doap.h"
diff --git a/libide/ide.h b/libide/ide.h
index 467c0d9..00a2ce0 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -44,16 +44,12 @@ G_BEGIN_DECLS
 #include "buildsystem/ide-build-stage-launcher.h"
 #include "buildsystem/ide-build-stage-mkdirs.h"
 #include "buildsystem/ide-build-stage-transfer.h"
-#include "buildsystem/ide-build-result-addin.h"
-#include "buildsystem/ide-build-result.h"
 #include "buildsystem/ide-build-system.h"
 #include "buildsystem/ide-build-target.h"
-#include "buildsystem/ide-builder.h"
 #include "buildsystem/ide-configuration-manager.h"
 #include "buildsystem/ide-configuration.h"
 #include "buildsystem/ide-environment-variable.h"
 #include "buildsystem/ide-environment.h"
-#include "buildsystem/ide-simple-builder.h"
 #include "devices/ide-device-manager.h"
 #include "devices/ide-device-provider.h"
 #include "devices/ide-device.h"
diff --git a/libide/runner/ide-run-manager.c b/libide/runner/ide-run-manager.c
index 1792f9b..c5d7ad4 100644
--- a/libide/runner/ide-run-manager.c
+++ b/libide/runner/ide-run-manager.c
@@ -382,26 +382,27 @@ ide_run_manager_install_cb (GObject      *object,
 {
   IdeBuildManager *build_manager = (IdeBuildManager *)object;
   g_autoptr(GTask) task = user_data;
+  g_autoptr(GError) error = NULL;
   IdeRunManager *self;
   IdeBuildTarget *build_target;
   GCancellable *cancellable;
-  GError *error = NULL;
 
   IDE_ENTRY;
 
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
   g_assert (G_IS_TASK (task));
 
-  if (!ide_build_manager_build_finish (build_manager, result, &error))
+  self = g_task_get_source_object (task);
+  g_assert (IDE_IS_RUN_MANAGER (self));
+
+  if (!ide_build_manager_execute_finish (build_manager, result, &error))
     {
-      g_task_return_error (task, error);
+      g_task_return_error (task, g_steal_pointer (&error));
       IDE_EXIT;
     }
 
-  self = g_task_get_source_object (task);
-  g_assert (IDE_IS_RUN_MANAGER (self));
-
   build_target = ide_run_manager_get_build_target (self);
+
   if (build_target == NULL)
     {
       cancellable = g_task_get_cancellable (task);
@@ -474,7 +475,8 @@ ide_run_manager_do_install_before_run (IdeRunManager *self,
                            self,
                            G_CONNECT_SWAPPED);
 
-  ide_build_manager_install_async (build_manager,
+  ide_build_manager_execute_async (build_manager,
+                                   IDE_BUILD_PHASE_INSTALL,
                                    g_task_get_cancellable (task),
                                    ide_run_manager_install_cb,
                                    g_object_ref (task));
diff --git a/libide/runtimes/ide-runtime.c b/libide/runtimes/ide-runtime.c
index 1476e0e..104040b 100644
--- a/libide/runtimes/ide-runtime.c
+++ b/libide/runtimes/ide-runtime.c
@@ -21,7 +21,6 @@
 #include "ide-context.h"
 #include "ide-debug.h"
 
-#include "buildsystem/ide-builder.h"
 #include "buildsystem/ide-configuration.h"
 #include "projects/ide-project.h"
 #include "runtimes/ide-runtime.h"
@@ -43,87 +42,6 @@ enum {
 
 static GParamSpec *properties [N_PROPS];
 
-static void
-ide_runtime_real_prebuild_async (IdeRuntime          *self,
-                                 IdeBuildResult      *build_result,
-                                 GCancellable        *cancellable,
-                                 GAsyncReadyCallback  callback,
-                                 gpointer             user_data)
-{
-  g_autoptr(GTask) task = NULL;
-
-  g_assert (IDE_IS_RUNTIME (self));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  task = g_task_new (self, cancellable, callback, user_data);
-  g_task_return_boolean (task, TRUE);
-}
-
-static gboolean
-ide_runtime_real_prebuild_finish (IdeRuntime    *self,
-                                  GAsyncResult  *result,
-                                  GError       **error)
-{
-  g_assert (IDE_IS_RUNTIME (self));
-  g_assert (G_IS_TASK (result));
-
-  return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-ide_runtime_real_postbuild_async (IdeRuntime          *self,
-                                  IdeBuildResult      *build_result,
-                                  GCancellable        *cancellable,
-                                  GAsyncReadyCallback  callback,
-                                  gpointer             user_data)
-{
-  g_autoptr(GTask) task = NULL;
-
-  g_assert (IDE_IS_RUNTIME (self));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  task = g_task_new (self, cancellable, callback, user_data);
-  g_task_return_boolean (task, TRUE);
-}
-
-static gboolean
-ide_runtime_real_postbuild_finish (IdeRuntime    *self,
-                                   GAsyncResult  *result,
-                                   GError       **error)
-{
-  g_assert (IDE_IS_RUNTIME (self));
-  g_assert (G_IS_TASK (result));
-
-  return g_task_propagate_boolean (G_TASK (result), error);
-}
-
-static void
-ide_runtime_real_postinstall_async (IdeRuntime          *self,
-                                    IdeBuildResult      *build_result,
-                                    GCancellable        *cancellable,
-                                    GAsyncReadyCallback  callback,
-                                    gpointer             user_data)
-{
-  g_autoptr(GTask) task = NULL;
-
-  g_assert (IDE_IS_RUNTIME (self));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  task = g_task_new (self, cancellable, callback, user_data);
-  g_task_return_boolean (task, TRUE);
-}
-
-static gboolean
-ide_runtime_real_postinstall_finish (IdeRuntime    *self,
-                                     GAsyncResult  *result,
-                                     GError       **error)
-{
-  g_assert (IDE_IS_RUNTIME (self));
-  g_assert (G_IS_TASK (result));
-
-  return g_task_propagate_boolean (G_TASK (result), error);
-}
-
 static IdeSubprocessLauncher *
 ide_runtime_real_create_launcher (IdeRuntime  *self,
                                   GError     **error)
@@ -337,12 +255,6 @@ ide_runtime_class_init (IdeRuntimeClass *klass)
   object_class->get_property = ide_runtime_get_property;
   object_class->set_property = ide_runtime_set_property;
 
-  klass->prebuild_async = ide_runtime_real_prebuild_async;
-  klass->prebuild_finish = ide_runtime_real_prebuild_finish;
-  klass->postbuild_async = ide_runtime_real_postbuild_async;
-  klass->postbuild_finish = ide_runtime_real_postbuild_finish;
-  klass->postinstall_async = ide_runtime_real_postinstall_async;
-  klass->postinstall_finish = ide_runtime_real_postinstall_finish;
   klass->create_launcher = ide_runtime_real_create_launcher;
   klass->create_runner = ide_runtime_real_create_runner;
   klass->contains_program_in_path = ide_runtime_real_contains_program_in_path;
@@ -440,83 +352,12 @@ ide_runtime_new (IdeContext  *context,
                        NULL);
 }
 
-void
-ide_runtime_prebuild_async (IdeRuntime          *self,
-                            IdeBuildResult      *build_result,
-                            GCancellable        *cancellable,
-                            GAsyncReadyCallback  callback,
-                            gpointer             user_data)
-{
-  g_return_if_fail (IDE_IS_RUNTIME (self));
-  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  IDE_RUNTIME_GET_CLASS (self)->prebuild_async (self, build_result, cancellable, callback, user_data);
-}
-
-gboolean
-ide_runtime_prebuild_finish (IdeRuntime    *self,
-                             GAsyncResult  *result,
-                             GError       **error)
-{
-  g_return_val_if_fail (IDE_IS_RUNTIME (self), FALSE);
-
-  return IDE_RUNTIME_GET_CLASS (self)->prebuild_finish (self, result, error);
-}
-
-void
-ide_runtime_postbuild_async (IdeRuntime          *self,
-                             IdeBuildResult      *build_result,
-                             GCancellable        *cancellable,
-                             GAsyncReadyCallback  callback,
-                             gpointer             user_data)
-{
-  g_return_if_fail (IDE_IS_RUNTIME (self));
-  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  IDE_RUNTIME_GET_CLASS (self)->postbuild_async (self, build_result, cancellable, callback, user_data);
-}
-
-gboolean
-ide_runtime_postbuild_finish (IdeRuntime    *self,
-                              GAsyncResult  *result,
-                              GError       **error)
-{
-  g_return_val_if_fail (IDE_IS_RUNTIME (self), FALSE);
-
-  return IDE_RUNTIME_GET_CLASS (self)->postbuild_finish (self, result, error);
-}
-
-void
-ide_runtime_postinstall_async (IdeRuntime          *self,
-                               IdeBuildResult      *build_result,
-                               GCancellable        *cancellable,
-                               GAsyncReadyCallback  callback,
-                               gpointer             user_data)
-{
-  g_return_if_fail (IDE_IS_RUNTIME (self));
-  g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
-
-  IDE_RUNTIME_GET_CLASS (self)->postinstall_async (self, build_result, cancellable, callback, user_data);
-}
-
-gboolean
-ide_runtime_postinstall_finish (IdeRuntime    *self,
-                                GAsyncResult  *result,
-                                GError       **error)
-{
-  g_return_val_if_fail (IDE_IS_RUNTIME (self), FALSE);
-
-  return IDE_RUNTIME_GET_CLASS (self)->postinstall_finish (self, result, error);
-}
-
 /**
  * ide_runtime_create_launcher:
  *
  * Creates a launcher for the runtime.
  *
  * This can be used to execute a command within a runtime.
- * If you are doing a build, you probably want to ensure you call
- * ide_runtime_prebuild_async() before using the launcher.
  *
  * It is important that this function can be run from a thread without
  * side effects.
diff --git a/libide/runtimes/ide-runtime.h b/libide/runtimes/ide-runtime.h
index 533a7ee..9bcadae 100644
--- a/libide/runtimes/ide-runtime.h
+++ b/libide/runtimes/ide-runtime.h
@@ -43,22 +43,6 @@ struct _IdeRuntimeClass
 {
   IdeObjectClass parent;
 
-  void                   (*prebuild_async)           (IdeRuntime           *self,
-                                                      IdeBuildResult       *build_result,
-                                                      GCancellable         *cancellable,
-                                                      GAsyncReadyCallback   callback,
-                                                      gpointer              user_data);
-  gboolean               (*prebuild_finish)          (IdeRuntime           *self,
-                                                      GAsyncResult         *result,
-                                                      GError              **error);
-  void                   (*postbuild_async)          (IdeRuntime           *self,
-                                                      IdeBuildResult       *build_result,
-                                                      GCancellable         *cancellable,
-                                                      GAsyncReadyCallback   callback,
-                                                      gpointer              user_data);
-  gboolean               (*postbuild_finish)         (IdeRuntime           *self,
-                                                      GAsyncResult         *result,
-                                                      GError              **error);
   gboolean               (*contains_program_in_path) (IdeRuntime           *self,
                                                       const gchar          *program,
                                                       GCancellable         *cancellable);
@@ -68,14 +52,6 @@ struct _IdeRuntimeClass
                                                       IdeConfiguration     *configuration);
   IdeRunner             *(*create_runner)            (IdeRuntime           *self,
                                                       IdeBuildTarget       *build_target);
-  void                   (*postinstall_async)        (IdeRuntime           *self,
-                                                      IdeBuildResult       *build_result,
-                                                      GCancellable         *cancellable,
-                                                      GAsyncReadyCallback   callback,
-                                                      gpointer              user_data);
-  gboolean               (*postinstall_finish)       (IdeRuntime           *self,
-                                                      GAsyncResult         *result,
-                                                      GError              **error);
   GFile                 *(*translate_file)           (IdeRuntime           *self,
                                                       GFile                *file);
 
@@ -95,30 +71,6 @@ struct _IdeRuntimeClass
 };
 
 GQuark                 ide_runtime_error_quark              (void) G_GNUC_CONST;
-void                   ide_runtime_prebuild_async           (IdeRuntime           *self,
-                                                             IdeBuildResult       *build_result,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-gboolean               ide_runtime_prebuild_finish          (IdeRuntime           *self,
-                                                             GAsyncResult         *result,
-                                                             GError              **error);
-void                   ide_runtime_postbuild_async          (IdeRuntime           *self,
-                                                             IdeBuildResult       *build_result,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-gboolean               ide_runtime_postbuild_finish         (IdeRuntime           *self,
-                                                             GAsyncResult         *result,
-                                                             GError              **error);
-void                   ide_runtime_postinstall_async        (IdeRuntime           *self,
-                                                             IdeBuildResult       *build_result,
-                                                             GCancellable         *cancellable,
-                                                             GAsyncReadyCallback   callback,
-                                                             gpointer              user_data);
-gboolean               ide_runtime_postinstall_finish       (IdeRuntime           *self,
-                                                             GAsyncResult         *result,
-                                                             GError              **error);
 gboolean               ide_runtime_contains_program_in_path (IdeRuntime           *self,
                                                              const gchar          *program,
                                                              GCancellable         *cancellable);
diff --git a/libide/workbench/ide-omni-bar.c b/libide/workbench/ide-omni-bar.c
index ef03eaa..2b1d3dc 100644
--- a/libide/workbench/ide-omni-bar.c
+++ b/libide/workbench/ide-omni-bar.c
@@ -26,10 +26,11 @@
 #include "ide-debug.h"
 
 #include "buildsystem/ide-build-manager.h"
-#include "buildsystem/ide-build-result.h"
+#include "buildsystem/ide-build-pipeline.h"
 #include "buildsystem/ide-configuration.h"
 #include "buildsystem/ide-configuration-manager.h"
 #include "projects/ide-project.h"
+#include "util/ide-glib.h"
 #include "util/ide-gtk.h"
 #include "vcs/ide-vcs.h"
 #include "workbench/ide-omni-bar.h"
@@ -88,11 +89,6 @@ struct _IdeOmniBar
   EggBindingGroup *vcs_bindings;
 
   /*
-   * This is the IdeBuildResult for the last requested built.
-   */
-  IdeBuildResult *build_result;
-
-  /*
    * This tracks the number of times we have shown the current build
    * message while looping between the various messages. After our
    * SETTLE_MESSAGE_COUNT has been reached, we stop flapping between
@@ -101,6 +97,12 @@ struct _IdeOmniBar
   guint seen_count;
 
   /*
+   * Just tracks if we have already done a build so we can change
+   * how we display user messages.
+   */
+  guint did_build : 1;
+
+  /*
    * The following are template children from the GtkBuilder template.
    */
   GtkLabel       *branch_label;
@@ -151,32 +153,20 @@ date_time_to_label (GBinding     *binding,
 }
 
 static gboolean
-time_span_to_label (GBinding     *binding,
-                    const GValue *from_value,
-                    GValue       *to_value,
-                    gpointer      user_data)
+message_to_label (GBinding     *binding,
+                  const GValue *from_value,
+                  GValue       *to_value,
+                  gpointer      user_data)
 {
-  GTimeSpan span;
-
   g_assert (G_IS_BINDING (binding));
   g_assert (from_value != NULL);
-  g_assert (G_VALUE_HOLDS (from_value, G_TYPE_INT64));
+  g_assert (G_VALUE_HOLDS (from_value, G_TYPE_STRING));
   g_assert (to_value != NULL);
   g_assert (G_VALUE_HOLDS (to_value, G_TYPE_STRING));
 
-  if (0 != (span = g_value_get_int64 (from_value)))
-    {
-      guint hours;
-      guint minutes;
-      guint seconds;
-
-      hours = span / G_TIME_SPAN_HOUR;
-      minutes = (span % G_TIME_SPAN_HOUR) / G_TIME_SPAN_MINUTE;
-      seconds = (span % G_TIME_SPAN_MINUTE) / G_TIME_SPAN_SECOND;
-
-      g_value_take_string (to_value,
-                           g_strdup_printf ("%02u:%02u:%02u", hours, minutes, seconds));
-    }
+  g_value_take_string (to_value,
+                       /* translators: this message is shown in the header bar to indicate build status */
+                       g_strdup_printf (_("Build: %s"), g_value_get_string (from_value)));
 
   return TRUE;
 }
@@ -455,10 +445,17 @@ event_box_leave_notify (IdeOmniBar  *self,
 static void
 ide_omni_bar_next_message (IdeOmniBar *self)
 {
+  IdeBuildManager *build_manager;
   const gchar *name;
+  IdeContext *context;
 
   g_assert (IDE_IS_OMNI_BAR (self));
 
+  if (NULL == (context = ide_widget_get_context (GTK_WIDGET (self))))
+    return;
+
+  build_manager = ide_context_get_build_manager (context);
+
   name = gtk_stack_get_visible_child_name (self->message_stack);
 
   /*
@@ -473,10 +470,10 @@ ide_omni_bar_next_message (IdeOmniBar *self)
       /* Only rotate to build result if we have one and we haven't
        * flapped too many times.
        */
-      if (self->build_result != NULL && self->seen_count < 2)
+      if (self->did_build && self->seen_count < 2)
         gtk_stack_set_visible_child_name (self->message_stack, "build");
     }
-  else if (!ide_build_result_get_running (self->build_result))
+  else if (!ide_build_manager_get_busy (build_manager))
     {
       self->seen_count++;
       gtk_stack_set_visible_child_name (self->message_stack, "config");
@@ -551,33 +548,32 @@ ide_omni_bar_popover_closed (IdeOmniBar *self,
 }
 
 static void
-ide_omni_bar__build_manager__build_started (IdeOmniBar      *self,
-                                            IdeBuildResult  *build_result,
-                                            IdeBuildManager *build_manager)
+ide_omni_bar__build_manager__build_started (IdeOmniBar       *self,
+                                            IdeBuildPipeline *build_pipeline,
+                                            IdeBuildManager  *build_manager)
 {
   g_assert (IDE_IS_OMNI_BAR (self));
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  g_assert (IDE_IS_BUILD_PIPELINE (build_pipeline));
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
 
+  self->did_build = TRUE;
+  self->seen_count = 0;
+
   gtk_widget_hide (GTK_WIDGET (self->popover_failed_label));
   gtk_widget_show (GTK_WIDGET (self->popover_build_cancel_button));
 
-  g_set_object (&self->build_result, build_result);
-
-  self->seen_count = 0;
-
   gtk_stack_set_visible_child_name (self->popover_time_stack, "current-build");
 
   gtk_revealer_set_reveal_child (self->popover_details_revealer, TRUE);
 }
 
 static void
-ide_omni_bar__build_manager__build_failed (IdeOmniBar      *self,
-                                           IdeBuildResult  *build_result,
-                                           IdeBuildManager *build_manager)
+ide_omni_bar__build_manager__build_failed (IdeOmniBar       *self,
+                                           IdeBuildPipeline *build_pipeline,
+                                           IdeBuildManager  *build_manager)
 {
   g_assert (IDE_IS_OMNI_BAR (self));
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  g_assert (IDE_IS_BUILD_PIPELINE (build_pipeline));
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
 
   gtk_widget_set_visible (GTK_WIDGET (self->popover_failed_label), TRUE);
@@ -588,12 +584,12 @@ ide_omni_bar__build_manager__build_failed (IdeOmniBar      *self,
 }
 
 static void
-ide_omni_bar__build_manager__build_finished (IdeOmniBar      *self,
-                                             IdeBuildResult  *build_result,
-                                             IdeBuildManager *build_manager)
+ide_omni_bar__build_manager__build_finished (IdeOmniBar       *self,
+                                             IdeBuildPipeline *build_pipeline,
+                                             IdeBuildManager  *build_manager)
 {
   g_assert (IDE_IS_OMNI_BAR (self));
-  g_assert (IDE_IS_BUILD_RESULT (build_result));
+  g_assert (IDE_IS_BUILD_PIPELINE (build_pipeline));
   g_assert (IDE_IS_BUILD_MANAGER (build_manager));
 
   gtk_widget_hide (GTK_WIDGET (self->popover_build_cancel_button));
@@ -606,7 +602,6 @@ ide_omni_bar_finalize (GObject *object)
 {
   IdeOmniBar *self = (IdeOmniBar *)object;
 
-  g_clear_object (&self->build_result);
   g_clear_object (&self->build_manager_bindings);
   g_clear_object (&self->build_manager_signals);
   g_clear_object (&self->config_manager_bindings);
@@ -707,11 +702,13 @@ ide_omni_bar_init (IdeOmniBar *self)
                                NULL,
                                NULL);
 
-  egg_binding_group_bind (self->build_manager_bindings,
-                          "message",
-                          self->build_result_mode_label,
-                          "label",
-                          G_BINDING_SYNC_CREATE);
+  egg_binding_group_bind_full (self->build_manager_bindings,
+                               "message",
+                               self->build_result_mode_label,
+                               "label",
+                               G_BINDING_SYNC_CREATE,
+                               message_to_label,
+                               NULL, NULL, NULL);
 
   egg_binding_group_bind (self->build_manager_bindings,
                           "message",
@@ -724,7 +721,7 @@ ide_omni_bar_init (IdeOmniBar *self)
                                self->popover_build_running_time_label,
                                "label",
                                G_BINDING_SYNC_CREATE,
-                               time_span_to_label,
+                               ide_g_time_span_to_label_mapping,
                                NULL,
                                NULL,
                                NULL);


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