1903 lines
56 KiB
C
1903 lines
56 KiB
C
|
/* ide-build-manager.c
|
||
|
*
|
||
|
* Copyright 2016-2019 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
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||
|
*/
|
||
|
|
||
|
#define G_LOG_DOMAIN "ide-build-manager"
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#include <dazzle.h>
|
||
|
#include <glib/gi18n.h>
|
||
|
#include <libide-code.h>
|
||
|
#include <libide-threading.h>
|
||
|
#include <libide-vcs.h>
|
||
|
|
||
|
#include "ide-build-manager.h"
|
||
|
#include "ide-build-private.h"
|
||
|
#include "ide-config-manager.h"
|
||
|
#include "ide-config.h"
|
||
|
#include "ide-device-info.h"
|
||
|
#include "ide-device-manager.h"
|
||
|
#include "ide-device.h"
|
||
|
#include "ide-foundry-compat.h"
|
||
|
#include "ide-pipeline.h"
|
||
|
#include "ide-run-manager.h"
|
||
|
#include "ide-runtime-manager.h"
|
||
|
#include "ide-runtime-private.h"
|
||
|
#include "ide-runtime.h"
|
||
|
#include "ide-toolchain-manager.h"
|
||
|
#include "ide-toolchain-private.h"
|
||
|
|
||
|
/**
|
||
|
* SECTION:ide-build-manager
|
||
|
* @title: IdeBuildManager
|
||
|
* @short_description: Manages the active build configuration and pipeline
|
||
|
*
|
||
|
* The #IdeBuildManager is responsible for managing the active build pipeline
|
||
|
* as well as providing common high-level actions to plugins.
|
||
|
*
|
||
|
* You can use various async operations such as
|
||
|
* ide_build_manager_build_async(), ide_build_manager_clean_async(), or
|
||
|
* ide_build_manager_rebuild_async() to build, clean, and rebuild respectively
|
||
|
* without needing to track the build pipeline.
|
||
|
*
|
||
|
* The #IdePipeline is used to specify how and when build operations
|
||
|
* should occur. Plugins attach build stages to the pipeline to perform
|
||
|
* build actions.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
|
||
|
struct _IdeBuildManager
|
||
|
{
|
||
|
IdeObject parent_instance;
|
||
|
|
||
|
GCancellable *cancellable;
|
||
|
|
||
|
IdePipeline *pipeline;
|
||
|
GDateTime *last_build_time;
|
||
|
DzlSignalGroup *pipeline_signals;
|
||
|
|
||
|
gchar *branch_name;
|
||
|
|
||
|
GTimer *running_time;
|
||
|
|
||
|
guint diagnostic_count;
|
||
|
guint error_count;
|
||
|
guint warning_count;
|
||
|
|
||
|
guint timer_source;
|
||
|
|
||
|
guint started : 1;
|
||
|
guint can_build : 1;
|
||
|
guint can_export : 1;
|
||
|
guint building : 1;
|
||
|
guint needs_rediagnose : 1;
|
||
|
guint has_configured : 1;
|
||
|
};
|
||
|
|
||
|
static void initable_iface_init (GInitableIface *iface);
|
||
|
static void ide_build_manager_set_can_build (IdeBuildManager *self,
|
||
|
gboolean can_build);
|
||
|
static void ide_build_manager_action_build (IdeBuildManager *self,
|
||
|
GVariant *param);
|
||
|
static void ide_build_manager_action_rebuild (IdeBuildManager *self,
|
||
|
GVariant *param);
|
||
|
static void ide_build_manager_action_cancel (IdeBuildManager *self,
|
||
|
GVariant *param);
|
||
|
static void ide_build_manager_action_clean (IdeBuildManager *self,
|
||
|
GVariant *param);
|
||
|
static void ide_build_manager_action_export (IdeBuildManager *self,
|
||
|
GVariant *param);
|
||
|
static void ide_build_manager_action_install (IdeBuildManager *self,
|
||
|
GVariant *param);
|
||
|
|
||
|
DZL_DEFINE_ACTION_GROUP (IdeBuildManager, ide_build_manager, {
|
||
|
{ "build", ide_build_manager_action_build },
|
||
|
{ "cancel", ide_build_manager_action_cancel },
|
||
|
{ "clean", ide_build_manager_action_clean },
|
||
|
{ "export", ide_build_manager_action_export },
|
||
|
{ "install", ide_build_manager_action_install },
|
||
|
{ "rebuild", ide_build_manager_action_rebuild },
|
||
|
})
|
||
|
|
||
|
G_DEFINE_TYPE_EXTENDED (IdeBuildManager, ide_build_manager, IDE_TYPE_OBJECT, G_TYPE_FLAG_FINAL,
|
||
|
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
|
||
|
G_IMPLEMENT_INTERFACE (G_TYPE_ACTION_GROUP,
|
||
|
ide_build_manager_init_action_group))
|
||
|
|
||
|
enum {
|
||
|
PROP_0,
|
||
|
PROP_BUSY,
|
||
|
PROP_CAN_BUILD,
|
||
|
PROP_ERROR_COUNT,
|
||
|
PROP_HAS_DIAGNOSTICS,
|
||
|
PROP_LAST_BUILD_TIME,
|
||
|
PROP_MESSAGE,
|
||
|
PROP_PIPELINE,
|
||
|
PROP_RUNNING_TIME,
|
||
|
PROP_WARNING_COUNT,
|
||
|
N_PROPS
|
||
|
};
|
||
|
|
||
|
enum {
|
||
|
BUILD_STARTED,
|
||
|
BUILD_FINISHED,
|
||
|
BUILD_FAILED,
|
||
|
N_SIGNALS
|
||
|
};
|
||
|
|
||
|
static GParamSpec *properties [N_PROPS];
|
||
|
static guint signals [N_SIGNALS];
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_rediagnose (IdeBuildManager *self)
|
||
|
{
|
||
|
IdeDiagnosticsManager *diagnostics;
|
||
|
IdeBufferManager *buffer_manager;
|
||
|
IdeContext *context;
|
||
|
guint n_items;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
context = ide_object_get_context (IDE_OBJECT (self));
|
||
|
buffer_manager = ide_buffer_manager_from_context (context);
|
||
|
diagnostics = ide_diagnostics_manager_from_context (context);
|
||
|
n_items = g_list_model_get_n_items (G_LIST_MODEL (buffer_manager));
|
||
|
|
||
|
for (guint i = 0; i < n_items; i++)
|
||
|
{
|
||
|
g_autoptr(IdeBuffer) buffer = g_list_model_get_item (G_LIST_MODEL (buffer_manager), i);
|
||
|
|
||
|
ide_diagnostics_manager_rediagnose (diagnostics, buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
timer_callback (gpointer data)
|
||
|
{
|
||
|
IdeBuildManager *self = data;
|
||
|
|
||
|
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_start_timer (IdeBuildManager *self)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (self->timer_source == 0);
|
||
|
|
||
|
if (self->running_time != NULL)
|
||
|
g_timer_start (self->running_time);
|
||
|
else
|
||
|
self->running_time = g_timer_new ();
|
||
|
|
||
|
/*
|
||
|
* We use the DzlFrameSource 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_stop_timer (IdeBuildManager *self)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
dzl_clear_source (&self->timer_source);
|
||
|
|
||
|
if (self->running_time != NULL)
|
||
|
{
|
||
|
g_timer_stop (self->running_time);
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNNING_TIME]);
|
||
|
}
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_reset_info (IdeBuildManager *self)
|
||
|
{
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
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;
|
||
|
self->warning_count = 0;
|
||
|
self->error_count = 0;
|
||
|
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ERROR_COUNT]);
|
||
|
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]);
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_WARNING_COUNT]);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_handle_diagnostic (IdeBuildManager *self,
|
||
|
IdeDiagnostic *diagnostic,
|
||
|
IdePipeline *pipeline)
|
||
|
{
|
||
|
IdeDiagnosticSeverity severity;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (diagnostic != NULL);
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
self->diagnostic_count++;
|
||
|
if (self->diagnostic_count == 1)
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HAS_DIAGNOSTICS]);
|
||
|
|
||
|
severity = ide_diagnostic_get_severity (diagnostic);
|
||
|
|
||
|
if (severity == IDE_DIAGNOSTIC_WARNING)
|
||
|
{
|
||
|
self->warning_count++;
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_WARNING_COUNT]);
|
||
|
}
|
||
|
else if (severity == IDE_DIAGNOSTIC_ERROR || severity == IDE_DIAGNOSTIC_FATAL)
|
||
|
{
|
||
|
self->error_count++;
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ERROR_COUNT]);
|
||
|
}
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_update_action_enabled (IdeBuildManager *self)
|
||
|
{
|
||
|
gboolean busy;
|
||
|
gboolean can_build;
|
||
|
gboolean can_export;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
busy = ide_build_manager_get_busy (self);
|
||
|
can_build = ide_build_manager_get_can_build (self);
|
||
|
can_export = self->pipeline ? ide_pipeline_get_can_export (self->pipeline) : FALSE;
|
||
|
|
||
|
ide_build_manager_set_action_enabled (self, "build", !busy && can_build);
|
||
|
ide_build_manager_set_action_enabled (self, "cancel", busy);
|
||
|
ide_build_manager_set_action_enabled (self, "clean", !busy && can_build);
|
||
|
ide_build_manager_set_action_enabled (self, "export", !busy && can_build && can_export);
|
||
|
ide_build_manager_set_action_enabled (self, "install", !busy && can_build);
|
||
|
ide_build_manager_set_action_enabled (self, "rebuild", !busy && can_build);
|
||
|
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUSY]);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_notify_busy (IdeBuildManager *self,
|
||
|
GParamSpec *pspec,
|
||
|
IdePipeline *pipeline)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (G_IS_PARAM_SPEC (pspec));
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
ide_build_manager_update_action_enabled (self);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_notify_message (IdeBuildManager *self,
|
||
|
GParamSpec *pspec,
|
||
|
IdePipeline *pipeline)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (G_IS_PARAM_SPEC (pspec));
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
if (pipeline == self->pipeline)
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_MESSAGE]);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_pipeline_started (IdeBuildManager *self,
|
||
|
IdePipelinePhase phase,
|
||
|
IdePipeline *pipeline)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
self->building = TRUE;
|
||
|
|
||
|
g_signal_emit (self, signals [BUILD_STARTED], 0, pipeline);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_pipeline_finished (IdeBuildManager *self,
|
||
|
gboolean failed,
|
||
|
IdePipeline *pipeline)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
self->building = FALSE;
|
||
|
|
||
|
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_ensure_toolchain_cb (GObject *object,
|
||
|
GAsyncResult *result,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
IdeToolchainManager *toolchain_manager = (IdeToolchainManager *)object;
|
||
|
g_autoptr(GError) error = NULL;
|
||
|
g_autoptr(IdeTask) task = user_data;
|
||
|
IdePipeline *pipeline;
|
||
|
IdeBuildManager *self;
|
||
|
GCancellable *cancellable;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_TOOLCHAIN_MANAGER (toolchain_manager));
|
||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||
|
g_assert (IDE_IS_TASK (task));
|
||
|
|
||
|
self = ide_task_get_source_object (task);
|
||
|
pipeline = ide_task_get_task_data (task);
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
if (!_ide_toolchain_manager_prepare_finish (toolchain_manager, result, &error))
|
||
|
{
|
||
|
g_message ("Failed to prepare toolchain: %s", error->message);
|
||
|
IDE_GOTO (failure);
|
||
|
}
|
||
|
|
||
|
if (pipeline != self->pipeline)
|
||
|
{
|
||
|
IDE_TRACE_MSG ("pipeline is no longer active, ignoring");
|
||
|
IDE_GOTO (failure);
|
||
|
}
|
||
|
|
||
|
if (ide_task_return_error_if_cancelled (task))
|
||
|
IDE_GOTO (failure);
|
||
|
|
||
|
cancellable = ide_task_get_cancellable (task);
|
||
|
|
||
|
/* This will cause plugins to load on the pipeline. */
|
||
|
if (!g_initable_init (G_INITABLE (pipeline), cancellable, &error))
|
||
|
{
|
||
|
/* translators: %s is replaced with the error message */
|
||
|
ide_object_warning (self,
|
||
|
_("Failed to initialize build pipeline: %s"),
|
||
|
error->message);
|
||
|
IDE_GOTO (failure);
|
||
|
}
|
||
|
|
||
|
ide_build_manager_set_can_build (self, TRUE);
|
||
|
|
||
|
if (ide_pipeline_is_ready (pipeline))
|
||
|
ide_build_manager_rediagnose (self);
|
||
|
else
|
||
|
g_signal_connect_object (pipeline,
|
||
|
"loaded",
|
||
|
G_CALLBACK (ide_build_manager_rediagnose),
|
||
|
self,
|
||
|
G_CONNECT_SWAPPED);
|
||
|
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PIPELINE]);
|
||
|
|
||
|
ide_task_return_boolean (task, TRUE);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
|
||
|
failure:
|
||
|
|
||
|
if (error != NULL)
|
||
|
ide_task_return_error (task, g_steal_pointer (&error));
|
||
|
else
|
||
|
ide_task_return_new_error (task,
|
||
|
G_IO_ERROR,
|
||
|
G_IO_ERROR_FAILED,
|
||
|
"Failed to setup build pipeline");
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_ensure_runtime_cb (GObject *object,
|
||
|
GAsyncResult *result,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
IdeRuntimeManager *runtime_manager = (IdeRuntimeManager *)object;
|
||
|
g_autoptr(GError) error = NULL;
|
||
|
g_autoptr(IdeTask) task = user_data;
|
||
|
IdePipeline *pipeline;
|
||
|
IdeBuildManager *self;
|
||
|
IdeToolchainManager *toolchain_manager;
|
||
|
IdeContext *context;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_RUNTIME_MANAGER (runtime_manager));
|
||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||
|
g_assert (IDE_IS_TASK (task));
|
||
|
|
||
|
self = ide_task_get_source_object (task);
|
||
|
pipeline = ide_task_get_task_data (task);
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
if (!_ide_runtime_manager_prepare_finish (runtime_manager, result, &error))
|
||
|
{
|
||
|
if (error != NULL)
|
||
|
g_message ("Failed to prepare runtime: %s", error->message);
|
||
|
IDE_GOTO (failure);
|
||
|
}
|
||
|
|
||
|
if (pipeline != self->pipeline)
|
||
|
{
|
||
|
IDE_TRACE_MSG ("pipeline is no longer active, ignoring");
|
||
|
IDE_GOTO (failure);
|
||
|
}
|
||
|
|
||
|
if (ide_task_return_error_if_cancelled (task))
|
||
|
IDE_GOTO (failure);
|
||
|
|
||
|
context = ide_object_get_context (IDE_OBJECT (pipeline));
|
||
|
g_assert (IDE_IS_CONTEXT (context));
|
||
|
|
||
|
toolchain_manager = ide_toolchain_manager_from_context (context);
|
||
|
g_assert (IDE_IS_TOOLCHAIN_MANAGER (toolchain_manager));
|
||
|
|
||
|
_ide_toolchain_manager_prepare_async (toolchain_manager,
|
||
|
pipeline,
|
||
|
ide_task_get_cancellable (task),
|
||
|
ide_build_manager_ensure_toolchain_cb,
|
||
|
g_object_ref (task));
|
||
|
|
||
|
IDE_EXIT;
|
||
|
|
||
|
failure:
|
||
|
|
||
|
if (error != NULL)
|
||
|
ide_task_return_error (task, g_steal_pointer (&error));
|
||
|
else
|
||
|
ide_task_return_new_error (task,
|
||
|
G_IO_ERROR,
|
||
|
G_IO_ERROR_FAILED,
|
||
|
"Failed to setup build pipeline");
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_device_get_info_cb (GObject *object,
|
||
|
GAsyncResult *result,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
IdeDevice *device = (IdeDevice *)object;
|
||
|
g_autoptr(IdeDeviceInfo) info = NULL;
|
||
|
g_autoptr(GError) error = NULL;
|
||
|
g_autoptr(IdeTask) task = user_data;
|
||
|
IdeRuntimeManager *runtime_manager;
|
||
|
IdePipeline *pipeline;
|
||
|
IdeContext *context;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_DEVICE (device));
|
||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||
|
g_assert (IDE_IS_TASK (task));
|
||
|
|
||
|
pipeline = ide_task_get_task_data (task);
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
if (ide_task_return_error_if_cancelled (task))
|
||
|
IDE_EXIT;
|
||
|
|
||
|
if (!(context = ide_object_get_context (IDE_OBJECT (pipeline))) ||
|
||
|
!(runtime_manager = ide_runtime_manager_from_context (context)))
|
||
|
{
|
||
|
ide_task_return_new_error (task,
|
||
|
G_IO_ERROR,
|
||
|
G_IO_ERROR_CANCELLED,
|
||
|
"Device was destroyed");
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
if (!(info = ide_device_get_info_finish (device, result, &error)))
|
||
|
{
|
||
|
ide_context_warning (context,
|
||
|
_("Failed to get device information: %s"),
|
||
|
error->message);
|
||
|
ide_task_return_error (task, g_steal_pointer (&error));
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
IDE_TRACE_MSG (" Device Kind = %d", ide_device_info_get_kind (info));
|
||
|
IDE_TRACE_MSG (" Device Triplet = %s",
|
||
|
ide_triplet_get_full_name (ide_device_info_get_host_triplet (info)));
|
||
|
|
||
|
_ide_pipeline_check_toolchain (pipeline, info);
|
||
|
|
||
|
_ide_runtime_manager_prepare_async (runtime_manager,
|
||
|
pipeline,
|
||
|
ide_task_get_cancellable (task),
|
||
|
ide_build_manager_ensure_runtime_cb,
|
||
|
g_object_ref (task));
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_invalidate_pipeline (IdeBuildManager *self)
|
||
|
{
|
||
|
g_autoptr(IdeTask) task = NULL;
|
||
|
IdeConfigManager *config_manager;
|
||
|
IdeDeviceManager *device_manager;
|
||
|
IdeRunManager *run_manager;
|
||
|
IdeConfig *config;
|
||
|
IdeContext *context;
|
||
|
IdeDevice *device;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
context = ide_object_get_context (IDE_OBJECT (self));
|
||
|
|
||
|
IDE_TRACE_MSG ("Reloading pipeline due to configuration change");
|
||
|
|
||
|
/*
|
||
|
* If we are currently building, we need to synthesize the failure
|
||
|
* of that build and re-setup the pipeline.
|
||
|
*/
|
||
|
if (self->building)
|
||
|
{
|
||
|
g_assert (self->pipeline != NULL);
|
||
|
|
||
|
self->building = FALSE;
|
||
|
dzl_clear_source (&self->timer_source);
|
||
|
g_signal_emit (self, signals [BUILD_FAILED], 0, self->pipeline);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Clear any cached build targets from the run manager.
|
||
|
*/
|
||
|
run_manager = ide_run_manager_from_context (context);
|
||
|
ide_run_manager_set_build_target (run_manager, NULL);
|
||
|
|
||
|
/*
|
||
|
* Cancel and clear our previous pipeline and associated components
|
||
|
* as they are not invalide.
|
||
|
*/
|
||
|
ide_build_manager_cancel (self);
|
||
|
|
||
|
ide_clear_and_destroy_object (&self->pipeline);
|
||
|
|
||
|
g_clear_pointer (&self->running_time, g_timer_destroy);
|
||
|
|
||
|
self->diagnostic_count = 0;
|
||
|
self->error_count = 0;
|
||
|
self->warning_count = 0;
|
||
|
|
||
|
/* Don't setup anything new if we're in shutdown or we haven't
|
||
|
* been told we are allowed to start.
|
||
|
*/
|
||
|
if (ide_object_in_destruction (IDE_OBJECT (context)) || !self->started)
|
||
|
IDE_EXIT;
|
||
|
|
||
|
config_manager = ide_config_manager_from_context (context);
|
||
|
device_manager = ide_device_manager_from_context (context);
|
||
|
|
||
|
config = ide_config_manager_get_current (config_manager);
|
||
|
device = ide_device_manager_get_device (device_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.
|
||
|
*
|
||
|
* We will delay the initialization until after the we have ensured the
|
||
|
* runtime is available (possibly installing it).
|
||
|
*/
|
||
|
ide_build_manager_set_can_build (self, FALSE);
|
||
|
self->pipeline = g_object_new (IDE_TYPE_PIPELINE,
|
||
|
"config", config,
|
||
|
"device", device,
|
||
|
NULL);
|
||
|
ide_object_append (IDE_OBJECT (self), IDE_OBJECT (self->pipeline));
|
||
|
dzl_signal_group_set_target (self->pipeline_signals, self->pipeline);
|
||
|
|
||
|
/*
|
||
|
* Create a task to manage our async pipeline initialization state.
|
||
|
*/
|
||
|
task = ide_task_new (self, self->cancellable, NULL, NULL);
|
||
|
ide_task_set_task_data (task, g_object_ref (self->pipeline), g_object_unref);
|
||
|
ide_task_set_priority (task, G_PRIORITY_LOW);
|
||
|
|
||
|
/*
|
||
|
* Next, we need to get information on the build device, which may require
|
||
|
* connecting to it. So we will query that information (so we can get
|
||
|
* arch/kernel/system too). We might need that when bootstrapping the
|
||
|
* runtime (if it's missing) among other things.
|
||
|
*/
|
||
|
ide_device_get_info_async (device,
|
||
|
self->cancellable,
|
||
|
ide_build_manager_device_get_info_cb,
|
||
|
g_steal_pointer (&task));
|
||
|
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ERROR_COUNT]);
|
||
|
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]);
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_WARNING_COUNT]);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_vcs_changed (IdeBuildManager *self,
|
||
|
IdeVcs *vcs)
|
||
|
{
|
||
|
g_autofree gchar *branch_name = NULL;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (IDE_IS_VCS (vcs));
|
||
|
|
||
|
/* Only invalidate the pipeline if they switched branches. Ignore things
|
||
|
* like opening up `git gui` or other things that could touch the index
|
||
|
* without really changing things out from underneath us.
|
||
|
*/
|
||
|
|
||
|
branch_name = ide_vcs_get_branch_name (vcs);
|
||
|
|
||
|
if (!ide_str_equal0 (branch_name, self->branch_name))
|
||
|
{
|
||
|
g_free (self->branch_name);
|
||
|
self->branch_name = g_strdup (branch_name);
|
||
|
ide_build_manager_invalidate_pipeline (self);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
initable_init (GInitable *initable,
|
||
|
GCancellable *cancellable,
|
||
|
GError **error)
|
||
|
{
|
||
|
IdeBuildManager *self = (IdeBuildManager *)initable;
|
||
|
IdeConfigManager *config_manager;
|
||
|
IdeDeviceManager *device_manager;
|
||
|
IdeContext *context;
|
||
|
IdeVcs *vcs;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
context = ide_object_get_context (IDE_OBJECT (self));
|
||
|
config_manager = ide_config_manager_from_context (context);
|
||
|
device_manager = ide_device_manager_from_context (context);
|
||
|
vcs = ide_vcs_from_context (context);
|
||
|
|
||
|
self->branch_name = ide_vcs_get_branch_name (vcs);
|
||
|
|
||
|
g_signal_connect_object (config_manager,
|
||
|
"invalidate",
|
||
|
G_CALLBACK (ide_build_manager_invalidate_pipeline),
|
||
|
self,
|
||
|
G_CONNECT_SWAPPED);
|
||
|
|
||
|
g_signal_connect_object (device_manager,
|
||
|
"notify::device",
|
||
|
G_CALLBACK (ide_build_manager_invalidate_pipeline),
|
||
|
self,
|
||
|
G_CONNECT_SWAPPED);
|
||
|
|
||
|
g_signal_connect_object (vcs,
|
||
|
"changed",
|
||
|
G_CALLBACK (ide_build_manager_vcs_changed),
|
||
|
self,
|
||
|
G_CONNECT_SWAPPED);
|
||
|
|
||
|
ide_build_manager_invalidate_pipeline (self);
|
||
|
|
||
|
IDE_RETURN (TRUE);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_real_build_started (IdeBuildManager *self,
|
||
|
IdePipeline *pipeline)
|
||
|
{
|
||
|
IdePipelinePhase phase;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
ide_build_manager_start_timer (self);
|
||
|
|
||
|
/*
|
||
|
* When the build completes, we may want to update diagnostics for
|
||
|
* files that are open. But we only want to do this if we are reaching
|
||
|
* configure for the first time, or performing a real build.
|
||
|
*/
|
||
|
|
||
|
phase = ide_pipeline_get_requested_phase (pipeline);
|
||
|
g_assert ((phase & IDE_PIPELINE_PHASE_MASK) == phase);
|
||
|
|
||
|
if (phase == IDE_PIPELINE_PHASE_BUILD ||
|
||
|
(phase == IDE_PIPELINE_PHASE_CONFIGURE && !self->has_configured))
|
||
|
{
|
||
|
self->needs_rediagnose = TRUE;
|
||
|
self->has_configured = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_real_build_failed (IdeBuildManager *self,
|
||
|
IdePipeline *pipeline)
|
||
|
{
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
ide_build_manager_stop_timer (self);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_real_build_finished (IdeBuildManager *self,
|
||
|
IdePipeline *pipeline)
|
||
|
{
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
|
||
|
ide_build_manager_stop_timer (self);
|
||
|
|
||
|
if (self->needs_rediagnose)
|
||
|
{
|
||
|
self->needs_rediagnose = FALSE;
|
||
|
ide_build_manager_rediagnose (self);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
initable_iface_init (GInitableIface *iface)
|
||
|
{
|
||
|
iface->init = initable_init;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_finalize (GObject *object)
|
||
|
{
|
||
|
IdeBuildManager *self = (IdeBuildManager *)object;
|
||
|
|
||
|
ide_clear_and_destroy_object (&self->pipeline);
|
||
|
g_clear_object (&self->pipeline_signals);
|
||
|
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);
|
||
|
g_clear_pointer (&self->branch_name, g_free);
|
||
|
|
||
|
dzl_clear_source (&self->timer_source);
|
||
|
|
||
|
G_OBJECT_CLASS (ide_build_manager_parent_class)->finalize (object);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_get_property (GObject *object,
|
||
|
guint prop_id,
|
||
|
GValue *value,
|
||
|
GParamSpec *pspec)
|
||
|
{
|
||
|
IdeBuildManager *self = IDE_BUILD_MANAGER (object);
|
||
|
|
||
|
switch (prop_id)
|
||
|
{
|
||
|
case PROP_BUSY:
|
||
|
g_value_set_boolean (value, ide_build_manager_get_busy (self));
|
||
|
break;
|
||
|
|
||
|
case PROP_CAN_BUILD:
|
||
|
g_value_set_boolean (value, ide_build_manager_get_can_build (self));
|
||
|
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;
|
||
|
|
||
|
case PROP_ERROR_COUNT:
|
||
|
g_value_set_uint (value, self->error_count);
|
||
|
break;
|
||
|
|
||
|
case PROP_WARNING_COUNT:
|
||
|
g_value_set_uint (value, self->warning_count);
|
||
|
break;
|
||
|
|
||
|
case PROP_PIPELINE:
|
||
|
g_value_set_object (value, self->pipeline);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_class_init (IdeBuildManagerClass *klass)
|
||
|
{
|
||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
|
|
||
|
object_class->finalize = ide_build_manager_finalize;
|
||
|
object_class->get_property = ide_build_manager_get_property;
|
||
|
|
||
|
/**
|
||
|
* IdeBuildManager:can-build:
|
||
|
*
|
||
|
* Gets if the build manager can queue a build request.
|
||
|
*
|
||
|
* This might be false if the required runtime is not available or other
|
||
|
* errors in setting up the build pipeline.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_CAN_BUILD] =
|
||
|
g_param_spec_boolean ("can-build",
|
||
|
"Can Build",
|
||
|
"If the manager can queue a build",
|
||
|
FALSE,
|
||
|
(G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||
|
|
||
|
/**
|
||
|
* 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).
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_BUSY] =
|
||
|
g_param_spec_boolean ("busy",
|
||
|
"Busy",
|
||
|
"If a build is actively executing",
|
||
|
FALSE,
|
||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||
|
|
||
|
/**
|
||
|
* IdeBuildManager:error-count:
|
||
|
*
|
||
|
* The number of errors discovered during the build process.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_ERROR_COUNT] =
|
||
|
g_param_spec_uint ("error-count",
|
||
|
"Error Count",
|
||
|
"The number of errors that have been seen in the current build",
|
||
|
0, G_MAXUINT, 0,
|
||
|
(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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_HAS_DIAGNOSTICS] =
|
||
|
g_param_spec_boolean ("has-diagnostics",
|
||
|
"Has Diagnostics",
|
||
|
"Has Diagnostics",
|
||
|
FALSE,
|
||
|
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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_MESSAGE] =
|
||
|
g_param_spec_string ("message",
|
||
|
"Message",
|
||
|
"The current build message",
|
||
|
NULL,
|
||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||
|
|
||
|
/**
|
||
|
* IdeBuildManager:pipeline:
|
||
|
*
|
||
|
* The "pipeline" property is the build pipeline that the build manager
|
||
|
* is currently managing.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_PIPELINE] =
|
||
|
g_param_spec_object ("pipeline",
|
||
|
"Pipeline",
|
||
|
"The build pipeline",
|
||
|
IDE_TYPE_PIPELINE,
|
||
|
(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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_RUNNING_TIME] =
|
||
|
g_param_spec_int64 ("running-time",
|
||
|
"Running Time",
|
||
|
"The amount of elapsed time performing the current build",
|
||
|
0,
|
||
|
G_MAXINT64,
|
||
|
0,
|
||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||
|
|
||
|
/**
|
||
|
* IdeBuildManager:warning-count:
|
||
|
*
|
||
|
* The "warning-count" property contains the number of warnings that have
|
||
|
* been discovered in the current build request.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
properties [PROP_WARNING_COUNT] =
|
||
|
g_param_spec_uint ("warning-count",
|
||
|
"Warning Count",
|
||
|
"The number of warnings that have been seen in the current build",
|
||
|
0, G_MAXUINT, 0,
|
||
|
(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 #IdePipeline
|
||
|
*
|
||
|
* 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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
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,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_PIPELINE);
|
||
|
|
||
|
/**
|
||
|
* IdeBuildManager::build-failed:
|
||
|
* @self: An #IdeBuildManager
|
||
|
* @pipeline: An #IdePipeline
|
||
|
*
|
||
|
* 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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
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,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_PIPELINE);
|
||
|
|
||
|
/**
|
||
|
* IdeBuildManager::build-finished:
|
||
|
* @self: An #IdeBuildManager
|
||
|
* @pipeline: An #IdePipeline
|
||
|
*
|
||
|
* The "build-finished" signal is emitted when a build completed
|
||
|
* successfully.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
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,
|
||
|
G_TYPE_NONE, 1, IDE_TYPE_PIPELINE);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_action_cancel (IdeBuildManager *self,
|
||
|
GVariant *param)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
ide_build_manager_cancel (self);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_action_build (IdeBuildManager *self,
|
||
|
GVariant *param)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
ide_build_manager_build_async (self, IDE_PIPELINE_PHASE_BUILD, NULL, NULL, NULL, NULL);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_action_rebuild (IdeBuildManager *self,
|
||
|
GVariant *param)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
ide_build_manager_rebuild_async (self, IDE_PIPELINE_PHASE_BUILD, NULL, NULL, NULL, NULL);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_action_clean (IdeBuildManager *self,
|
||
|
GVariant *param)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
ide_build_manager_clean_async (self, IDE_PIPELINE_PHASE_BUILD, NULL, NULL, NULL);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_action_install (IdeBuildManager *self,
|
||
|
GVariant *param)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
ide_build_manager_build_async (self, IDE_PIPELINE_PHASE_INSTALL, NULL, NULL, NULL, NULL);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_action_export (IdeBuildManager *self,
|
||
|
GVariant *param)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
ide_build_manager_build_async (self, IDE_PIPELINE_PHASE_EXPORT, NULL, NULL, NULL, NULL);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_init (IdeBuildManager *self)
|
||
|
{
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
ide_build_manager_update_action_enabled (self);
|
||
|
|
||
|
self->cancellable = g_cancellable_new ();
|
||
|
self->needs_rediagnose = TRUE;
|
||
|
|
||
|
self->pipeline_signals = dzl_signal_group_new (IDE_TYPE_PIPELINE);
|
||
|
|
||
|
dzl_signal_group_connect_object (self->pipeline_signals,
|
||
|
"diagnostic",
|
||
|
G_CALLBACK (ide_build_manager_handle_diagnostic),
|
||
|
self,
|
||
|
G_CONNECT_SWAPPED);
|
||
|
|
||
|
dzl_signal_group_connect_object (self->pipeline_signals,
|
||
|
"notify::busy",
|
||
|
G_CALLBACK (ide_build_manager_notify_busy),
|
||
|
self,
|
||
|
G_CONNECT_SWAPPED);
|
||
|
|
||
|
dzl_signal_group_connect_object (self->pipeline_signals,
|
||
|
"notify::message",
|
||
|
G_CALLBACK (ide_build_manager_notify_message),
|
||
|
self,
|
||
|
G_CONNECT_SWAPPED);
|
||
|
|
||
|
dzl_signal_group_connect_object (self->pipeline_signals,
|
||
|
"started",
|
||
|
G_CALLBACK (ide_build_manager_pipeline_started),
|
||
|
self,
|
||
|
G_CONNECT_SWAPPED);
|
||
|
|
||
|
dzl_signal_group_connect_object (self->pipeline_signals,
|
||
|
"finished",
|
||
|
G_CALLBACK (ide_build_manager_pipeline_finished),
|
||
|
self,
|
||
|
G_CONNECT_SWAPPED);
|
||
|
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_get_busy:
|
||
|
* @self: An #IdeBuildManager
|
||
|
*
|
||
|
* Gets if the #IdeBuildManager is currently busy building the project.
|
||
|
*
|
||
|
* See #IdeBuildManager:busy for more information.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_build_manager_get_busy (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), FALSE);
|
||
|
|
||
|
if G_LIKELY (self->pipeline != NULL)
|
||
|
return ide_pipeline_get_busy (self->pipeline);
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gchar *
|
||
|
ide_build_manager_get_message (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), NULL);
|
||
|
|
||
|
if G_LIKELY (self->pipeline != NULL)
|
||
|
return ide_pipeline_get_message (self->pipeline);
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GDateTime *
|
||
|
ide_build_manager_get_last_build_time (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), NULL);
|
||
|
|
||
|
return self->last_build_time;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
GTimeSpan
|
||
|
ide_build_manager_get_running_time (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), 0);
|
||
|
|
||
|
if (self->running_time != NULL)
|
||
|
return g_timer_elapsed (self->running_time, NULL) * G_TIME_SPAN_SECOND;
|
||
|
|
||
|
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.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_build_manager_cancel (IdeBuildManager *self)
|
||
|
{
|
||
|
g_autoptr(GCancellable) cancellable = NULL;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
cancellable = g_steal_pointer (&self->cancellable);
|
||
|
self->cancellable = g_cancellable_new ();
|
||
|
|
||
|
g_debug ("Cancelling [%p] build due to user request", cancellable);
|
||
|
|
||
|
if (!g_cancellable_is_cancelled (cancellable))
|
||
|
g_cancellable_cancel (cancellable);
|
||
|
|
||
|
if (self->pipeline != NULL)
|
||
|
_ide_pipeline_cancel (self->pipeline);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 #IdePipeline.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
IdePipeline *
|
||
|
ide_build_manager_get_pipeline (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_MAIN_THREAD (), NULL);
|
||
|
g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), NULL);
|
||
|
|
||
|
return self->pipeline;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_ref_pipeline:
|
||
|
* @self: a #IdeBuildManager
|
||
|
*
|
||
|
* A thread-safe variant of ide_build_manager_get_pipeline().
|
||
|
*
|
||
|
* Returns: (transfer full) (nullable): an #IdePipeline or %NULL
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
IdePipeline *
|
||
|
ide_build_manager_ref_pipeline (IdeBuildManager *self)
|
||
|
{
|
||
|
IdePipeline *ret = NULL;
|
||
|
|
||
|
g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), NULL);
|
||
|
|
||
|
ide_object_lock (IDE_OBJECT (self));
|
||
|
g_set_object (&ret, self->pipeline);
|
||
|
ide_object_unlock (IDE_OBJECT (self));
|
||
|
|
||
|
return g_steal_pointer (&ret);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_build_targets_cb (GObject *object,
|
||
|
GAsyncResult *result,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
IdePipeline *pipeline = (IdePipeline *)object;
|
||
|
g_autoptr(IdeTask) task = user_data;
|
||
|
g_autoptr(GError) error = NULL;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||
|
g_assert (IDE_IS_TASK (task));
|
||
|
|
||
|
if (!ide_pipeline_build_targets_finish (pipeline, result, &error))
|
||
|
{
|
||
|
ide_object_warning (pipeline, "%s", error->message);
|
||
|
ide_task_return_error (task, g_steal_pointer (&error));
|
||
|
IDE_GOTO (failure);
|
||
|
}
|
||
|
|
||
|
ide_task_return_boolean (task, TRUE);
|
||
|
|
||
|
failure:
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_save_all_cb (GObject *object,
|
||
|
GAsyncResult *result,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
IdeBufferManager *buffer_manager = (IdeBufferManager *)object;
|
||
|
g_autoptr(IdeTask) task = user_data;
|
||
|
g_autoptr(GError) error = NULL;
|
||
|
IdeBuildManager *self;
|
||
|
GCancellable *cancellable;
|
||
|
GPtrArray *targets;
|
||
|
IdePipelinePhase phase;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_BUFFER_MANAGER (buffer_manager));
|
||
|
g_assert (IDE_IS_TASK (task));
|
||
|
|
||
|
self = ide_task_get_source_object (task);
|
||
|
cancellable = ide_task_get_cancellable (task);
|
||
|
targets = ide_task_get_task_data (task);
|
||
|
|
||
|
g_assert (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
|
||
|
if (!ide_buffer_manager_save_all_finish (buffer_manager, result, &error))
|
||
|
{
|
||
|
ide_task_return_error (task, g_steal_pointer (&error));
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
phase = ide_pipeline_get_requested_phase (self->pipeline);
|
||
|
|
||
|
ide_pipeline_build_targets_async (self->pipeline,
|
||
|
phase,
|
||
|
targets,
|
||
|
cancellable,
|
||
|
ide_build_manager_build_targets_cb,
|
||
|
g_steal_pointer (&task));
|
||
|
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HAS_DIAGNOSTICS]);
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LAST_BUILD_TIME]);
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNNING_TIME]);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_build_async:
|
||
|
* @self: An #IdeBuildManager
|
||
|
* @phase: An #IdePipelinePhase or 0
|
||
|
* @targets: (nullable) (element-type IdeBuildTarget): an array of
|
||
|
* #IdeBuildTarget to build
|
||
|
* @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_build_finish().
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_build_manager_build_async (IdeBuildManager *self,
|
||
|
IdePipelinePhase phase,
|
||
|
GPtrArray *targets,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_autoptr(IdeTask) task = NULL;
|
||
|
IdeBufferManager *buffer_manager;
|
||
|
IdeContext *context;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
g_return_if_fail (!g_cancellable_is_cancelled (self->cancellable));
|
||
|
|
||
|
cancellable = dzl_cancellable_chain (cancellable, self->cancellable);
|
||
|
|
||
|
task = ide_task_new (self, cancellable, callback, user_data);
|
||
|
ide_task_set_source_tag (task, ide_build_manager_build_async);
|
||
|
ide_task_set_priority (task, G_PRIORITY_LOW);
|
||
|
ide_task_set_return_on_cancel (task, TRUE);
|
||
|
|
||
|
if (targets != NULL)
|
||
|
ide_task_set_task_data (task, _g_ptr_array_copy_objects (targets), g_ptr_array_unref);
|
||
|
|
||
|
if (self->pipeline == NULL ||
|
||
|
self->can_build == FALSE ||
|
||
|
!ide_pipeline_is_ready (self->pipeline))
|
||
|
{
|
||
|
ide_task_return_new_error (task,
|
||
|
G_IO_ERROR,
|
||
|
G_IO_ERROR_PENDING,
|
||
|
"Cannot execute pipeline, it has not yet been prepared");
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
if (!ide_pipeline_request_phase (self->pipeline, phase))
|
||
|
{
|
||
|
ide_task_return_boolean (task, TRUE);
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Only update our "build time" if we are advancing to IDE_PIPELINE_PHASE_BUILD,
|
||
|
* we don't really care about "builds" for configure stages and less.
|
||
|
*/
|
||
|
if ((phase & IDE_PIPELINE_PHASE_MASK) >= IDE_PIPELINE_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;
|
||
|
self->warning_count = 0;
|
||
|
self->error_count = 0;
|
||
|
}
|
||
|
|
||
|
ide_build_manager_reset_info (self);
|
||
|
|
||
|
/*
|
||
|
* 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_PIPELINE_PHASE_MASK) >= IDE_PIPELINE_PHASE_BUILD)
|
||
|
{
|
||
|
context = ide_object_get_context (IDE_OBJECT (self));
|
||
|
buffer_manager = ide_buffer_manager_from_context (context);
|
||
|
ide_buffer_manager_save_all_async (buffer_manager,
|
||
|
NULL,
|
||
|
ide_build_manager_save_all_cb,
|
||
|
g_steal_pointer (&task));
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
ide_pipeline_build_targets_async (self->pipeline,
|
||
|
phase,
|
||
|
targets,
|
||
|
cancellable,
|
||
|
ide_build_manager_build_targets_cb,
|
||
|
g_steal_pointer (&task));
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_build_finish:
|
||
|
* @self: An #IdeBuildManager
|
||
|
* @result: a #GAsyncResult
|
||
|
* @error: A location for a #GError or %NULL
|
||
|
*
|
||
|
* Completes a request to ide_build_manager_build_async().
|
||
|
*
|
||
|
* Returns: %TRUE if successful, otherwise %FALSE and @error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_build_manager_build_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 (IDE_IS_TASK (result), FALSE);
|
||
|
|
||
|
ret = ide_task_propagate_boolean (IDE_TASK (result), error);
|
||
|
|
||
|
IDE_RETURN (ret);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_clean_cb (GObject *object,
|
||
|
GAsyncResult *result,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
IdePipeline *pipeline = (IdePipeline *)object;
|
||
|
g_autoptr(IdeTask) task = user_data;
|
||
|
g_autoptr(GError) error = NULL;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||
|
g_assert (IDE_IS_TASK (task));
|
||
|
|
||
|
if (!ide_pipeline_clean_finish (pipeline, result, &error))
|
||
|
ide_task_return_error (task, g_steal_pointer (&error));
|
||
|
else
|
||
|
ide_task_return_boolean (task, TRUE);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_clean_async:
|
||
|
* @self: a #IdeBuildManager
|
||
|
* @phase: the build phase to clean
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: (nullable): a callback to execute upon completion, or %NULL
|
||
|
* @user_data: closure data for @callback
|
||
|
*
|
||
|
* Asynchronously requests that the build pipeline clean up to @phase.
|
||
|
*
|
||
|
* See ide_pipeline_clean_async() for more information.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_build_manager_clean_async (IdeBuildManager *self,
|
||
|
IdePipelinePhase phase,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_autoptr(IdeTask) task = NULL;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
g_return_if_fail (!g_cancellable_is_cancelled (self->cancellable));
|
||
|
|
||
|
cancellable = dzl_cancellable_chain (cancellable, self->cancellable);
|
||
|
|
||
|
task = ide_task_new (self, cancellable, callback, user_data);
|
||
|
ide_task_set_source_tag (task, ide_build_manager_clean_async);
|
||
|
ide_task_set_priority (task, G_PRIORITY_LOW);
|
||
|
ide_task_set_return_on_cancel (task, TRUE);
|
||
|
|
||
|
if (self->pipeline == NULL)
|
||
|
{
|
||
|
ide_task_return_new_error (task,
|
||
|
G_IO_ERROR,
|
||
|
G_IO_ERROR_PENDING,
|
||
|
"Cannot execute pipeline, it has not yet been prepared");
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
ide_build_manager_reset_info (self);
|
||
|
|
||
|
ide_pipeline_clean_async (self->pipeline,
|
||
|
phase,
|
||
|
cancellable,
|
||
|
ide_build_manager_clean_cb,
|
||
|
g_steal_pointer (&task));
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_clean_finish:
|
||
|
* @self: a #IdeBuildManager
|
||
|
* @result: a #GAsyncResult
|
||
|
* @error: a location for a #GError, or %NULL
|
||
|
*
|
||
|
* Completes an asynchronous request to ide_build_manager_clean_async().
|
||
|
*
|
||
|
* Returns: %TRUE if successful; otherwise %FALSE and @error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_build_manager_clean_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 (IDE_IS_TASK (result), FALSE);
|
||
|
|
||
|
ret = ide_task_propagate_boolean (IDE_TASK (result), error);
|
||
|
|
||
|
IDE_RETURN (ret);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_rebuild_cb (GObject *object,
|
||
|
GAsyncResult *result,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
IdePipeline *pipeline = (IdePipeline *)object;
|
||
|
g_autoptr(IdeTask) task = user_data;
|
||
|
g_autoptr(GError) error = NULL;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_assert (IDE_IS_PIPELINE (pipeline));
|
||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||
|
g_assert (IDE_IS_TASK (task));
|
||
|
|
||
|
if (!ide_pipeline_rebuild_finish (pipeline, result, &error))
|
||
|
ide_task_return_error (task, g_steal_pointer (&error));
|
||
|
else
|
||
|
ide_task_return_boolean (task, TRUE);
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_rebuild_async:
|
||
|
* @self: a #IdeBuildManager
|
||
|
* @phase: the build phase to rebuild to
|
||
|
* @targets: (element-type IdeBuildTarget) (nullable): an array of #GPtrArray
|
||
|
* of #IdeBuildTarget or %NULL.
|
||
|
* @cancellable: (nullable): a #GCancellable or %NULL
|
||
|
* @callback: (nullable): a callback to execute upon completion, or %NULL
|
||
|
* @user_data: closure data for @callback
|
||
|
*
|
||
|
* Asynchronously requests that the build pipeline clean and rebuild up
|
||
|
* to the given phase. This may involve discarding previous build artifacts
|
||
|
* to allow for the rebuild process.
|
||
|
*
|
||
|
* See ide_pipeline_rebuild_async() for more information.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_build_manager_rebuild_async (IdeBuildManager *self,
|
||
|
IdePipelinePhase phase,
|
||
|
GPtrArray *targets,
|
||
|
GCancellable *cancellable,
|
||
|
GAsyncReadyCallback callback,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_autoptr(IdeTask) task = NULL;
|
||
|
|
||
|
IDE_ENTRY;
|
||
|
|
||
|
g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
|
||
|
g_return_if_fail (!g_cancellable_is_cancelled (self->cancellable));
|
||
|
|
||
|
cancellable = dzl_cancellable_chain (cancellable, self->cancellable);
|
||
|
|
||
|
task = ide_task_new (self, cancellable, callback, user_data);
|
||
|
ide_task_set_source_tag (task, ide_build_manager_rebuild_async);
|
||
|
ide_task_set_priority (task, G_PRIORITY_LOW);
|
||
|
ide_task_set_return_on_cancel (task, TRUE);
|
||
|
|
||
|
if (self->pipeline == NULL)
|
||
|
{
|
||
|
ide_task_return_new_error (task,
|
||
|
G_IO_ERROR,
|
||
|
G_IO_ERROR_PENDING,
|
||
|
"Cannot execute pipeline, it has not yet been prepared");
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
ide_build_manager_reset_info (self);
|
||
|
|
||
|
ide_pipeline_rebuild_async (self->pipeline,
|
||
|
phase,
|
||
|
targets,
|
||
|
cancellable,
|
||
|
ide_build_manager_rebuild_cb,
|
||
|
g_steal_pointer (&task));
|
||
|
|
||
|
IDE_EXIT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_rebuild_finish:
|
||
|
* @self: a #IdeBuildManager
|
||
|
* @result: a #GAsyncResult
|
||
|
* @error: a location for a #GError, or %NULL
|
||
|
*
|
||
|
* Completes an asynchronous request to ide_build_manager_rebuild_async().
|
||
|
*
|
||
|
* Returns: %TRUE if successful; otherwise %FALSE and @error is set.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
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 (IDE_IS_TASK (result), FALSE);
|
||
|
|
||
|
ret = ide_task_propagate_boolean (IDE_TASK (result), error);
|
||
|
|
||
|
IDE_RETURN (ret);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_get_can_build:
|
||
|
* @self: a #IdeBuildManager
|
||
|
*
|
||
|
* Checks if the current pipeline is ready to build.
|
||
|
*
|
||
|
* Returns: %TRUE if a build operation can advance the pipeline.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
gboolean
|
||
|
ide_build_manager_get_can_build (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), FALSE);
|
||
|
|
||
|
return self->can_build;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
ide_build_manager_set_can_build (IdeBuildManager *self,
|
||
|
gboolean can_build)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
can_build = !!can_build;
|
||
|
|
||
|
if (self->can_build != can_build)
|
||
|
{
|
||
|
self->can_build = can_build;
|
||
|
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CAN_BUILD]);
|
||
|
ide_build_manager_update_action_enabled (self);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* ide_build_manager_invalidate:
|
||
|
* @self: a #IdeBuildManager
|
||
|
*
|
||
|
* Requests that the #IdeBuildManager invalidate the current pipeline and
|
||
|
* setup a new pipeline.
|
||
|
*
|
||
|
* Since: 3.32
|
||
|
*/
|
||
|
void
|
||
|
ide_build_manager_invalidate (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_MAIN_THREAD ());
|
||
|
g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
|
||
|
|
||
|
ide_build_manager_invalidate_pipeline (self);
|
||
|
}
|
||
|
|
||
|
guint
|
||
|
ide_build_manager_get_error_count (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), 0);
|
||
|
|
||
|
return self->error_count;
|
||
|
}
|
||
|
|
||
|
guint
|
||
|
ide_build_manager_get_warning_count (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_val_if_fail (IDE_IS_BUILD_MANAGER (self), 0);
|
||
|
|
||
|
return self->warning_count;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
_ide_build_manager_start (IdeBuildManager *self)
|
||
|
{
|
||
|
g_return_if_fail (IDE_IS_BUILD_MANAGER (self));
|
||
|
g_return_if_fail (self->started == FALSE);
|
||
|
|
||
|
self->started = TRUE;
|
||
|
|
||
|
ide_build_manager_invalidate (self);
|
||
|
}
|