[gnome-builder] git: add dependency updater for git submodules



commit 57003ef97fc6dbc41475009a83a4cf176e4c49bd
Author: Christian Hergert <chergert redhat com>
Date:   Wed Oct 3 16:29:26 2018 -0700

    git: add dependency updater for git submodules
    
    When clicking "Update Dependencies" in the UI, we can now update git
    submodules along with the flatpak dependencies.
    
    In the future, we probably want to remove the build pipeline advancement
    from the updaters themselves, and instead do that from the code that
    creates the updater plugin instances so that we don't race.

 src/plugins/git/ide-git-dependency-updater.c | 166 ++++++++++++++++++++
 src/plugins/git/ide-git-dependency-updater.h |  31 ++++
 src/plugins/git/ide-git-pipeline-addin.c     | 156 +------------------
 src/plugins/git/ide-git-plugin.c             |   4 +
 src/plugins/git/ide-git-submodule-stage.c    | 220 +++++++++++++++++++++++++++
 src/plugins/git/ide-git-submodule-stage.h    |  34 +++++
 src/plugins/git/meson.build                  |   4 +
 7 files changed, 466 insertions(+), 149 deletions(-)
---
diff --git a/src/plugins/git/ide-git-dependency-updater.c b/src/plugins/git/ide-git-dependency-updater.c
new file mode 100644
index 000000000..5e938f8ff
--- /dev/null
+++ b/src/plugins/git/ide-git-dependency-updater.c
@@ -0,0 +1,166 @@
+/* ide-git-dependency-updater.c
+ *
+ * Copyright 2018 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
+ */
+
+#include "config.h"
+
+#define G_LOG_DOMAIN "ide-git-dependency-updater"
+
+#include "ide-git-dependency-updater.h"
+#include "ide-git-submodule-stage.h"
+
+struct _IdeGitDependencyUpdater
+{
+  IdeObject parent_instance;
+};
+
+static void
+find_submodule_stage_cb (gpointer data,
+                         gpointer user_data)
+{
+  IdeGitSubmoduleStage **stage = user_data;
+
+  g_assert (IDE_IS_BUILD_STAGE (data));
+  g_assert (stage != NULL);
+  g_assert (*stage == NULL || IDE_IS_BUILD_STAGE (*stage));
+
+  if (IDE_IS_GIT_SUBMODULE_STAGE (data))
+    *stage = IDE_GIT_SUBMODULE_STAGE (data);
+}
+
+static void
+ide_git_dependency_updater_update_cb (GObject      *object,
+                                      GAsyncResult *result,
+                                      gpointer      user_data)
+{
+  IdeBuildManager *manager = (IdeBuildManager *)object;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_BUILD_MANAGER (manager));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  if (!ide_build_manager_rebuild_finish (manager, result, &error))
+    ide_task_return_error (task, g_steal_pointer (&error));
+  else
+    ide_task_return_boolean (task, TRUE);
+
+  IDE_EXIT;
+}
+
+static void
+ide_git_dependency_updater_update_async (IdeDependencyUpdater *self,
+                                         GCancellable         *cancellable,
+                                         GAsyncReadyCallback   callback,
+                                         gpointer              user_data)
+{
+  g_autoptr(IdeTask) task = NULL;
+  IdeGitSubmoduleStage *stage = NULL;
+  IdeBuildPipeline *pipeline;
+  IdeBuildManager *manager;
+  IdeContext *context;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_GIT_DEPENDENCY_UPDATER (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, ide_git_dependency_updater_update_async);
+  ide_task_set_priority (task, G_PRIORITY_LOW);
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  manager = ide_context_get_build_manager (context);
+  pipeline = ide_build_manager_get_pipeline (manager);
+
+  g_assert (!pipeline || IDE_IS_BUILD_PIPELINE (pipeline));
+
+  if (pipeline == NULL)
+    {
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_FAILED,
+                                 "Cannot update git submodules until build pipeline is initialized");
+      IDE_EXIT;
+    }
+
+  /* Find the submodule stage and tell it to download updates one time */
+  ide_build_pipeline_foreach_stage (pipeline, find_submodule_stage_cb, &stage);
+
+  if (stage == NULL)
+    {
+      /* Synthesize success if there is no submodule stage */
+      ide_task_return_boolean (task, TRUE);
+      IDE_EXIT;
+    }
+
+  ide_git_submodule_stage_force_update (stage);
+
+  /* Ensure downloads and everything past it is invalidated */
+  ide_build_pipeline_invalidate_phase (pipeline, IDE_BUILD_PHASE_DOWNLOADS);
+
+  /* Start building all the way up to the project configure so that
+   * the user knows if the updates broke their configuration or anything.
+   *
+   * TODO: This should probably be done by the calling API so that we don't
+   *       race with other updaters.
+   */
+  ide_build_manager_rebuild_async (manager,
+                                   IDE_BUILD_PHASE_CONFIGURE,
+                                   NULL,
+                                  ide_git_dependency_updater_update_cb,
+                                   g_steal_pointer (&task));
+
+  IDE_EXIT;
+}
+
+static gboolean
+ide_git_dependency_updater_update_finish (IdeDependencyUpdater  *self,
+                                          GAsyncResult          *result,
+                                          GError               **error)
+{
+  g_assert (IDE_IS_GIT_DEPENDENCY_UPDATER (self));
+  g_assert (IDE_IS_TASK (result));
+
+  return ide_task_propagate_boolean (IDE_TASK (result), error);
+}
+
+static void
+dependency_updater_iface_init (IdeDependencyUpdaterInterface *iface)
+{
+  iface->update_async = ide_git_dependency_updater_update_async;
+  iface->update_finish = ide_git_dependency_updater_update_finish;
+}
+
+G_DEFINE_TYPE_WITH_CODE (IdeGitDependencyUpdater, ide_git_dependency_updater, IDE_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (IDE_TYPE_DEPENDENCY_UPDATER,
+                                                dependency_updater_iface_init))
+
+static void
+ide_git_dependency_updater_class_init (IdeGitDependencyUpdaterClass *klass)
+{
+}
+
+static void
+ide_git_dependency_updater_init (IdeGitDependencyUpdater *self)
+{
+}
diff --git a/src/plugins/git/ide-git-dependency-updater.h b/src/plugins/git/ide-git-dependency-updater.h
new file mode 100644
index 000000000..a0d8d2617
--- /dev/null
+++ b/src/plugins/git/ide-git-dependency-updater.h
@@ -0,0 +1,31 @@
+/* ide-git-dependency-updater.h
+ *
+ * Copyright 2018 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 <ide.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_GIT_DEPENDENCY_UPDATER (ide_git_dependency_updater_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeGitDependencyUpdater, ide_git_dependency_updater, IDE, GIT_DEPENDENCY_UPDATER, 
IdeObject)
+
+G_END_DECLS
diff --git a/src/plugins/git/ide-git-pipeline-addin.c b/src/plugins/git/ide-git-pipeline-addin.c
index ee48bf00f..e4c7009e3 100644
--- a/src/plugins/git/ide-git-pipeline-addin.c
+++ b/src/plugins/git/ide-git-pipeline-addin.c
@@ -25,145 +25,21 @@
 #include <glib/gi18n.h>
 
 #include "ide-git-pipeline-addin.h"
+#include "ide-git-submodule-stage.h"
 #include "ide-git-vcs.h"
 
 struct _IdeGitPipelineAddin
 {
   IdeObject parent_instance;
-  guint has_run : 1;
 };
 
-static void
-submodule_status_cb (GObject      *object,
-                     GAsyncResult *result,
-                     gpointer      user_data)
-{
-  IdeSubprocess *subprocess = (IdeSubprocess *)object;
-  g_autoptr(IdeBuildStage) stage = user_data;
-  g_autoptr(GError) error = NULL;
-  g_autofree gchar *stdout_buf = NULL;
-  IdeLineReader reader;
-  const gchar *line;
-  gsize line_len;
-
-  g_assert (IDE_IS_SUBPROCESS (subprocess));
-  g_assert (G_IS_ASYNC_RESULT (result));
-  g_assert (IDE_IS_BUILD_STAGE_LAUNCHER (stage));
-
-  if (!ide_subprocess_communicate_utf8_finish (subprocess, result, &stdout_buf, NULL, &error))
-    {
-      ide_build_stage_log (stage,
-                           IDE_BUILD_LOG_STDERR,
-                           error->message,
-                           -1);
-      goto failure;
-    }
-
-  ide_line_reader_init (&reader, stdout_buf, -1);
-  while ((line = ide_line_reader_next (&reader, &line_len)))
-    {
-      /* If we find a line starting with -, it isn't initialized
-       * and needs a submodule-init/update.
-       */
-      if (stdout_buf[0] == '-')
-        {
-          ide_build_stage_set_completed (stage, FALSE);
-          goto unpause;
-        }
-    }
-
-failure:
-  ide_build_stage_set_completed (stage, TRUE);
-
-unpause:
-  ide_build_stage_unpause (stage);
-}
-
-static void
-submodule_update_query_cb (IdeGitPipelineAddin   *self,
-                           IdeBuildPipeline      *pipeline,
-                           GCancellable          *cancellable,
-                           IdeBuildStageLauncher *stage)
-{
-  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
-  g_autoptr(IdeSubprocess) subprocess = NULL;
-  g_autoptr(GError) error = NULL;
-  IdeContext *context;
-  IdeVcs *vcs;
-  GFile *workdir;
-
-  g_assert (IDE_IS_GIT_PIPELINE_ADDIN (self));
-  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
-  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
-  g_assert (IDE_IS_BUILD_STAGE_LAUNCHER (stage));
-
-  /* Short-circuit if we've already run */
-  if (self->has_run)
-    {
-      ide_build_stage_set_completed (IDE_BUILD_STAGE (stage), TRUE);
-      return;
-    }
-
-  self->has_run = TRUE;
-
-  if (!ide_application_has_network (IDE_APPLICATION_DEFAULT))
-    {
-      ide_build_stage_log (IDE_BUILD_STAGE (stage),
-                           IDE_BUILD_LOG_STDERR,
-                           _("Network is not available, skipping submodule update"),
-                           -1);
-      ide_build_stage_set_completed (IDE_BUILD_STAGE (stage), TRUE);
-      return;
-    }
-
-  /* We need to run "git submodule status" to see if there are any
-   * lines that are prefixed with - (meaning they have not yet been
-   * initialized).
-   *
-   * We only do a git submodule init/update if that is the case, otherwise
-   * dependencies are updated with the dependency updater.
-   */
-
-  context = ide_object_get_context (IDE_OBJECT (self));
-  vcs = ide_context_get_vcs (context);
-  workdir = ide_vcs_get_working_directory (vcs);
-
-  launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
-  ide_subprocess_launcher_push_argv (launcher, "git");
-  ide_subprocess_launcher_push_argv (launcher, "submodule");
-  ide_subprocess_launcher_push_argv (launcher, "status");
-  ide_subprocess_launcher_set_cwd (launcher, g_file_peek_path (workdir));
-  ide_subprocess_launcher_set_clear_env (launcher, FALSE);
-
-  if (!(subprocess = ide_subprocess_launcher_spawn (launcher, cancellable, &error)))
-    {
-      ide_build_stage_log (IDE_BUILD_STAGE (stage),
-                           IDE_BUILD_LOG_STDERR,
-                           error->message,
-                           -1);
-      ide_build_stage_set_completed (IDE_BUILD_STAGE (stage), TRUE);
-      return;
-    }
-
-  ide_build_stage_pause (IDE_BUILD_STAGE (stage));
-
-  ide_subprocess_communicate_utf8_async (subprocess,
-                                         NULL,
-                                         cancellable,
-                                         submodule_status_cb,
-                                         g_object_ref (stage));
-}
-
 static void
 ide_git_pipeline_addin_load (IdeBuildPipelineAddin *addin,
                              IdeBuildPipeline      *pipeline)
 {
-  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
-  g_autoptr(GError) error = NULL;
-  IdeBuildStage *stage;
+  g_autoptr(IdeGitSubmoduleStage) submodule = NULL;
   IdeContext *context;
   IdeVcs *vcs;
-  GFile *workdir;
   guint stage_id;
 
   g_assert (IDE_IS_GIT_PIPELINE_ADDIN (addin));
@@ -171,35 +47,17 @@ ide_git_pipeline_addin_load (IdeBuildPipelineAddin *addin,
 
   context = ide_object_get_context (IDE_OBJECT (addin));
   vcs = ide_context_get_vcs (context);
-  workdir = ide_vcs_get_working_directory (vcs);
 
   /* Ignore everything if this isn't a git-based repository */
   if (!IDE_IS_GIT_VCS (vcs))
     return;
 
-  launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE |
-                                          G_SUBPROCESS_FLAGS_STDERR_PIPE);
-  ide_subprocess_launcher_set_clear_env (launcher, FALSE);
-  ide_subprocess_launcher_set_cwd (launcher, g_file_peek_path (workdir));
-  ide_subprocess_launcher_push_argv (launcher, "sh");
-  ide_subprocess_launcher_push_argv (launcher, "-c");
-  ide_subprocess_launcher_push_argv (launcher, "git submodule init && git submodule update");
-
-  stage_id = ide_build_pipeline_connect_launcher (pipeline,
-                                                  IDE_BUILD_PHASE_DOWNLOADS,
-                                                  100,
-                                                  launcher);
-  stage = ide_build_pipeline_get_stage_by_id (pipeline, stage_id);
+  submodule = ide_git_submodule_stage_new (context);
+  stage_id = ide_build_pipeline_connect (pipeline,
+                                         IDE_BUILD_PHASE_DOWNLOADS,
+                                         100,
+                                         IDE_BUILD_STAGE (submodule));
   ide_build_pipeline_addin_track (addin, stage_id);
-
-  ide_build_stage_launcher_set_ignore_exit_status (IDE_BUILD_STAGE_LAUNCHER (stage), TRUE);
-  ide_build_stage_set_name (stage, _("Initialize git submodules"));
-
-  g_signal_connect_object (stage,
-                           "query",
-                           G_CALLBACK (submodule_update_query_cb),
-                           addin,
-                           G_CONNECT_SWAPPED);
 }
 
 static void
