Commit 19516480 authored by Christian Hergert's avatar Christian Hergert Committed by Matthew Leeds
Browse files

build-tools: port to IdeBuildPipeline

This updates the build tools plugin to use the build pipeline to track
build progress and logging.
parent 1553ca89
......@@ -29,8 +29,7 @@ struct _GbpBuildLogPanel
{
PnlDockWidget parent_instance;
IdeBuildResult *result;
EggSignalGroup *signals;
IdeBuildPipeline *pipeline;
GtkCssProvider *css;
GSettings *settings;
GtkTextBuffer *buffer;
......@@ -38,11 +37,13 @@ struct _GbpBuildLogPanel
GtkScrolledWindow *scroller;
GtkTextView *text_view;
GtkTextTag *stderr_tag;
guint log_observer;
};
enum {
PROP_0,
PROP_RESULT,
PROP_PIPELINE,
LAST_PROP
};
......@@ -87,23 +88,26 @@ gbp_build_log_panel_reset_view (GbpBuildLogPanel *self)
}
static void
gbp_build_log_panel_log (GbpBuildLogPanel *self,
IdeBuildResultLog log,
const gchar *message,
IdeBuildResult *result)
gbp_build_log_panel_log_observer (IdeBuildLogStream stream,
const gchar *message,
gssize message_len,
gpointer user_data)
{
GbpBuildLogPanel *self = user_data;
GtkTextMark *insert;
GtkTextIter iter;
g_assert (GBP_IS_BUILD_LOG_PANEL (self));
g_assert (message != NULL);
g_assert (IDE_IS_BUILD_RESULT (result));
g_assert (message_len >= 0);
g_assert (message[message_len] == '\0');
gtk_text_buffer_get_end_iter (self->buffer, &iter);
if (G_LIKELY (log == IDE_BUILD_RESULT_LOG_STDOUT))
if G_LIKELY (stream == IDE_BUILD_LOG_STDOUT)
{
gtk_text_buffer_insert (self->buffer, &iter, message, -1);
gtk_text_buffer_insert (self->buffer, &iter, "\n", 1);
}
else
{
......@@ -112,6 +116,7 @@ gbp_build_log_panel_log (GbpBuildLogPanel *self,
offset = gtk_text_iter_get_offset (&iter);
gtk_text_buffer_insert (self->buffer, &iter, message, -1);
gtk_text_buffer_insert (self->buffer, &iter, "\n", 1);
gtk_text_buffer_get_iter_at_offset (self->buffer, &begin, offset);
gtk_text_buffer_apply_tag (self->buffer, self->stderr_tag, &begin, &iter);
}
......@@ -121,16 +126,30 @@ gbp_build_log_panel_log (GbpBuildLogPanel *self,
}
void
gbp_build_log_panel_set_result (GbpBuildLogPanel *self,
IdeBuildResult *result)
gbp_build_log_panel_set_pipeline (GbpBuildLogPanel *self,
IdeBuildPipeline *pipeline)
{
g_return_if_fail (GBP_IS_BUILD_LOG_PANEL (self));
g_return_if_fail (!result || IDE_IS_BUILD_RESULT (result));
g_return_if_fail (!pipeline || IDE_IS_BUILD_PIPELINE (pipeline));
if (g_set_object (&self->result, result))
if (pipeline != self->pipeline)
{
gbp_build_log_panel_reset_view (self);
egg_signal_group_set_target (self->signals, result);
if (self->pipeline != NULL)
{
ide_build_pipeline_remove_log_observer (self->pipeline, self->log_observer);
self->log_observer = 0;
g_clear_object (&self->pipeline);
}
if (pipeline != NULL)
{
self->pipeline = g_object_ref (pipeline);
self->log_observer =
ide_build_pipeline_add_log_observer (self->pipeline,
gbp_build_log_panel_log_observer,
self,
NULL);
}
}
}
......@@ -174,14 +193,23 @@ gbp_build_log_panel_finalize (GObject *object)
self->stderr_tag = NULL;
g_clear_object (&self->result);
g_clear_object (&self->signals);
g_clear_object (&self->pipeline);
g_clear_object (&self->css);
g_clear_object (&self->settings);
G_OBJECT_CLASS (gbp_build_log_panel_parent_class)->finalize (object);
}
static void
gbp_build_log_panel_dispose (GObject *object)
{
GbpBuildLogPanel *self = (GbpBuildLogPanel *)object;
gbp_build_log_panel_set_pipeline (self, NULL);
G_OBJECT_CLASS (gbp_build_log_panel_parent_class)->dispose (object);
}
static void
gbp_build_log_panel_get_property (GObject *object,
guint prop_id,
......@@ -192,8 +220,8 @@ gbp_build_log_panel_get_property (GObject *object,
switch (prop_id)
{
case PROP_RESULT:
g_value_set_object (value, self->result);
case PROP_PIPELINE:
g_value_set_object (value, self->pipeline);
break;
default:
......@@ -211,8 +239,8 @@ gbp_build_log_panel_set_property (GObject *object,
switch (prop_id)
{
case PROP_RESULT:
gbp_build_log_panel_set_result (self, g_value_get_object (value));
case PROP_PIPELINE:
gbp_build_log_panel_set_pipeline (self, g_value_get_object (value));
break;
default:
......@@ -226,6 +254,7 @@ gbp_build_log_panel_class_init (GbpBuildLogPanelClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = gbp_build_log_panel_dispose;
object_class->finalize = gbp_build_log_panel_finalize;
object_class->get_property = gbp_build_log_panel_get_property;
object_class->set_property = gbp_build_log_panel_set_property;
......@@ -234,11 +263,11 @@ gbp_build_log_panel_class_init (GbpBuildLogPanelClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/plugins/build-tools-plugin/gbp-build-log-panel.ui");
gtk_widget_class_bind_template_child (widget_class, GbpBuildLogPanel, scroller);
properties [PROP_RESULT] =
g_param_spec_object ("result",
properties [PROP_PIPELINE] =
g_param_spec_object ("pipeline",
"Result",
"Result",
IDE_TYPE_BUILD_RESULT,
IDE_TYPE_BUILD_PIPELINE,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_properties (object_class, LAST_PROP, properties);
......@@ -255,14 +284,6 @@ gbp_build_log_panel_init (GbpBuildLogPanel *self)
gbp_build_log_panel_reset_view (self);
self->signals = egg_signal_group_new (IDE_TYPE_BUILD_RESULT);
egg_signal_group_connect_object (self->signals,
"log",
G_CALLBACK (gbp_build_log_panel_log),
self,
G_CONNECT_SWAPPED);
self->settings = g_settings_new ("org.gnome.builder.terminal");
g_signal_connect_object (self->settings,
"changed::font-name",
......
......@@ -19,7 +19,6 @@
#ifndef GBP_BUILD_LOG_PANEL_H
#define GBP_BUILD_LOG_PANEL_H
#include <gtk/gtk.h>
#include <ide.h>
G_BEGIN_DECLS
......@@ -28,8 +27,8 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GbpBuildLogPanel, gbp_build_log_panel, GBP, BUILD_LOG_PANEL, PnlDockWidget)
void gbp_build_log_panel_set_result (GbpBuildLogPanel *self,
IdeBuildResult *result);
void gbp_build_log_panel_set_pipeline (GbpBuildLogPanel *self,
IdeBuildPipeline *pipeline);
G_END_DECLS
......
......@@ -19,19 +19,14 @@
#include <glib/gi18n.h>
#include <ide.h>
#include "egg-binding-group.h"
#include "egg-signal-group.h"
#include "gbp-build-panel.h"
struct _GbpBuildPanel
{
PnlDockWidget parent_instance;
IdeBuildResult *result;
EggSignalGroup *signals;
EggBindingGroup *bindings;
GHashTable *diags_hash;
IdeBuildPipeline *pipeline;
GtkListStore *diagnostics_store;
GtkCellRendererText *diagnostics_text;
......@@ -50,24 +45,24 @@ struct _GbpBuildPanel
G_DEFINE_TYPE (GbpBuildPanel, gbp_build_panel, PNL_TYPE_DOCK_WIDGET)
enum {
PROP_0,
PROP_RESULT,
LAST_PROP
};
enum {
COLUMN_DIAGNOSTIC,
COLUMN_TEXT,
LAST_COLUMN
};
static GParamSpec *properties [LAST_PROP];
enum {
PROP_0,
PROP_PIPELINE,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
static void
gbp_build_panel_diagnostic (GbpBuildPanel *self,
IdeDiagnostic *diagnostic,
IdeBuildResult *result)
gbp_build_panel_diagnostic (GbpBuildPanel *self,
IdeDiagnostic *diagnostic,
IdeBuildPipeline *pipeline)
{
IdeDiagnosticSeverity severity;
guint hash;
......@@ -76,7 +71,7 @@ gbp_build_panel_diagnostic (GbpBuildPanel *self,
g_assert (GBP_IS_BUILD_PANEL (self));
g_assert (diagnostic != NULL);
g_assert (IDE_IS_BUILD_RESULT (result));
g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
severity = ide_diagnostic_get_severity (diagnostic);
......@@ -151,49 +146,73 @@ gbp_build_panel_diagnostic (GbpBuildPanel *self,
static void
gbp_build_panel_update_running_time (GbpBuildPanel *self)
{
g_autofree gchar *text = NULL;
g_assert (GBP_IS_BUILD_PANEL (self));
if (self->result != NULL)
if (self->pipeline != NULL)
{
IdeBuildManager *build_manager;
IdeContext *context;
GTimeSpan span;
guint hours;
guint minutes;
guint seconds;
gchar *text;
span = ide_build_result_get_running_time (self->result);
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;
context = ide_widget_get_context (GTK_WIDGET (self));
build_manager = ide_context_get_build_manager (context);
text = g_strdup_printf ("%02u:%02u:%02u", hours, minutes, seconds);
gtk_label_set_label (self->running_time_label, text);
g_free (text);
}
else
{
gtk_label_set_label (self->running_time_label, NULL);
span = ide_build_manager_get_running_time (build_manager);
text = ide_g_time_span_to_label (span);
}
gtk_label_set_label (self->running_time_label, text);
}
static void
gbp_build_panel_connect (GbpBuildPanel *self,
IdeBuildResult *result)
gbp_build_panel_started (GbpBuildPanel *self,
IdeBuildPipeline *pipeline)
{
IDE_ENTRY;
g_assert (GBP_IS_BUILD_PANEL (self));
g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
self->error_count = 0;
self->warning_count = 0;
gtk_label_set_label (self->warnings_label, "—");
gtk_label_set_label (self->errors_label, "—");
gtk_list_store_clear (self->diagnostics_store);
g_hash_table_remove_all (self->diags_hash);
IDE_EXIT;
}
static void
gbp_build_panel_connect (GbpBuildPanel *self,
IdeBuildPipeline *pipeline)
{
g_return_if_fail (GBP_IS_BUILD_PANEL (self));
g_return_if_fail (IDE_IS_BUILD_RESULT (result));
g_return_if_fail (self->result == NULL);
g_return_if_fail (IDE_IS_BUILD_PIPELINE (pipeline));
g_return_if_fail (self->pipeline == NULL);
self->result = g_object_ref (result);
self->pipeline = g_object_ref (pipeline);
self->error_count = 0;
self->warning_count = 0;
gtk_label_set_label (self->warnings_label, "—");
gtk_label_set_label (self->errors_label, "—");
egg_signal_group_set_target (self->signals, result);
egg_binding_group_set_source (self->bindings, result);
g_signal_connect_object (pipeline,
"diagnostic",
G_CALLBACK (gbp_build_panel_diagnostic),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (pipeline,
"started",
G_CALLBACK (gbp_build_panel_started),
self,
G_CONNECT_SWAPPED);
gtk_revealer_set_reveal_child (self->status_revealer, TRUE);
......@@ -204,56 +223,37 @@ static void
gbp_build_panel_disconnect (GbpBuildPanel *self)
{
g_return_if_fail (GBP_IS_BUILD_PANEL (self));
g_return_if_fail (IDE_IS_BUILD_PIPELINE (self->pipeline));
g_signal_handlers_disconnect_by_func (self->pipeline,
G_CALLBACK (gbp_build_panel_diagnostic),
self);
g_clear_object (&self->pipeline);
gtk_revealer_set_reveal_child (self->status_revealer, FALSE);
egg_signal_group_set_target (self->signals, NULL);
egg_binding_group_set_source (self->bindings, NULL);
g_clear_object (&self->result);
g_hash_table_remove_all (self->diags_hash);
gtk_list_store_clear (self->diagnostics_store);
gtk_stack_set_visible_child_name (self->stack, "empty-state");
}
void
gbp_build_panel_set_result (GbpBuildPanel *self,
IdeBuildResult *result)
gbp_build_panel_set_pipeline (GbpBuildPanel *self,
IdeBuildPipeline *pipeline)
{
g_return_if_fail (GBP_IS_BUILD_PANEL (self));
g_return_if_fail (!result || IDE_IS_BUILD_RESULT (result));
g_return_if_fail (!pipeline || IDE_IS_BUILD_PIPELINE (pipeline));
if (result != self->result)
if (pipeline != self->pipeline)
{
if (self->result)
if (self->pipeline)
gbp_build_panel_disconnect (self);
if (result)
gbp_build_panel_connect (self, result);
if (pipeline)
gbp_build_panel_connect (self, pipeline);
}
}
static void
gbp_build_panel_notify_running (GbpBuildPanel *self,
GParamSpec *pspec,
IdeBuildResult *result)
{
g_assert (GBP_IS_BUILD_PANEL (self));
g_assert (IDE_IS_BUILD_RESULT (result));
gbp_build_panel_update_running_time (self);
}
static void
gbp_build_panel_notify_running_time (GbpBuildPanel *self,
GParamSpec *pspec,
IdeBuildResult *result)
{
g_assert (GBP_IS_BUILD_PANEL (self));
g_assert (IDE_IS_BUILD_RESULT (result));
gbp_build_panel_update_running_time (self);
}
static void
gbp_build_panel_diagnostic_activated (GbpBuildPanel *self,
GtkTreePath *path,
......@@ -370,16 +370,62 @@ gbp_build_panel_text_func (GtkCellLayout *layout,
g_object_set_property (G_OBJECT (renderer), "text", &value);
}
static void
gbp_build_panel_context_handler (GtkWidget *widget,
IdeContext *context)
{
GbpBuildPanel *self = (GbpBuildPanel *)widget;
IdeBuildManager *build_manager;
IDE_ENTRY;
g_assert (GBP_IS_BUILD_PANEL (self));
g_assert (!context || IDE_IS_CONTEXT (context));
if (context == NULL)
IDE_EXIT;
build_manager = ide_context_get_build_manager (context);
g_object_bind_property (build_manager, "message",
self->status_label, "label",
G_BINDING_SYNC_CREATE);
g_signal_connect_object (build_manager,
"notify::running-time",
G_CALLBACK (gbp_build_panel_update_running_time),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (build_manager,
"build-started",
G_CALLBACK (gbp_build_panel_update_running_time),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (build_manager,
"build-finished",
G_CALLBACK (gbp_build_panel_update_running_time),
self,
G_CONNECT_SWAPPED);
g_signal_connect_object (build_manager,
"build-failed",
G_CALLBACK (gbp_build_panel_update_running_time),
self,
G_CONNECT_SWAPPED);
IDE_EXIT;
}
static void
gbp_build_panel_destroy (GtkWidget *widget)
{
GbpBuildPanel *self = (GbpBuildPanel *)widget;
if (self->result)
if (self->pipeline != NULL)
gbp_build_panel_disconnect (self);
g_clear_object (&self->bindings);
g_clear_object (&self->signals);
g_clear_pointer (&self->diags_hash, g_hash_table_unref);
GTK_WIDGET_CLASS (gbp_build_panel_parent_class)->destroy (widget);
......@@ -391,16 +437,16 @@ gbp_build_panel_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
GbpBuildPanel *self = GBP_BUILD_PANEL(object);
GbpBuildPanel *self = GBP_BUILD_PANEL (object);
switch (prop_id)
{
case PROP_RESULT:
g_value_set_object (value, self->result);
case PROP_PIPELINE:
g_value_set_object (value, self->pipeline);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
......@@ -410,16 +456,16 @@ gbp_build_panel_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
GbpBuildPanel *self = GBP_BUILD_PANEL(object);
GbpBuildPanel *self = GBP_BUILD_PANEL (object);
switch (prop_id)
{
case PROP_RESULT:
gbp_build_panel_set_result (self, g_value_get_object (value));
case PROP_PIPELINE:
gbp_build_panel_set_pipeline (self, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
......@@ -429,19 +475,19 @@ gbp_build_panel_class_init (GbpBuildPanelClass *klass)
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
widget_class->destroy = gbp_build_panel_destroy;
object_class->get_property = gbp_build_panel_get_property;
object_class->set_property = gbp_build_panel_set_property;
widget_class->destroy = gbp_build_panel_destroy;
properties [PROP_RESULT] =
g_param_spec_object ("result",
"Result",
"Result",
IDE_TYPE_BUILD_RESULT,
(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
properties [PROP_PIPELINE] =
g_param_spec_object ("pipeline",
NULL,
NULL,
IDE_TYPE_BUILD_PIPELINE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, LAST_PROP, properties);
g_object_class_install_properties (object_class, N_PROPS, properties);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/builder/plugins/build-tools-plugin/gbp-build-panel.ui");
gtk_widget_class_set_css_name (widget_class, "buildpanel");
......@@ -468,25 +514,7 @@ gbp_build_panel_init (GbpBuildPanel *self)
g_object_set (self, "title", _("Build"), NULL);
self->signals = egg_signal_group_new (IDE_TYPE_BUILD_RESULT);
egg_signal_group_connect_object (self->signals,
"diagnostic",
G_CALLBACK (gbp_build_panel_diagnostic),
self,
G_CONNECT_SWAPPED);
egg_signal_group_connect_object (self->signals,
"notify::running",
G_CALLBACK (gbp_build_panel_notify_running),
self,
G_CONNECT_SWAPPED);
egg_signal_group_connect_object (self->signals,
"notify::running-time",
G_CALLBACK (gbp_build_panel_notify_running_time),
self,
G_CONNECT_SWAPPED);
ide_widget_set_context_handler (self, gbp_build_panel_context_handler);
g_signal_connect_object (self->diagnostics_tree_view,
"row-activated",
......@@ -498,10 +526,4 @@ gbp_build_panel_init (GbpBuildPanel *self)
GTK_CELL_RENDERER (self->diagnostics_text),
gbp_build_panel_text_func,
self, NULL);
self->bindings = egg_binding_group_new ();
egg_binding_group_bind (self->bindings, "mode", self->status_label, "label",
G_BINDING_SYNC_CREATE);
}