[gnome-builder/wip/gtk4-port: 1157/1774] plugins/cargo: port Cargo build system plugin to C




commit cac436f5b43cd472c45c69777fd916a157f819a2
Author: Christian Hergert <chergert redhat com>
Date:   Wed May 25 13:59:42 2022 -0700

    plugins/cargo: port Cargo build system plugin to C
    
    This is an incremental step on our path in #1670 to remove PyGObject
    plugins or port them to C.

 src/plugins/cargo/cargo-plugin.c                   |  55 +++++
 src/plugins/cargo/cargo.gresource.xml              |   6 +
 src/plugins/cargo/cargo.plugin                     |  10 +-
 src/plugins/cargo/cargo_plugin.py                  | 257 ---------------------
 .../cargo/gbp-cargo-build-system-discovery.c       |  47 ++++
 .../cargo/gbp-cargo-build-system-discovery.h       |  31 +++
 src/plugins/cargo/gbp-cargo-build-system.c         | 252 ++++++++++++++++++++
 src/plugins/cargo/gbp-cargo-build-system.h         |  37 +++
 src/plugins/cargo/gbp-cargo-dependency-updater.c   | 168 ++++++++++++++
 src/plugins/cargo/gbp-cargo-dependency-updater.h   |  31 +++
 src/plugins/cargo/gbp-cargo-pipeline-addin.c       | 178 ++++++++++++++
 src/plugins/cargo/gbp-cargo-pipeline-addin.h       |  31 +++
 src/plugins/cargo/gbp-cargo-run-command-provider.c | 123 ++++++++++
 src/plugins/cargo/gbp-cargo-run-command-provider.h |  31 +++
 src/plugins/cargo/meson.build                      |  23 +-
 15 files changed, 1009 insertions(+), 271 deletions(-)
---
diff --git a/src/plugins/cargo/cargo-plugin.c b/src/plugins/cargo/cargo-plugin.c
new file mode 100644
index 000000000..9f049e878
--- /dev/null
+++ b/src/plugins/cargo/cargo-plugin.c
@@ -0,0 +1,55 @@
+/* cargo-plugin.c
+ *
+ * Copyright 2016-2022 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 "cargo-plugin"
+
+#include "config.h"
+
+#include <libpeas/peas.h>
+
+#include <libide-editor.h>
+#include <libide-gui.h>
+#include <libide-tree.h>
+
+#include "gbp-cargo-build-system.h"
+#include "gbp-cargo-build-system-discovery.h"
+#include "gbp-cargo-dependency-updater.h"
+#include "gbp-cargo-pipeline-addin.h"
+#include "gbp-cargo-run-command-provider.h"
+
+_IDE_EXTERN void
+_gbp_cargo_register_types (PeasObjectModule *module)
+{
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_BUILD_SYSTEM,
+                                              GBP_TYPE_CARGO_BUILD_SYSTEM);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_BUILD_SYSTEM_DISCOVERY,
+                                              GBP_TYPE_CARGO_BUILD_SYSTEM_DISCOVERY);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_DEPENDENCY_UPDATER,
+                                              GBP_TYPE_CARGO_DEPENDENCY_UPDATER);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_PIPELINE_ADDIN,
+                                              GBP_TYPE_CARGO_PIPELINE_ADDIN);
+  peas_object_module_register_extension_type (module,
+                                              IDE_TYPE_RUN_COMMAND_PROVIDER,
+                                              GBP_TYPE_CARGO_RUN_COMMAND_PROVIDER);
+}
diff --git a/src/plugins/cargo/cargo.gresource.xml b/src/plugins/cargo/cargo.gresource.xml
new file mode 100644
index 000000000..7270ec40e
--- /dev/null
+++ b/src/plugins/cargo/cargo.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/plugins/cargo">
+    <file>cargo.plugin</file>
+  </gresource>
+</gresources>
diff --git a/src/plugins/cargo/cargo.plugin b/src/plugins/cargo/cargo.plugin
index 14d8a9f34..cfb0e8a27 100644
--- a/src/plugins/cargo/cargo.plugin
+++ b/src/plugins/cargo/cargo.plugin
@@ -1,12 +1,10 @@
 [Plugin]
 Authors=Christian Hergert <christian hergert me>
 Builtin=true
-Copyright=Copyright © 2016 Christian Hergert
+Copyright=Copyright © 2016-2022 Christian Hergert
 Description=Provides integration with the Cargo build system
-Hidden=true
-Loader=python3
-Module=cargo_plugin
-Name=Cargo
+Embedded=_gbp_cargo_register_types
+Module=cargo
+Name=Cargo Build System
 X-Project-File-Filter-Name=Cargo (Cargo.toml)
 X-Project-File-Filter-Pattern=Cargo.toml
-X-Builder-ABI=@PACKAGE_ABI@
diff --git a/src/plugins/cargo/gbp-cargo-build-system-discovery.c 
b/src/plugins/cargo/gbp-cargo-build-system-discovery.c
new file mode 100644
index 000000000..98a133348
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-build-system-discovery.c
@@ -0,0 +1,47 @@
+/* gbp-cargo-build-system-discovery.c
+ *
+ * Copyright 2016-2022 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 "gbp-cargo-build-system-discovery"
+
+#include "config.h"
+
+#include "gbp-cargo-build-system-discovery.h"
+
+struct _GbpCargoBuildSystemDiscovery
+{
+  IdeSimpleBuildSystemDiscovery parent_instance;
+};
+
+G_DEFINE_FINAL_TYPE (GbpCargoBuildSystemDiscovery, gbp_cargo_build_system_discovery, 
IDE_TYPE_SIMPLE_BUILD_SYSTEM_DISCOVERY)
+
+static void
+gbp_cargo_build_system_discovery_class_init (GbpCargoBuildSystemDiscoveryClass *klass)
+{
+}
+
+static void
+gbp_cargo_build_system_discovery_init (GbpCargoBuildSystemDiscovery *self)
+{
+  g_object_set (self,
+                "glob", "Cargo.toml",
+                "hint", "cargo",
+                "priority", -200,
+                NULL);
+}
diff --git a/src/plugins/cargo/gbp-cargo-build-system-discovery.h 
b/src/plugins/cargo/gbp-cargo-build-system-discovery.h
new file mode 100644
index 000000000..15d278eea
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-build-system-discovery.h
@@ -0,0 +1,31 @@
+/* gbp-cargo-build-system-discovery.h
+ *
+ * Copyright 2016-2022 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
+ */
+
+#pragma once
+
+#include <libide-foundry.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CARGO_BUILD_SYSTEM_DISCOVERY (gbp_cargo_build_system_discovery_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCargoBuildSystemDiscovery, gbp_cargo_build_system_discovery, GBP, 
CARGO_BUILD_SYSTEM_DISCOVERY, IdeSimpleBuildSystemDiscovery)
+
+G_END_DECLS
diff --git a/src/plugins/cargo/gbp-cargo-build-system.c b/src/plugins/cargo/gbp-cargo-build-system.c
new file mode 100644
index 000000000..b281306c4
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-build-system.c
@@ -0,0 +1,252 @@
+/* gbp-cargo-build-system.c
+ *
+ * Copyright 2016-2022 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 "gbp-cargo-build-system"
+#define CARGO "cargo"
+
+#include "config.h"
+
+#include "gbp-cargo-build-system.h"
+
+struct _GbpCargoBuildSystem
+{
+  IdeObject  parent_instance;
+  GFile     *project_file;
+};
+
+enum {
+  PROP_0,
+  PROP_PROJECT_FILE,
+  N_PROPS
+};
+
+static char *
+gbp_cargo_build_system_get_id (IdeBuildSystem *build_system)
+{
+  return g_strdup (CARGO);
+}
+
+static char *
+gbp_cargo_build_system_get_display_name (IdeBuildSystem *build_system)
+{
+  return g_strdup ("Cargo");
+}
+
+static int
+gbp_cargo_build_system_get_priority (IdeBuildSystem *build_system)
+{
+  return -200;
+}
+
+static gboolean
+gbp_cargo_build_system_supports_language (IdeBuildSystem *build_system,
+                                          const char     *language)
+{
+  return g_strv_contains (IDE_STRV_INIT ("rust", "c", "cpp"), language);
+}
+
+static void
+build_system_iface_init (IdeBuildSystemInterface *iface)
+{
+  iface->get_id = gbp_cargo_build_system_get_id;
+  iface->get_display_name = gbp_cargo_build_system_get_display_name;
+  iface->get_priority = gbp_cargo_build_system_get_priority;
+  iface->supports_language = gbp_cargo_build_system_supports_language;
+}
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (GbpCargoBuildSystem, gbp_cargo_build_system, IDE_TYPE_OBJECT,
+                               G_IMPLEMENT_INTERFACE (IDE_TYPE_BUILD_SYSTEM, build_system_iface_init))
+
+static GParamSpec *properties [N_PROPS];
+
+static void
+gbp_cargo_build_system_dispose (GObject *object)
+{
+  GbpCargoBuildSystem *self = (GbpCargoBuildSystem *)object;
+
+  g_clear_object (&self->project_file);
+
+  G_OBJECT_CLASS (gbp_cargo_build_system_parent_class)->dispose (object);
+}
+
+static void
+gbp_cargo_build_system_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  GbpCargoBuildSystem *self = GBP_CARGO_BUILD_SYSTEM (object);
+
+  switch (prop_id)
+    {
+    case PROP_PROJECT_FILE:
+      g_value_set_object (value, self->project_file);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_cargo_build_system_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  GbpCargoBuildSystem *self = GBP_CARGO_BUILD_SYSTEM (object);
+
+  switch (prop_id)
+    {
+    case PROP_PROJECT_FILE:
+      g_set_object (&self->project_file, g_value_get_object (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gbp_cargo_build_system_class_init (GbpCargoBuildSystemClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = gbp_cargo_build_system_dispose;
+  object_class->get_property = gbp_cargo_build_system_get_property;
+  object_class->set_property = gbp_cargo_build_system_set_property;
+
+  properties [PROP_PROJECT_FILE] =
+    g_param_spec_object ("project-file",
+                         "Project File",
+                         "The project file (Cargo.toml)",
+                         G_TYPE_FILE,
+                         (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+gbp_cargo_build_system_init (GbpCargoBuildSystem *self)
+{
+}
+
+char *
+gbp_cargo_build_system_get_project_dir (GbpCargoBuildSystem *self)
+{
+  g_autoptr(GFile) workdir = NULL;
+  g_autofree char *base = NULL;
+  IdeContext *context;
+
+  g_return_val_if_fail (GBP_IS_CARGO_BUILD_SYSTEM (self), NULL);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  workdir = ide_context_ref_workdir (context);
+
+  if (self->project_file == NULL)
+    return g_strdup (g_file_peek_path (workdir));
+
+  base = g_file_get_basename (self->project_file);
+
+  if (strcasecmp (base, "Cargo.toml") != 0)
+    {
+      g_autoptr(GFile) parent = g_file_get_parent (self->project_file);
+      return g_file_get_path (parent);
+    }
+
+  return g_file_get_path (self->project_file);
+}
+
+char *
+gbp_cargo_build_system_get_cargo_toml_path (GbpCargoBuildSystem *self)
+{
+  g_autofree char *base = NULL;
+  g_autoptr(GFile) child = NULL;
+
+  g_return_val_if_fail (GBP_IS_CARGO_BUILD_SYSTEM (self), NULL);
+
+  base = g_file_get_basename (self->project_file);
+  if (strcasecmp (base, "Cargo.toml") == 0)
+    return g_file_get_path (self->project_file);
+
+  child = g_file_get_child (self->project_file, "Cargo.toml");
+  return g_file_get_path (child);
+}
+
+/**
+ * gbp_cargo_build_system_locate_cargo:
+ * @self: (nullable): a #GbpCargoBuildSystem or %NULL
+ * @pipeline: (nullable): an #IdePipeline or %NULL
+ * @config: (nullable): an #IdeConfig or %NULL
+ *
+ * Currently, @self may be %NULL but is kept around so that in
+ * the future we may have other fallbacks which could take use
+ * of the build system.
+ *
+ * This function will first check for "CARGO" in @config's environment
+ * variables. If specified, that will be used.
+ *
+ * Then the config's runtime+sdk-extensions will be checked and if it
+ * contains "cargo" in the pipeline's $PATH, that will be used.
+ *
+ * Then if ~/.cargo/bin/cargo exists, that will be used.
+ *
+ * Lastly, nothing was found, so "cargo" will be used with the hope
+ * that something, somewhere, will find it when executing.
+ *
+ * Returns: (transfer full) (not nullable): a path to a cargo program
+ *   or "cargo" in the case that a specific path was not found.
+ */
+char *
+gbp_cargo_build_system_locate_cargo (GbpCargoBuildSystem *self,
+                                     IdePipeline         *pipeline,
+                                     IdeConfig           *config)
+{
+  g_autofree char *cargo_in_home = NULL;
+  IdeRuntime *runtime = NULL;
+  const char *envvar;
+
+  g_return_val_if_fail (!self || GBP_IS_CARGO_BUILD_SYSTEM (self), NULL);
+  g_return_val_if_fail (!pipeline || IDE_IS_PIPELINE (pipeline), NULL);
+  g_return_val_if_fail (!config || IDE_IS_CONFIG (config), NULL);
+
+  /* First check CARGO=path override in IdeConfig */
+  if (config != NULL)
+    {
+      if ((envvar = ide_config_getenv (config, "CARGO")))
+        return g_strdup (envvar);
+    }
+
+  /* Next see if the pipeline or one of it's extensions has Cargo */
+  if (pipeline != NULL)
+    {
+      if (ide_pipeline_contains_program_in_path (pipeline, CARGO, NULL))
+        return g_strdup (CARGO);
+    }
+
+  /* Now see if the user has cargo installed in ~/.cargo/bin */
+  cargo_in_home = g_build_filename (g_get_home_dir (), "bin", CARGO, NULL);
+  if (g_file_test (cargo_in_home, G_FILE_TEST_IS_EXECUTABLE))
+    return g_steal_pointer (&cargo_in_home);
+
+  /* Fallback to "cargo" and hope for the best */
+  return g_strdup (CARGO);
+}
+
diff --git a/src/plugins/cargo/gbp-cargo-build-system.h b/src/plugins/cargo/gbp-cargo-build-system.h
new file mode 100644
index 000000000..143b89857
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-build-system.h
@@ -0,0 +1,37 @@
+/* gbp-cargo-build-system.h
+ *
+ * Copyright 2016-2022 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
+ */
+
+#pragma once
+
+#include <libide-foundry.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CARGO_BUILD_SYSTEM (gbp_cargo_build_system_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCargoBuildSystem, gbp_cargo_build_system, GBP, CARGO_BUILD_SYSTEM, IdeObject)
+
+char *gbp_cargo_build_system_get_cargo_toml_path (GbpCargoBuildSystem *self);
+char *gbp_cargo_build_system_get_project_dir     (GbpCargoBuildSystem *self);
+char *gbp_cargo_build_system_locate_cargo        (GbpCargoBuildSystem *self,
+                                                  IdePipeline         *pipeline,
+                                                  IdeConfig           *config);
+
+G_END_DECLS
diff --git a/src/plugins/cargo/gbp-cargo-dependency-updater.c 
b/src/plugins/cargo/gbp-cargo-dependency-updater.c
new file mode 100644
index 000000000..48efb6adc
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-dependency-updater.c
@@ -0,0 +1,168 @@
+/* gbp-cargo-dependency-updater.c
+ *
+ * Copyright 2016-2022 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 "gbp-cargo-dependency-updater"
+
+#include "config.h"
+
+#include <libide-foundry.h>
+#include <libide-threading.h>
+
+#include "gbp-cargo-build-system.h"
+#include "gbp-cargo-dependency-updater.h"
+
+struct _GbpCargoDependencyUpdater
+{
+  IdeObject parent_instance;
+};
+
+static void
+gbp_cargo_dependency_updater_wait_check_cb (GObject      *object,
+                                            GAsyncResult *result,
+                                            gpointer      user_data)
+{
+  IdeSubprocess *subprocess = (IdeSubprocess *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_SUBPROCESS (subprocess));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  if (!ide_subprocess_wait_check_finish (subprocess, result, &error))
+    ide_task_return_error (task, g_steal_pointer (&error));
+  else
+    ide_task_return_boolean (task, TRUE);
+
+  IDE_EXIT;
+}
+
+static void
+gbp_cargo_dependency_updater_update_async (IdeDependencyUpdater *updater,
+                                           GCancellable         *cancellable,
+                                           GAsyncReadyCallback   callback,
+                                           gpointer              user_data)
+{
+  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
+  g_autoptr(IdeSubprocess) subprocess = NULL;
+  g_autoptr(IdeTask) task = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autofree char *cargo_toml = NULL;
+  g_autofree char *cargo = NULL;
+  IdeBuildManager *build_manager;
+  IdeBuildSystem *build_system;
+  IdePipeline *pipeline;
+  IdeContext *context;
+  const char *builddir;
+  IdeConfig *config;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CARGO_DEPENDENCY_UPDATER (updater));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (updater, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, gbp_cargo_dependency_updater_update_async);
+
+  context = ide_object_get_context (IDE_OBJECT (updater));
+  build_system = ide_build_system_from_context (context);
+
+  if (!GBP_IS_CARGO_BUILD_SYSTEM (build_system))
+    {
+      ide_task_return_unsupported_error (task);
+      IDE_EXIT;
+    }
+
+  build_manager = ide_build_manager_from_context (context);
+  pipeline = ide_build_manager_get_pipeline (build_manager);
+
+  if (pipeline == NULL)
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_NOT_INITIALIZED,
+                                 "Cannot update cargo dependencies. Build pipeline is not initialized.");
+      IDE_EXIT;
+    }
+
+  config = ide_pipeline_get_config (pipeline);
+  cargo = gbp_cargo_build_system_locate_cargo (GBP_CARGO_BUILD_SYSTEM (build_system), pipeline, config);
+  cargo_toml = gbp_cargo_build_system_get_cargo_toml_path (GBP_CARGO_BUILD_SYSTEM (build_system));
+
+  launcher = ide_pipeline_create_launcher (pipeline, NULL);
+  builddir = ide_pipeline_get_builddir (pipeline);
+  ide_subprocess_launcher_setenv (launcher, "CARGO_TARGET_DIR", builddir, TRUE);
+  ide_subprocess_launcher_push_argv (launcher, cargo);
+  ide_subprocess_launcher_push_argv (launcher, "update");
+  ide_subprocess_launcher_push_argv (launcher, "--manifest-path");
+  ide_subprocess_launcher_push_argv (launcher, cargo_toml);
+  ide_pipeline_attach_pty (pipeline, launcher);
+
+  if (!(subprocess = ide_subprocess_launcher_spawn (launcher, cancellable, NULL)))
+    {
+      ide_task_return_error (task, g_steal_pointer (&error));
+      IDE_EXIT;
+    }
+
+  ide_subprocess_wait_check_async (subprocess,
+                                   cancellable,
+                                   gbp_cargo_dependency_updater_wait_check_cb,
+                                   g_steal_pointer (&task));
+
+  IDE_EXIT;
+}
+
+static gboolean
+gbp_cargo_dependency_updater_update_finish (IdeDependencyUpdater  *updater,
+                                            GAsyncResult          *result,
+                                            GError               **error)
+{
+  gboolean ret;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CARGO_BUILD_SYSTEM (updater));
+  g_assert (IDE_IS_TASK (result));
+
+  ret = ide_task_propagate_boolean (IDE_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
+
+static void
+dependency_updater_iface_init (IdeDependencyUpdaterInterface *iface)
+{
+  iface->update_async = gbp_cargo_dependency_updater_update_async;
+  iface->update_finish = gbp_cargo_dependency_updater_update_finish;
+}
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (GbpCargoDependencyUpdater, gbp_cargo_dependency_updater, IDE_TYPE_OBJECT,
+                               G_IMPLEMENT_INTERFACE (IDE_TYPE_DEPENDENCY_UPDATER, 
dependency_updater_iface_init))
+static void
+gbp_cargo_dependency_updater_class_init (GbpCargoDependencyUpdaterClass *klass)
+{
+}
+
+static void
+gbp_cargo_dependency_updater_init (GbpCargoDependencyUpdater *self)
+{
+}
diff --git a/src/plugins/cargo/gbp-cargo-dependency-updater.h 
b/src/plugins/cargo/gbp-cargo-dependency-updater.h
new file mode 100644
index 000000000..044846358
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-dependency-updater.h
@@ -0,0 +1,31 @@
+/* gbp-cargo-dependency-updater.h
+ *
+ * Copyright 2016-2022 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
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CARGO_DEPENDENCY_UPDATER (gbp_cargo_dependency_updater_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCargoDependencyUpdater, gbp_cargo_dependency_updater, GBP, 
CARGO_DEPENDENCY_UPDATER, IdeObject)
+
+G_END_DECLS
diff --git a/src/plugins/cargo/gbp-cargo-pipeline-addin.c b/src/plugins/cargo/gbp-cargo-pipeline-addin.c
new file mode 100644
index 000000000..ad0123289
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-pipeline-addin.c
@@ -0,0 +1,178 @@
+/* gbp-cargo-pipeline-addin.c
+ *
+ * Copyright 2016-2022 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 "gbp-cargo-pipeline-addin"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <libide-foundry.h>
+
+#include "gbp-cargo-build-system.h"
+#include "gbp-cargo-pipeline-addin.h"
+
+struct _GbpCargoPipelineAddin
+{
+  IdeObject parent_instance;
+};
+
+static IdeSubprocessLauncher *
+create_launcher (IdePipeline *pipeline,
+                 const char  *project_dir,
+                 const char  *cargo)
+{
+  IdeSubprocessLauncher *ret;
+  const char *builddir;
+
+  g_assert (IDE_IS_PIPELINE (pipeline));
+
+  if (!(ret = ide_pipeline_create_launcher (pipeline, NULL)))
+    return NULL;
+
+  builddir = ide_pipeline_get_builddir (pipeline);
+  ide_subprocess_launcher_setenv (ret, "CARGO_TARGET_DIR", builddir, TRUE);
+  ide_subprocess_launcher_set_cwd (ret, project_dir);
+  ide_subprocess_launcher_push_argv (ret, cargo);
+
+  return ret;
+}
+
+static void
+query_cb (IdePipelineStage *stage,
+          IdePipeline      *pipeline,
+          GPtrArray        *targets,
+          GCancellable     *cancellable,
+          gpointer          user_data)
+{
+  g_assert (IDE_IS_PIPELINE_STAGE (stage));
+  g_assert (IDE_IS_PIPELINE (pipeline));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  /* Always defer to cargo to check if build is needed */
+  ide_pipeline_stage_set_completed (stage, FALSE);
+}
+
+static void
+gbp_cargo_pipeline_addin_load (IdePipelineAddin *addin,
+                               IdePipeline      *pipeline)
+{
+  g_autoptr(IdeSubprocessLauncher) fetch_launcher = NULL;
+  g_autoptr(IdeSubprocessLauncher) build_launcher = NULL;
+  g_autoptr(IdeSubprocessLauncher) clean_launcher = NULL;
+  IdePipelineStage *stage;
+  g_autofree char *project_dir = NULL;
+  g_autofree char *cargo = NULL;
+  IdeBuildSystem *build_system;
+  const char *config_opts;
+  IdeContext *context;
+  IdeConfig *config;
+  guint id;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CARGO_PIPELINE_ADDIN (addin));
+  g_assert (IDE_IS_PIPELINE (pipeline));
+
+  context = ide_object_get_context (IDE_OBJECT (addin));
+  build_system = ide_build_system_from_context (context);
+
+  if (!GBP_IS_CARGO_BUILD_SYSTEM (build_system))
+    IDE_EXIT;
+
+  project_dir = gbp_cargo_build_system_get_project_dir (GBP_CARGO_BUILD_SYSTEM (build_system));
+  config = ide_pipeline_get_config (pipeline);
+  config_opts = ide_config_get_config_opts (config);
+  cargo = gbp_cargo_build_system_locate_cargo (GBP_CARGO_BUILD_SYSTEM (build_system), pipeline, config);
+
+  g_assert (project_dir != NULL);
+  g_assert (IDE_IS_CONFIG (config));
+  g_assert (cargo != NULL);
+
+  fetch_launcher = create_launcher (pipeline, project_dir, cargo);
+  ide_subprocess_launcher_push_argv (fetch_launcher, "fetch");
+  id = ide_pipeline_attach_launcher (pipeline, IDE_PIPELINE_PHASE_DOWNLOADS, 0, fetch_launcher);
+  ide_pipeline_addin_track (addin, id);
+
+  build_launcher = create_launcher (pipeline, project_dir, cargo);
+  ide_subprocess_launcher_push_argv (build_launcher, "build");
+  ide_subprocess_launcher_push_argv (build_launcher, "--message-format");
+  ide_subprocess_launcher_push_argv (build_launcher, "human");
+
+  if (!ide_pipeline_is_native (pipeline))
+    {
+      IdeTriplet *triplet = ide_pipeline_get_host_triplet (pipeline);
+
+      ide_subprocess_launcher_push_argv (build_launcher, "--target");
+      ide_subprocess_launcher_push_argv (build_launcher, ide_triplet_get_full_name (triplet));
+    }
+
+  if (ide_config_get_parallelism (config) > 0)
+    {
+      int j = ide_config_get_parallelism (config);
+      ide_subprocess_launcher_push_argv_format (build_launcher, "-j%d", j);
+    }
+
+  if (!ide_config_get_debug (config))
+    ide_subprocess_launcher_push_argv (build_launcher, "--release");
+
+  /* Configure Options get passed to "cargo build" because there is no
+   * equivalent "configure stage" for cargo.
+   */
+  if (!ide_str_empty0 (config_opts))
+    {
+      g_auto(GStrv) args = NULL;
+      int argc;
+
+      if (g_shell_parse_argv (config_opts, &argc, &args, NULL))
+        ide_subprocess_launcher_push_args (build_launcher, (const char * const *)args);
+    }
+
+  clean_launcher = create_launcher (pipeline, project_dir, cargo);
+  ide_subprocess_launcher_push_argv (clean_launcher, "clean");
+
+  stage = ide_pipeline_stage_launcher_new (context, build_launcher);
+  ide_pipeline_stage_set_name (stage, _("Building project"));
+  ide_pipeline_stage_launcher_set_clean_launcher (IDE_PIPELINE_STAGE_LAUNCHER (stage), clean_launcher);
+  g_signal_connect (stage, "query", G_CALLBACK (query_cb), NULL);
+  id = ide_pipeline_attach (pipeline, IDE_PIPELINE_PHASE_BUILD, 0, stage);
+  ide_pipeline_addin_track (addin, id);
+
+  IDE_EXIT;
+}
+
+static void
+pipeline_addin_iface_init (IdePipelineAddinInterface *iface)
+{
+  iface->load = gbp_cargo_pipeline_addin_load;
+}
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (GbpCargoPipelineAddin, gbp_cargo_pipeline_addin, IDE_TYPE_OBJECT,
+                               G_IMPLEMENT_INTERFACE (IDE_TYPE_PIPELINE_ADDIN, pipeline_addin_iface_init))
+
+static void
+gbp_cargo_pipeline_addin_class_init (GbpCargoPipelineAddinClass *klass)
+{
+}
+
+static void
+gbp_cargo_pipeline_addin_init (GbpCargoPipelineAddin *self)
+{
+}
diff --git a/src/plugins/cargo/gbp-cargo-pipeline-addin.h b/src/plugins/cargo/gbp-cargo-pipeline-addin.h
new file mode 100644
index 000000000..cdb864b2a
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-pipeline-addin.h
@@ -0,0 +1,31 @@
+/* gbp-cargo-pipeline-addin.h
+ *
+ * Copyright 2016-2022 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
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CARGO_PIPELINE_ADDIN (gbp_cargo_pipeline_addin_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCargoPipelineAddin, gbp_cargo_pipeline_addin, GBP, CARGO_PIPELINE_ADDIN, IdeObject)
+
+G_END_DECLS
diff --git a/src/plugins/cargo/gbp-cargo-run-command-provider.c 
b/src/plugins/cargo/gbp-cargo-run-command-provider.c
new file mode 100644
index 000000000..1132db582
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-run-command-provider.c
@@ -0,0 +1,123 @@
+/* gbp-cargo-run-command-provider.c
+ *
+ * Copyright 2016-2022 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 "gbp-cargo-run-command-provider"
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+
+#include <libide-foundry.h>
+#include <libide-threading.h>
+
+#include "gbp-cargo-build-system.h"
+#include "gbp-cargo-run-command-provider.h"
+
+struct _GbpCargoRunCommandProvider
+{
+  IdeObject parent_instance;
+};
+
+static void
+gbp_cargo_run_command_provider_list_commands_async (IdeRunCommandProvider *provider,
+                                                    GCancellable          *cancellable,
+                                                    GAsyncReadyCallback    callback,
+                                                    gpointer               user_data)
+{
+  GbpCargoRunCommandProvider *self = (GbpCargoRunCommandProvider *)provider;
+  g_autoptr(IdeRunCommand) run_command = NULL;
+  g_autoptr(GListStore) store = NULL;
+  g_autoptr(IdeTask) task = NULL;
+  g_autofree char *cargo_toml = NULL;
+  IdeBuildSystem *build_system;
+  IdeContext *context;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CARGO_RUN_COMMAND_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_cargo_run_command_provider_list_commands_async);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  build_system = ide_build_system_from_context (context);
+
+  if (!GBP_IS_CARGO_BUILD_SYSTEM (build_system))
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_NOT_SUPPORTED,
+                                 "Not a cargo build system");
+      IDE_EXIT;
+    }
+
+  cargo_toml = gbp_cargo_build_system_get_cargo_toml_path (GBP_CARGO_BUILD_SYSTEM (build_system));
+
+  run_command = ide_run_command_new ();
+  ide_run_command_set_id (run_command, "cargo:run");
+  ide_run_command_set_priority (run_command, -500);
+  ide_run_command_set_display_name (run_command, _("Cargo Run"));
+  /* Pass Cargo.toml path so we are CWD independent */
+  ide_run_command_set_argv (run_command, IDE_STRV_INIT ("cargo", "run", "--manifest-path", cargo_toml));
+
+  store = g_list_store_new (IDE_TYPE_RUN_COMMAND);
+  g_list_store_append (store, run_command);
+  ide_task_return_pointer (task, g_steal_pointer (&store), g_object_unref);
+
+  IDE_EXIT;
+}
+
+static GListModel *
+gbp_cargo_run_command_provider_list_commands_finish (IdeRunCommandProvider *provider,
+                                                     GAsyncResult *result,
+                                                     GError **error)
+{
+  GListModel *ret;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_CARGO_RUN_COMMAND_PROVIDER (provider));
+  g_assert (IDE_IS_TASK (result));
+
+  ret = ide_task_propagate_pointer (IDE_TASK (result), error);
+
+  IDE_RETURN (ret);
+}
+
+static void
+run_command_provider_iface_init (IdeRunCommandProviderInterface *iface)
+{
+  iface->list_commands_async = gbp_cargo_run_command_provider_list_commands_async;
+  iface->list_commands_finish = gbp_cargo_run_command_provider_list_commands_finish;
+}
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (GbpCargoRunCommandProvider, gbp_cargo_run_command_provider, IDE_TYPE_OBJECT,
+                               G_IMPLEMENT_INTERFACE (IDE_TYPE_RUN_COMMAND_PROVIDER, 
run_command_provider_iface_init))
+
+static void
+gbp_cargo_run_command_provider_class_init (GbpCargoRunCommandProviderClass *klass)
+{
+}
+
+static void
+gbp_cargo_run_command_provider_init (GbpCargoRunCommandProvider *self)
+{
+}
diff --git a/src/plugins/cargo/gbp-cargo-run-command-provider.h 
b/src/plugins/cargo/gbp-cargo-run-command-provider.h
new file mode 100644
index 000000000..337936c57
--- /dev/null
+++ b/src/plugins/cargo/gbp-cargo-run-command-provider.h
@@ -0,0 +1,31 @@
+/* gbp-cargo-run-command-provider.h
+ *
+ * Copyright 2016-2022 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
+ */
+
+#pragma once
+
+#include <libide-core.h>
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_CARGO_RUN_COMMAND_PROVIDER (gbp_cargo_run_command_provider_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpCargoRunCommandProvider, gbp_cargo_run_command_provider, GBP, 
CARGO_RUN_COMMAND_PROVIDER, IdeObject)
+
+G_END_DECLS
diff --git a/src/plugins/cargo/meson.build b/src/plugins/cargo/meson.build
index 4b975cbea..f979a49d7 100644
--- a/src/plugins/cargo/meson.build
+++ b/src/plugins/cargo/meson.build
@@ -1,13 +1,20 @@
 if get_option('plugin_cargo')
 
-install_data('cargo_plugin.py', install_dir: plugindir)
-
-configure_file(
-          input: 'cargo.plugin',
-         output: 'cargo.plugin',
-  configuration: config_h,
-        install: true,
-    install_dir: plugindir,
+plugins_sources += files([
+  'cargo-plugin.c',
+  'gbp-cargo-build-system-discovery.c',
+  'gbp-cargo-build-system.c',
+  'gbp-cargo-dependency-updater.c',
+  'gbp-cargo-pipeline-addin.c',
+  'gbp-cargo-run-command-provider.c',
+])
+
+plugin_cargo_resources = gnome.compile_resources(
+  'cargo-resources',
+  'cargo.gresource.xml',
+  c_name: 'gbp_cargo',
 )
 
+plugins_sources += plugin_cargo_resources
+
 endif


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