Commit 43b1422d authored by Christian Hergert's avatar Christian Hergert

buildsystem: add plugin interface to discover build system

This adds an IdeBuildSystemDiscovery interface so that we can try to
discover the preferred build system during project loading based on
external data, such as a json manifest from flatpak.

https://bugzilla.gnome.org/show_bug.cgi?id=780006
parent 54af0d0b
......@@ -41,6 +41,7 @@ libide_1_0_la_public_headers = \
buildsystem/ide-build-stage-mkdirs.h \
buildsystem/ide-build-stage-transfer.h \
buildsystem/ide-build-system.h \
buildsystem/ide-build-system-discovery.h \
buildsystem/ide-build-target.h \
buildsystem/ide-build-utils.h \
buildsystem/ide-configuration-manager.h \
......@@ -217,6 +218,7 @@ libide_1_0_la_public_sources = \
buildsystem/ide-build-stage-mkdirs.c \
buildsystem/ide-build-stage-transfer.c \
buildsystem/ide-build-system.c \
buildsystem/ide-build-system-discovery.c \
buildsystem/ide-build-target.c \
buildsystem/ide-build-utils.c \
buildsystem/ide-configuration-manager.c \
......
/* ide-build-system-discovery.c
*
* Copyright (C) 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
* 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/>.
*/
#define G_LOG_DOMAIN "ide-build-system-discovery"
#include "ide-build-system-discovery.h"
G_DEFINE_INTERFACE (IdeBuildSystemDiscovery, ide_build_system_discovery, G_TYPE_OBJECT)
static void
ide_build_system_discovery_default_init (IdeBuildSystemDiscoveryInterface *iface)
{
}
/**
* ide_build_system_discovery_discover:
* @self: An #IdeBuildSystemDiscovery
* @project_file: A #GFile containing the project file (a directory)
* @cancellable: (nullable): A #GCancellable or %NULL
* @priority: (out): A location for the priority
* @error: a location for a #GError or %NULL
*
* This virtual method can be used to try to discover the build system to use for
* a particular project. This might be used in cases like Flatpak where the build
* system can be determined from the .json manifest rather than auto-discovery
* by locating project files.
*
* Returns: (transfer full): The hint for the build system, which should match what
* the build system returns from ide_build_system_get_id().
*/
gchar *
ide_build_system_discovery_discover (IdeBuildSystemDiscovery *self,
GFile *project_file,
GCancellable *cancellable,
gint *priority,
GError **error)
{
g_return_val_if_fail (IDE_IS_BUILD_SYSTEM_DISCOVERY (self), NULL);
g_return_val_if_fail (G_IS_FILE (project_file), NULL);
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), NULL);
if (priority != NULL)
*priority = G_MAXINT;
if (IDE_BUILD_SYSTEM_DISCOVERY_GET_IFACE (self)->discover)
return IDE_BUILD_SYSTEM_DISCOVERY_GET_IFACE (self)->discover (self, project_file, cancellable, priority, error);
g_set_error (error,
G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
"Discovery is not supported");
return NULL;
}
/* ide-build-system-discovery.h
*
* Copyright (C) 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
* 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/>.
*/
#ifndef IDE_BUILD_SYSTEM_DISCOVERY_H
#define IDE_BUILD_SYSTEM_DISCOVERY_H
#include <gio/gio.h>
#include "ide-types.h"
G_BEGIN_DECLS
#define IDE_TYPE_BUILD_SYSTEM_DISCOVERY (ide_build_system_discovery_get_type())
G_DECLARE_INTERFACE (IdeBuildSystemDiscovery, ide_build_system_discovery, IDE, BUILD_SYSTEM_DISCOVERY, GObject)
struct _IdeBuildSystemDiscoveryInterface
{
GTypeInterface parent_iface;
gchar *(*discover) (IdeBuildSystemDiscovery *self,
GFile *project_file,
GCancellable *cancellable,
gint *priority,
GError **error);
};
gchar *ide_build_system_discovery_discover (IdeBuildSystemDiscovery *self,
GFile *project_file,
GCancellable *cancellable,
gint *priority,
GError **error);
G_END_DECLS
#endif /* IDE_BUILD_SYSTEM_DISCOVERY_H */
......@@ -33,6 +33,7 @@
#include "buffers/ide-unsaved-files.h"
#include "buildsystem/ide-build-manager.h"
#include "buildsystem/ide-build-system.h"
#include "buildsystem/ide-build-system-discovery.h"
#include "buildsystem/ide-configuration-manager.h"
#include "diagnostics/ide-diagnostics-manager.h"
#include "devices/ide-device-manager.h"
......@@ -65,6 +66,7 @@ struct _IdeContext
IdeBufferManager *buffer_manager;
IdeBuildManager *build_manager;
IdeBuildSystem *build_system;
gchar *build_system_hint;
IdeConfigurationManager *configuration_manager;
IdeDiagnosticsManager *diagnostics_manager;
IdeDeviceManager *device_manager;
......@@ -346,6 +348,7 @@ ide_context_new_async (GFile *project_file,
g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (NULL, cancellable, callback, user_data);
g_task_set_source_tag (task, ide_context_new_async);
g_async_initable_new_async (IDE_TYPE_CONTEXT,
G_PRIORITY_DEFAULT,
......@@ -539,6 +542,7 @@ ide_context_finalize (GObject *object)
IDE_ENTRY;
g_clear_pointer (&self->build_system_hint, g_free);
g_clear_pointer (&self->services_by_gtype, g_hash_table_unref);
g_clear_pointer (&self->root_build_dir, g_free);
g_clear_pointer (&self->recent_projects_path, g_free);
......@@ -1020,6 +1024,7 @@ ide_context_init_build_system (gpointer source_object,
task = g_task_new (self, cancellable, callback, user_data);
ide_build_system_new_async (self,
self->project_file,
self->build_system_hint,
cancellable,
ide_context_init_build_system_cb,
g_object_ref (task));
......@@ -1502,6 +1507,119 @@ ide_context_init_loaded (gpointer source_object,
g_task_return_boolean (task, TRUE);
}
static void
ide_context_init_early_discover_cb (PeasExtensionSet *set,
PeasPluginInfo *plugin_info,
PeasExtension *exten,
gpointer user_data)
{
IdeBuildSystemDiscovery *discovery = (IdeBuildSystemDiscovery *)exten;
g_autofree gchar *ret = NULL;
struct {
GFile *project_file;
gchar *hint;
gint priority;
} *state = user_data;
gint priority = 0;
g_assert (PEAS_IS_EXTENSION_SET (set));
g_assert (plugin_info != NULL);
g_assert (IDE_IS_BUILD_SYSTEM_DISCOVERY (exten));
g_assert (state != NULL);
ret = ide_build_system_discovery_discover (discovery, state->project_file, NULL, &priority, NULL);
if (ret != NULL && priority < state->priority)
{
g_free (state->hint);
state->hint = g_steal_pointer (&ret);
state->priority = priority;
}
}
static void
ide_context_init_early_discovery_worker (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
IdeContext *self = source_object;
g_autoptr(PeasExtensionSet) addins = NULL;
GFile *project_file = task_data;
struct {
GFile *project_file;
gchar *hint;
gint priority;
} state;
g_assert (G_IS_TASK (task));
g_assert (IDE_IS_CONTEXT (self));
g_assert (G_IS_FILE (project_file));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
/*
* Before we load our build system by working through the extension
* points, try to discover if there is a specific build system we
* should be using.
*/
/*
* If the project file is not a directory, then we don't want to do any type-hint
* discovery (as we want to let the build system directly try to load the project).
*/
if (g_file_query_file_type (project_file, 0, cancellable) != G_FILE_TYPE_DIRECTORY)
{
g_task_return_boolean (task, TRUE);
return;
}
state.project_file = project_file;
state.hint = NULL;
state.priority = G_MAXINT;
/*
* Ask our plugins to try to discover what build system to use before loading
* build system extension points. This allows things like flatpak configuration
* files to influence what build system to load.
*/
addins = peas_extension_set_new (peas_engine_get_default (),
IDE_TYPE_BUILD_SYSTEM_DISCOVERY,
NULL);
peas_extension_set_foreach (addins, ide_context_init_early_discover_cb, &state);
/*
* If we discovered the build system to use based on the hint, we need to stash
* that info so the ide_context_init_build_system() function can use it to narrow
* the build systems to try.
*/
if (state.hint != NULL)
{
IDE_TRACE_MSG ("Discovered that %s is the build system to load", state.hint);
self->build_system_hint = g_steal_pointer (&state.hint);
}
g_task_return_boolean (task, TRUE);
}
static void
ide_context_init_early_discovery (gpointer source_object,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
IdeContext *self = source_object;
g_autoptr(GTask) task = NULL;
g_assert (IDE_IS_CONTEXT (self));
g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, ide_context_init_early_discovery);
g_task_set_task_data (task, g_object_ref (self->project_file), g_object_unref);
g_task_run_in_thread (task, ide_context_init_early_discovery_worker);
}
static void
ide_context_init_async (GAsyncInitable *initable,
int io_priority,
......@@ -1518,6 +1636,7 @@ ide_context_init_async (GAsyncInitable *initable,
cancellable,
callback,
user_data,
ide_context_init_early_discovery,
ide_context_init_build_system,
ide_context_init_vcs,
ide_context_init_services,
......
......@@ -45,6 +45,7 @@ G_BEGIN_DECLS
#include "buildsystem/ide-build-stage-mkdirs.h"
#include "buildsystem/ide-build-stage-transfer.h"
#include "buildsystem/ide-build-system.h"
#include "buildsystem/ide-build-system-discovery.h"
#include "buildsystem/ide-build-target.h"
#include "buildsystem/ide-configuration-manager.h"
#include "buildsystem/ide-configuration.h"
......
......@@ -54,6 +54,7 @@ libide_public_headers = [
'buildsystem/ide-build-stage-mkdirs.h',
'buildsystem/ide-build-stage-transfer.h',
'buildsystem/ide-build-system.h',
'buildsystem/ide-build-system-discovery.h',
'buildsystem/ide-build-target.h',
'buildsystem/ide-build-utils.h',
'buildsystem/ide-configuration-manager.h',
......@@ -257,6 +258,7 @@ libide_public_sources = [
'buildsystem/ide-build-stage-mkdirs.c',
'buildsystem/ide-build-stage-transfer.c',
'buildsystem/ide-build-system.c',
'buildsystem/ide-build-system-discovery.c',
'buildsystem/ide-build-target.c',
'buildsystem/ide-build-utils.c',
'buildsystem/ide-configuration-manager.c',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment