[gnome-builder] cmake: add build target provider



commit f01e37048d8d99182aaf0607d1495ae31cba971a
Author: Günther Wagner <info gunibert de>
Date:   Fri Aug 6 00:07:48 2021 +0200

    cmake: add build target provider
    
    This uses the preferred codemodel IDE integration which can be found
    here: https://cmake.org/cmake/help/latest/guide/ide-integration/index.html

 src/plugins/cmake/cmake-plugin.c                   |   4 +
 .../cmake/gbp-cmake-build-stage-codemodel.c        | 162 +++++++++++++++++
 .../cmake/gbp-cmake-build-stage-codemodel.h        |  33 ++++
 .../cmake/gbp-cmake-build-target-provider.c        | 194 +++++++++++++++++++++
 .../cmake/gbp-cmake-build-target-provider.h        |  33 ++++
 src/plugins/cmake/gbp-cmake-pipeline-addin.c       |   8 +
 src/plugins/cmake/meson.build                      |   2 +
 7 files changed, 436 insertions(+)
---
diff --git a/src/plugins/cmake/cmake-plugin.c b/src/plugins/cmake/cmake-plugin.c
index de605456c..a0505448e 100644
--- a/src/plugins/cmake/cmake-plugin.c
+++ b/src/plugins/cmake/cmake-plugin.c
@@ -27,6 +27,7 @@
 #include "gbp-cmake-build-system-discovery.h"
 #include "gbp-cmake-pipeline-addin.h"
 #include "gbp-cmake-toolchain-provider.h"
+#include "gbp-cmake-build-target-provider.h"
 
 _IDE_EXTERN void
 _gbp_cmake_register_types (PeasObjectModule *module)
@@ -43,4 +44,7 @@ _gbp_cmake_register_types (PeasObjectModule *module)
   peas_object_module_register_extension_type (module,
                                               IDE_TYPE_TOOLCHAIN_PROVIDER,
                                               GBP_TYPE_CMAKE_TOOLCHAIN_PROVIDER);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_BUILD_TARGET_PROVIDER,
+                                              GBP_TYPE_CMAKE_BUILD_TARGET_PROVIDER);
 }