diff --git a/src/plugins/git/ide-git-plugin.c b/src/plugins/git/ide-git-plugin.c
index ac790b09d..5e06cac5a 100644
--- a/src/plugins/git/ide-git-plugin.c
+++ b/src/plugins/git/ide-git-plugin.c
@@ -19,6 +19,7 @@
 #include <libpeas/peas.h>
 #include <ide.h>
 
+#include "ide-git-dependency-updater.h"
 #include "ide-git-genesis-addin.h"
 #include "ide-git-pipeline-addin.h"
 #include "ide-git-remote-callbacks.h"
@@ -76,6 +77,9 @@ ide_git_register_types (PeasObjectModule *module)
       peas_object_module_register_extension_type (module,
                                                   IDE_TYPE_BUILD_PIPELINE_ADDIN,
                                                   IDE_TYPE_GIT_PIPELINE_ADDIN);
+      peas_object_module_register_extension_type (module,
+                                                  IDE_TYPE_DEPENDENCY_UPDATER,
+                                                  IDE_TYPE_GIT_DEPENDENCY_UPDATER);
 
       ide_vcs_register_ignored (".git");
     }
diff --git a/src/plugins/git/ide-git-submodule-stage.c b/src/plugins/git/ide-git-submodule-stage.c
new file mode 100644
index 000000000..c677b803c
--- /dev/null
+++ b/src/plugins/git/ide-git-submodule-stage.c
@@ -0,0 +1,220 @@
+/* ide-git-submodule-stage.c
+ *
+ * Copyright 2018 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
+ */
+
+#include "config.h"
+
+#define G_LOG_DOMAIN "ide-git-submodule-stage"
+
+#include <glib/gi18n.h>
+
+#include "ide-git-submodule-stage.h"
+
+struct _IdeGitSubmoduleStage
+{
+  IdeBuildStageLauncher parent_instance;
+
+  guint has_run : 1;
+  guint force_update : 1;
+};
+
+G_DEFINE_TYPE (IdeGitSubmoduleStage, ide_git_submodule_stage, IDE_TYPE_BUILD_STAGE_LAUNCHER)
+
+IdeGitSubmoduleStage *
+ide_git_submodule_stage_new (IdeContext *context)
+{
+  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
+  g_autoptr(IdeGitSubmoduleStage) self = NULL;
+  IdeVcs *vcs;
+  GFile *workdir;
+
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+
+  vcs = ide_context_get_vcs (context);
+  workdir = ide_vcs_get_working_directory (vcs);
+
+  self = g_object_new (IDE_TYPE_GIT_SUBMODULE_STAGE,
+                       "context", context,
+                       NULL);
+
+  launcher = ide_subprocess_launcher_new (0);
+  ide_subprocess_launcher_set_cwd (launcher, g_file_peek_path (workdir));
+  ide_subprocess_launcher_set_clear_env (launcher, FALSE);
+  ide_subprocess_launcher_push_argv (launcher, "sh");
+  ide_subprocess_launcher_push_argv (launcher, "-c");
+  ide_subprocess_launcher_push_argv (launcher, "git submodule init && git submodule update");
+
+  ide_build_stage_launcher_set_launcher (IDE_BUILD_STAGE_LAUNCHER (self), launcher);
+
+  return g_steal_pointer (&self);
+}
+
+static void
+ide_git_submodule_stage_query_cb (GObject      *object,
+                                  GAsyncResult *result,
+                                  gpointer      user_data)
+{
+  IdeSubprocess *subprocess = (IdeSubprocess *)object;
+  g_autoptr(IdeGitSubmoduleStage) self = user_data;
+  g_autoptr(GError) error = NULL;
+  g_autofree gchar *stdout_buf = NULL;
+  IdeLineReader reader;
+  const gchar *line;
+  gsize line_len;
+
+  g_assert (IDE_IS_SUBPROCESS (subprocess));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_GIT_SUBMODULE_STAGE (self));
+
+  if (!ide_subprocess_communicate_utf8_finish (subprocess, result, &stdout_buf, NULL, &error))
+    {
+      ide_build_stage_log (IDE_BUILD_STAGE (self),
+                           IDE_BUILD_LOG_STDERR,
+                           error->message,
+                           -1);
+      goto failure;
+    }
+
+  ide_line_reader_init (&reader, stdout_buf, -1);
+  while ((line = ide_line_reader_next (&reader, &line_len)))
+    {
+      /* If we find a line starting with -, it isn't initialized
+       * and needs a submodule-init/update.
+       */
+      if (stdout_buf[0] == '-')
+        {
+          ide_build_stage_set_completed (IDE_BUILD_STAGE (self), FALSE);
+          goto unpause;
+        }
+    }
+
+failure:
+  ide_build_stage_set_completed (IDE_BUILD_STAGE (self), TRUE);
+
+unpause:
+  ide_build_stage_unpause (IDE_BUILD_STAGE (self));
+}
+
+static void
+ide_git_submodule_stage_query (IdeBuildStage    *stage,
+                               IdeBuildPipeline *pipeline,
+                               GCancellable     *cancellable)
+{
+  IdeGitSubmoduleStage *self = (IdeGitSubmoduleStage *)stage;
+  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
+  g_autoptr(IdeSubprocess) subprocess = NULL;
+  g_autoptr(GError) error = NULL;
+  IdeContext *context;
+  IdeVcs *vcs;
+  GFile *workdir;
+
+  IDE_ENTRY;
+
+  g_assert (IDE_IS_GIT_SUBMODULE_STAGE (self));
+  g_assert (IDE_IS_BUILD_PIPELINE (pipeline));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  if (!ide_application_has_network (IDE_APPLICATION_DEFAULT))
+    {
+      ide_build_stage_log (stage,
+                           IDE_BUILD_LOG_STDERR,
+                           _("Network is not available, skipping submodule update"),
+                           -1);
+      ide_build_stage_set_completed (stage, TRUE);
+      IDE_EXIT;
+    }
+
+  if (self->force_update)
+    {
+      self->force_update = FALSE;
+      self->has_run = TRUE;
+      ide_build_stage_set_completed (stage, FALSE);
+      IDE_EXIT;
+    }
+
+  if (self->has_run)
+    {
+      ide_build_stage_set_completed (stage, TRUE);
+      IDE_EXIT;
+    }
+
+  self->has_run = TRUE;
+
+  /* We need to run "git submodule status" to see if there are any
+   * lines that are prefixed with - (meaning they have not yet been
+   * initialized).
+   *
+   * We only do a git submodule init/update if that is the case, otherwise
+   * dependencies are updated with the dependency updater.
+   */
+
+  context = ide_object_get_context (IDE_OBJECT (self));
+  vcs = ide_context_get_vcs (context);
+  workdir = ide_vcs_get_working_directory (vcs);
+
+  launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
+  ide_subprocess_launcher_push_argv (launcher, "git");
+  ide_subprocess_launcher_push_argv (launcher, "submodule");
+  ide_subprocess_launcher_push_argv (launcher, "status");
+  ide_subprocess_launcher_set_cwd (launcher, g_file_peek_path (workdir));
+  ide_subprocess_launcher_set_clear_env (launcher, FALSE);
+
+  if (!(subprocess = ide_subprocess_launcher_spawn (launcher, cancellable, &error)))
+    {
+      ide_build_stage_log (IDE_BUILD_STAGE (stage),
+                           IDE_BUILD_LOG_STDERR,
+                           error->message,
+                           -1);
+      ide_build_stage_set_completed (IDE_BUILD_STAGE (stage), TRUE);
+      IDE_EXIT;
+    }
+
+  ide_build_stage_pause (IDE_BUILD_STAGE (stage));
+
+  ide_subprocess_communicate_utf8_async (subprocess,
+                                         NULL,
+                                         cancellable,
+                                         ide_git_submodule_stage_query_cb,
+                                         g_object_ref (self));
+
+  IDE_EXIT;
+}
+
+static void
+ide_git_submodule_stage_class_init (IdeGitSubmoduleStageClass *klass)
+{
+  IdeBuildStageClass *stage_class = IDE_BUILD_STAGE_CLASS (klass);
+
+  stage_class->query = ide_git_submodule_stage_query;
+}
+
+static void
+ide_git_submodule_stage_init (IdeGitSubmoduleStage *self)
+{
+  ide_build_stage_set_name (IDE_BUILD_STAGE (self), _("Initialize git submodules"));
+  ide_build_stage_launcher_set_ignore_exit_status (IDE_BUILD_STAGE_LAUNCHER (self), TRUE);
+}
+
+void
+ide_git_submodule_stage_force_update (IdeGitSubmoduleStage *self)
+{
+  g_return_if_fail (IDE_IS_GIT_SUBMODULE_STAGE (self));
+
+  self->force_update = TRUE;
+}
diff --git a/src/plugins/git/ide-git-submodule-stage.h b/src/plugins/git/ide-git-submodule-stage.h
new file mode 100644
index 000000000..d9a02ce02
--- /dev/null
+++ b/src/plugins/git/ide-git-submodule-stage.h
@@ -0,0 +1,34 @@
+/* ide-git-submodule-stage.h
+ *
+ * Copyright 2018 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 <ide.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_GIT_SUBMODULE_STAGE (ide_git_submodule_stage_get_type())
+
+G_DECLARE_FINAL_TYPE (IdeGitSubmoduleStage, ide_git_submodule_stage, IDE, GIT_SUBMODULE_STAGE, 
IdeBuildStageLauncher)
+
+IdeGitSubmoduleStage *ide_git_submodule_stage_new          (IdeContext           *context);
+void                  ide_git_submodule_stage_force_update (IdeGitSubmoduleStage *self);
+
+G_END_DECLS
diff --git a/src/plugins/git/meson.build b/src/plugins/git/meson.build
index e25d29701..69ae084cc 100644
--- a/src/plugins/git/meson.build
+++ b/src/plugins/git/meson.build
@@ -11,6 +11,8 @@ git_sources = [
   'ide-git-buffer-change-monitor.h',
   'ide-git-clone-widget.c',
   'ide-git-clone-widget.h',
+  'ide-git-dependency-updater.c',
+  'ide-git-dependency-updater.h',
   'ide-git-genesis-addin.c',
   'ide-git-genesis-addin.h',
   'ide-git-pipeline-addin.c',
@@ -18,6 +20,8 @@ git_sources = [
   'ide-git-plugin.c',
   'ide-git-remote-callbacks.c',
   'ide-git-remote-callbacks.h',
+  'ide-git-submodule-stage.c',
+  'ide-git-submodule-stage.h',
   'ide-git-vcs.c',
   'ide-git-vcs.h',
   'ide-git-vcs-config.c',


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