[gnome-builder] buildsystem: add plugin interface to discover build system



commit 43b1422dfeb7ec8d2a441729b386b9430c6e3716
Author: Christian Hergert <chergert redhat com>
Date:   Mon Mar 13 15:16:12 2017 -0700

    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

 libide/Makefile.am                              |    2 +
 libide/buildsystem/ide-build-system-discovery.c |   69 +++++++++++++
 libide/buildsystem/ide-build-system-discovery.h |   51 ++++++++++
 libide/ide-context.c                            |  119 +++++++++++++++++++++++
 libide/ide.h                                    |    1 +
 libide/meson.build                              |    2 +
 6 files changed, 244 insertions(+), 0 deletions(-)
---
diff --git a/libide/Makefile.am b/libide/Makefile.am
index ca1d0ca..6c2ad77 100644
--- a/libide/Makefile.am
+++ b/libide/Makefile.am
@@ -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                             \
diff --git a/libide/buildsystem/ide-build-system-discovery.c b/libide/buildsystem/ide-build-system-discovery.c
new file mode 100644
index 0000000..a9e52b7
--- /dev/null
+++ b/libide/buildsystem/ide-build-system-discovery.c
@@ -0,0 +1,69 @@
+/* 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;
+}
diff --git a/libide/buildsystem/ide-build-system-discovery.h b/libide/buildsystem/ide-build-system-discovery.h
new file mode 100644
index 0000000..8aa98aa
--- /dev/null
+++ b/libide/buildsystem/ide-build-system-discovery.h
@@ -0,0 +1,51 @@
+/* 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 */
diff --git a/libide/ide-context.c b/libide/ide-context.c
index 6ddf5b0..780762e 100644
--- a/libide/ide-context.c
+++ b/libide/ide-context.c
@@ -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));
@@ -1503,6 +1508,119 @@ ide_context_init_loaded (gpointer             source_object,
 }
 
 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,
                         GCancellable        *cancellable,
@@ -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,
diff --git a/libide/ide.h b/libide/ide.h
index 587201b..a05ac0c 100644
--- a/libide/ide.h
+++ b/libide/ide.h
@@ -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"
diff --git a/libide/meson.build b/libide/meson.build
index a4636f3..ee0cf86 100644
--- a/libide/meson.build
+++ b/libide/meson.build
@@ -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',


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