diff --git a/src/plugins/cmake/gbp-cmake-build-stage-codemodel.c 
b/src/plugins/cmake/gbp-cmake-build-stage-codemodel.c
new file mode 100644
index 000000000..9568cde74
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-build-stage-codemodel.c
@@ -0,0 +1,162 @@
+/* gbp-cmake-build-stage-codemodel.c
+ *
+ * Copyright 2021 Günther Wagner <info gunibert de>
+ *
+ * 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 "gbp-cmake-build-stage-codemodel"
+
+#include <json-glib/json-glib.h>
+
+#include "gbp-cmake-build-stage-codemodel.h"
+
+struct _GbpCmakeBuildStageCodemodel
+{
+  IdePipelineStage parent_instance;
+};
+
+G_DEFINE_TYPE (GbpCmakeBuildStageCodemodel, gbp_cmake_build_stage_codemodel, IDE_TYPE_PIPELINE_STAGE)
+
+GbpCmakeBuildStageCodemodel *
+gbp_cmake_build_stage_codemodel_new (void)
+{
+  return g_object_new (GBP_TYPE_CMAKE_BUILD_STAGE_CODEMODEL, NULL);
+}
+
+static gchar *
+gbp_cmake_build_stage_codemodel_get_query_path (GbpCmakeBuildStageCodemodel *self,
+                                                IdePipeline                 *pipeline)
+{
+  g_return_val_if_fail (GBP_IS_CMAKE_BUILD_STAGE_CODEMODEL (self), NULL);
+  g_return_val_if_fail (IDE_IS_PIPELINE (pipeline), NULL);
+
+  return ide_pipeline_build_builddir_path (pipeline, ".cmake", "api", "v1", "query", "client-builder", NULL);
+}
+
+static JsonNode *
+gbp_cmake_build_stage_codemodel_create_query (GbpCmakeBuildStageCodemodel *self)
+{
+  g_autoptr(JsonBuilder) builder = NULL;
+
+  g_return_val_if_fail (GBP_IS_CMAKE_BUILD_STAGE_CODEMODEL (self), NULL);
+
+  builder = json_builder_new ();
+  json_builder_begin_object (builder);
+
+  json_builder_set_member_name (builder, "requests");
+  json_builder_begin_array (builder);
+
+  json_builder_begin_object (builder);
+
+  json_builder_set_member_name (builder, "kind");
+  json_builder_add_string_value (builder, "codemodel");
+
+  json_builder_set_member_name (builder, "version");
+  json_builder_add_int_value (builder, 2);
+
+  json_builder_end_object (builder);
+
+  json_builder_end_array (builder);
+
+  json_builder_end_object (builder);
+
+  return json_builder_get_root (builder);
+}
+
+static gboolean
+gbp_cmake_build_stage_codemodel_build (IdePipelineStage  *stage,
+                                       IdePipeline       *pipeline,
+                                       GCancellable      *cancellable,
+                                       GError           **error)
+{
+  GbpCmakeBuildStageCodemodel *self = GBP_CMAKE_BUILD_STAGE_CODEMODEL (stage);
+  g_autoptr(JsonGenerator) generator = NULL;
+  g_autoptr(JsonNode) query = NULL;
+  g_autofree gchar *path = NULL;
+  g_autofree gchar *queryfile = NULL;
+  gboolean ret;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_BUILD_STAGE_CODEMODEL (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  ide_pipeline_stage_set_active (stage, TRUE);
+
+  path = gbp_cmake_build_stage_codemodel_get_query_path (self, pipeline);
+  ret = g_mkdir_with_parents (path, 0750);
+
+  if (ret != 0)
+    {
+        g_set_error_literal (error,
+                             G_FILE_ERROR,
+                             g_file_error_from_errno (errno),
+                             g_strerror (errno));
+        IDE_RETURN (FALSE);
+    }
+
+  generator = json_generator_new ();
+  query = gbp_cmake_build_stage_codemodel_create_query (self);
+  json_generator_set_root (generator, query);
+  queryfile = g_build_filename (path, "query.json", NULL);
+  json_generator_to_file (generator, queryfile, NULL);
+
+  ide_pipeline_stage_set_active (stage, FALSE);
+
+  IDE_RETURN (TRUE);
+}
+
+static void
+gbp_cmake_build_stage_codemodel_query (IdePipelineStage *stage,
+                                       IdePipeline      *pipeline,
+                                       GPtrArray        *targets,
+                                       GCancellable     *cancellable)
+{
+  GbpCmakeBuildStageCodemodel *self = GBP_CMAKE_BUILD_STAGE_CODEMODEL (stage);
+  g_autofree gchar *path = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_BUILD_STAGE_CODEMODEL (self));
+  g_assert (IDE_IS_PIPELINE (pipeline));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  path = gbp_cmake_build_stage_codemodel_get_query_path (self, pipeline);
+  if (!g_file_test (path, G_FILE_TEST_EXISTS))
+    {
+      ide_pipeline_stage_set_completed (stage, FALSE);
+      IDE_EXIT;
+    }
+
+  ide_pipeline_stage_set_completed (stage, TRUE);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_cmake_build_stage_codemodel_class_init (GbpCmakeBuildStageCodemodelClass *klass)
+{
+  IdePipelineStageClass *stage_class = IDE_PIPELINE_STAGE_CLASS (klass);
+
+  stage_class->build = gbp_cmake_build_stage_codemodel_build;
+  stage_class->query = gbp_cmake_build_stage_codemodel_query;
+}
+
+static void
+gbp_cmake_build_stage_codemodel_init (GbpCmakeBuildStageCodemodel *self)
+{
+}
diff --git a/src/plugins/cmake/gbp-cmake-build-stage-codemodel.h 
b/src/plugins/cmake/gbp-cmake-build-stage-codemodel.h
new file mode 100644
index 000000000..a00d91ea9
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-build-stage-codemodel.h
@@ -0,0 +1,33 @@
+/* gbp-cmake-build-stage-codemodel.h
+ *
+ * Copyright 2021 Günther Wagner <info gunibert de>
+ *
+ * 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
+ */
+
+#pragma once
+
+#include <libide-foundry.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CMAKE_BUILD_STAGE_CODEMODEL (gbp_cmake_build_stage_codemodel_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCmakeBuildStageCodemodel, gbp_cmake_build_stage_codemodel, GBP, 
CMAKE_BUILD_STAGE_CODEMODEL, IdePipelineStage)
+
+GbpCmakeBuildStageCodemodel *gbp_cmake_build_stage_codemodel_new (void);
+
+G_END_DECLS
diff --git a/src/plugins/cmake/gbp-cmake-build-target-provider.c 
b/src/plugins/cmake/gbp-cmake-build-target-provider.c
new file mode 100644
index 000000000..030a6f76d
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-build-target-provider.c
@@ -0,0 +1,194 @@
+/* gbp-cmake-build-target-provider.c
+ *
+ * Copyright 2021 Günther Wagner <info gunibert de>
+ *
+ * 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
+ */
+
+#include "gbp-cmake-build-target-provider.h"
+#include "gbp-cmake-build-target.h"
+#include <json-glib/json-glib.h>
+
+struct _GbpCmakeBuildTargetProvider
+{
+  IdeObject parent_instance;
+};
+
+static void build_target_provider_iface_init (IdeBuildTargetProviderInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GbpCmakeBuildTargetProvider, gbp_cmake_build_target_provider, IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_TARGET_PROVIDER, 
build_target_provider_iface_init))
+
+GbpCmakeBuildTargetProvider *
+gbp_cmake_build_target_provider_new (void)
+{
+  return g_object_new (GBP_TYPE_CMAKE_BUILD_TARGET_PROVIDER, NULL);
+}
+
+static void
+gbp_cmake_build_target_provider_class_init (GbpCmakeBuildTargetProviderClass *klass)
+{
+}
+
+static void
+gbp_cmake_build_target_provider_init (GbpCmakeBuildTargetProvider *self)
+{
+}
+
+static void
+gbp_cmake_build_target_provider_create_target (GbpCmakeBuildTargetProvider  *self,
+                                               GPtrArray                   **ret,
+                                               IdeContext                   *context,
+                                               JsonObject                   *obj)
+{
+  g_autoptr(IdeBuildTarget) target = NULL;
+  g_autoptr(GFile) install_directory = NULL;
+  g_autofree gchar *install_dir = NULL;
+  g_autofree gchar *install_dir_abs = NULL;
+  g_autofree gchar *name = NULL;
+  JsonArray *artefacts;
+  JsonObject *path_object;
+  JsonObject *install;
+  JsonObject *prefix;
+  const gchar *artefacts_path;
+  const gchar *prefix_path;
+
+  g_return_if_fail (GBP_IS_CMAKE_BUILD_TARGET_PROVIDER (self));
+
+  artefacts = json_object_get_array_member (obj, "artifacts");
+  /* currently we support only one artefact executable */
+  path_object = json_array_get_object_element (artefacts, 0);
+  artefacts_path = json_object_get_string_member (path_object, "path");
+
+  install = json_object_get_object_member (obj, "install");
+  prefix = json_object_get_object_member (install, "prefix");
+  prefix_path = json_object_get_string_member (prefix, "path");
+
+  install_dir = g_path_get_dirname (artefacts_path);
+  install_dir_abs = g_build_path (G_DIR_SEPARATOR_S, prefix_path, install_dir, NULL);
+  install_directory = g_file_new_for_path (install_dir_abs);
+
+  name = g_path_get_basename (artefacts_path);
+  target = gbp_cmake_build_target_new (context, install_directory, name);
+
+  g_debug ("Found target %s with install directory %s", name, install_dir_abs);
+
+  g_ptr_array_add (*ret, g_steal_pointer (&target));
+}
+
+static void
+gbp_cmake_build_target_provider_get_targets_async (IdeBuildTargetProvider *provider,
+                                                   GCancellable           *cancellable,
+                                                   GAsyncReadyCallback     callback,
+                                                   gpointer                user_data)
+{
+  GbpCmakeBuildTargetProvider *self = GBP_CMAKE_BUILD_TARGET_PROVIDER (provider);
+  g_autoptr(IdeTask) task = NULL;
+  g_autoptr(GPtrArray) ret = NULL;
+  g_autoptr(GFile) reply = NULL;
+  g_autoptr(GFileEnumerator) enumerator = NULL;
+  g_autofree gchar *replydir = NULL;
+  IdeContext *context;
+  IdeBuildManager *build_manager;
+  IdePipeline *pipeline;
+  const gchar *builddir;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_BUILD_TARGET_PROVIDER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, gbp_cmake_build_target_provider_get_targets_async);
+  ide_task_set_priority (task, G_PRIORITY_LOW);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  build_manager = ide_build_manager_from_context (context);
+  pipeline = ide_build_manager_get_pipeline (build_manager);
+  builddir = ide_pipeline_get_builddir (pipeline);
+
+  replydir = g_build_path (G_DIR_SEPARATOR_S, builddir, ".cmake", "api", "v1", "reply", NULL);
+
+  if (!g_file_test (replydir, G_FILE_TEST_EXISTS))
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_EXISTS,
+                                 "Response codemodel does not exists, ignoring");
+      IDE_EXIT;
+    }
+
+  ret = g_ptr_array_new_with_free_func (g_object_unref);
+  reply = g_file_new_for_path (replydir);
+  enumerator = g_file_enumerate_children (reply, G_FILE_ATTRIBUTE_STANDARD_NAME, G_FILE_QUERY_INFO_NONE, 
cancellable, NULL);
+
+  while (TRUE)
+    {
+      g_autoptr(GFileInputStream) stream = NULL;
+      g_autoptr(JsonParser) parser = NULL;
+      GFile *file;
+      JsonNode *root;
+      JsonObject *jobject;
+
+      if (!g_file_enumerator_iterate (enumerator, NULL, &file, cancellable, NULL))
+        goto out;
+      if (!file)
+        break;
+
+      stream = g_file_read (file, cancellable, NULL);
+      parser = json_parser_new ();
+      json_parser_load_from_stream (parser, G_INPUT_STREAM (stream), cancellable, NULL);
+
+      root = json_parser_get_root (parser);
+      jobject = json_node_get_object (root);
+      if (json_object_has_member (jobject, "type") &&
+          ide_str_equal0 (json_object_get_string_member (jobject, "type"), "EXECUTABLE"))
+        {
+          gbp_cmake_build_target_provider_create_target (self, &ret, context, jobject);
+        }
+    }
+
+out:
+  IDE_PROBE;
+  ide_task_return_pointer (task, g_steal_pointer (&ret), g_ptr_array_unref);
+
+  IDE_EXIT;
+}
+
+static GPtrArray *
+gbp_cmake_build_target_provider_get_targets_finish (IdeBuildTargetProvider  *provider,
+                                                    GAsyncResult            *result,
+                                                    GError                 **error)
+{
+  GPtrArray *ret;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CMAKE_BUILD_TARGET_PROVIDER (provider));
+  g_assert (IDE_IS_TASK (result));
+  g_assert (ide_task_is_valid (IDE_TASK (result), provider));
+
+  ret = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+  IDE_RETURN (IDE_PTR_ARRAY_STEAL_FULL (&ret));
+}
+
+static void
+build_target_provider_iface_init (IdeBuildTargetProviderInterface *iface)
+{
+  iface->get_targets_async = gbp_cmake_build_target_provider_get_targets_async;
+  iface->get_targets_finish = gbp_cmake_build_target_provider_get_targets_finish;
+}
diff --git a/src/plugins/cmake/gbp-cmake-build-target-provider.h 
b/src/plugins/cmake/gbp-cmake-build-target-provider.h
new file mode 100644
index 000000000..5a7c954b8
--- /dev/null
+++ b/src/plugins/cmake/gbp-cmake-build-target-provider.h
@@ -0,0 +1,33 @@
+/* gbp-cmake-build-target-provider.h
+ *
+ * Copyright 2021 Günther Wagner <info gunibert de>
+ *
+ * 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
+ */
+
+#pragma once
+
+#include <libide-foundry.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CMAKE_BUILD_TARGET_PROVIDER (gbp_cmake_build_target_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCmakeBuildTargetProvider, gbp_cmake_build_target_provider, GBP, 
CMAKE_BUILD_TARGET_PROVIDER, IdeObject)
+
+GbpCmakeBuildTargetProvider *gbp_cmake_build_target_provider_new (void);
+
+G_END_DECLS
diff --git a/src/plugins/cmake/gbp-cmake-pipeline-addin.c b/src/plugins/cmake/gbp-cmake-pipeline-addin.c
index 0a24049b6..6335fdb38 100644
--- a/src/plugins/cmake/gbp-cmake-pipeline-addin.c
+++ b/src/plugins/cmake/gbp-cmake-pipeline-addin.c
@@ -25,6 +25,7 @@
 
 #include "gbp-cmake-build-system.h"
 #include "gbp-cmake-build-stage-cross-file.h"
+#include "gbp-cmake-build-stage-codemodel.h"
 #include "gbp-cmake-toolchain.h"
 #include "gbp-cmake-pipeline-addin.h"
 
@@ -69,6 +70,7 @@ gbp_cmake_pipeline_addin_load (IdePipelineAddin *addin,
                                IdePipeline      *pipeline)
 {
   GbpCMakePipelineAddin *self = (GbpCMakePipelineAddin *)addin;
+  g_autoptr(GbpCmakeBuildStageCodemodel) codemodel_stage = NULL;
   g_autoptr(IdeSubprocessLauncher) configure_launcher = NULL;
   g_autoptr(IdeSubprocessLauncher) build_launcher = NULL;
   g_autoptr(IdeSubprocessLauncher) install_launcher = NULL;
@@ -163,6 +165,12 @@ gbp_cmake_pipeline_addin_load (IdePipelineAddin *addin,
       ide_pipeline_addin_track (addin, id);
     }
 
+  /* Setup ide integration stage for cmake */
+  codemodel_stage = gbp_cmake_build_stage_codemodel_new ();
+  ide_pipeline_stage_set_name (IDE_PIPELINE_STAGE (codemodel_stage), "Prepare Codemodel");
+  id = ide_pipeline_attach (pipeline, IDE_PIPELINE_PHASE_PREPARE, 1, IDE_PIPELINE_STAGE (codemodel_stage));
+  ide_pipeline_addin_track (addin, id);
+
   /* Setup our configure stage. */
 
   prefix_option = g_strdup_printf ("-DCMAKE_INSTALL_PREFIX=%s", prefix);
diff --git a/src/plugins/cmake/meson.build b/src/plugins/cmake/meson.build
index f97154023..31765f413 100644
--- a/src/plugins/cmake/meson.build
+++ b/src/plugins/cmake/meson.build
@@ -6,9 +6,11 @@ plugins_sources += files([
   'gbp-cmake-build-system.c',
   'gbp-cmake-build-system-discovery.c',
   'gbp-cmake-build-target.c',
+  'gbp-cmake-build-target-provider.c',
   'gbp-cmake-pipeline-addin.c',
   'gbp-cmake-toolchain.c',
   'gbp-cmake-toolchain-provider.c',
+  'gbp-cmake-build-stage-codemodel.c',
 ])
 
 plugin_cmake_resources = gnome.compile_resources(


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