[gnome-builder] libide/foundry: use PTY intercept when running tests



commit 6c927fae51c056f2472604af69ff4d0b55575303
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jul 14 16:42:09 2022 -0700

    libide/foundry: use PTY intercept when running tests
    
    We will need this so that we can eventually parse unit test output for the
    various kinds of providers (tap, etc). But furthermore, it actually allows
    us to have multiple processes share a VtePty which is then rendered within
    the testui VteTerminal widget.
    
    Also make the IdeTest run_async() API private so that we can adjust it as
    necessary. The public API is to run via the test-manager.

 src/libide/foundry/ide-test-manager.c | 60 +++++++++++++++++++++++------------
 src/libide/foundry/ide-test-private.h | 37 +++++++++++++++++++++
 src/libide/foundry/ide-test.c         | 21 ++++++++----
 src/libide/foundry/ide-test.h         | 11 -------
 4 files changed, 91 insertions(+), 38 deletions(-)
---
diff --git a/src/libide/foundry/ide-test-manager.c b/src/libide/foundry/ide-test-manager.c
index 6fdd80117..a9501c27b 100644
--- a/src/libide/foundry/ide-test-manager.c
+++ b/src/libide/foundry/ide-test-manager.c
@@ -32,11 +32,12 @@
 #include "ide-foundry-compat.h"
 #include "ide-pipeline.h"
 #include "ide-pty.h"
+#include "ide-run-context.h"
 #include "ide-run-command.h"
 #include "ide-run-commands.h"
 #include "ide-run-manager.h"
-#include "ide-test.h"
 #include "ide-test-manager.h"
+#include "ide-test-private.h"
 
 #define MAX_UNIT_TESTS 4
 
@@ -59,6 +60,8 @@ struct _IdeTestManager
   GtkFilterListModel *filtered;
   IdeCachedListModel *tests;
   VtePty             *pty;
+  IdePtyIntercept     intercept;
+  int                 pty_producer;
 };
 
 typedef struct
@@ -111,6 +114,7 @@ run_all_free (RunAll *state)
   g_clear_pointer (&state->tests, g_ptr_array_unref);
   g_clear_object (&state->pipeline);
   g_clear_object (&state->pty);
+
   g_slice_free (RunAll, state);
 }
 
@@ -177,11 +181,17 @@ static void
 ide_test_manager_dispose (GObject *object)
 {
   IdeTestManager *self = (IdeTestManager *)object;
+  g_auto(IdePtyFd) fd = IDE_PTY_FD_INVALID;
 
-  g_clear_object (&self->pty);
   g_clear_object (&self->filtered);
   g_clear_object (&self->tests);
 
+  g_clear_object (&self->pty);
+  fd = pty_fd_steal (&self->pty_producer);
+
+  if (IDE_IS_PTY_INTERCEPT (&self->intercept))
+    ide_pty_intercept_clear (&self->intercept);
+
   G_OBJECT_CLASS (ide_test_manager_parent_class)->dispose (object);
 }
 
@@ -236,8 +246,16 @@ ide_test_manager_init (IdeTestManager *self)
 {
   GtkCustomFilter *filter;
   GtkMapListModel *map;
+  int consumer_fd;
 
   self->pty = ide_pty_new_sync (NULL);
+  self->pty_producer = -1;
+
+  /* Now create intercept, which we'll use to apply PTY
+   * to all the spawned processes instead of our VtePty.
+   */
+  consumer_fd = vte_pty_get_fd (self->pty);
+  ide_pty_intercept_init (&self->intercept, consumer_fd, NULL);
 
   filter = gtk_custom_filter_new (filter_tests_func, NULL, NULL);
   self->filtered = gtk_filter_list_model_new (NULL, GTK_FILTER (filter));
@@ -252,7 +270,7 @@ ide_test_manager_run_all_cb (GObject      *object,
                              GAsyncResult *result,
                              gpointer      user_data)
 {
-  IdeTest *test = (IdeTest *)object;
+  IdeTestManager *self = (IdeTestManager *)object;
   g_autoptr(IdeTask) task = user_data;
   g_autoptr(GError) error = NULL;
   GCancellable *cancellable;
@@ -261,7 +279,7 @@ ide_test_manager_run_all_cb (GObject      *object,
   IDE_ENTRY;
 
   g_assert (IDE_IS_MAIN_THREAD ());
-  g_assert (IDE_IS_TEST (test));
+  g_assert (IDE_IS_TEST_MANAGER (self));
   g_assert (G_IS_ASYNC_RESULT (result));
   g_assert (IDE_IS_TASK (task));
 
@@ -270,10 +288,9 @@ ide_test_manager_run_all_cb (GObject      *object,
 
   g_assert (state != NULL);
   g_assert (state->n_active > 0);
-  g_assert (!state->pty || VTE_IS_PTY (state->pty));
   g_assert (state->tests != NULL);
 
-  if (!ide_test_run_finish (test, result, &error))
+  if (!ide_test_manager_run_finish (self, result, &error))
     g_message ("%s", error->message);
 
   if (state->tests->len > 0 &&
@@ -283,12 +300,11 @@ ide_test_manager_run_all_cb (GObject      *object,
 
       state->n_active++;
 
-      ide_test_run_async (next_test,
-                          state->pipeline,
-                          state->pty,
-                          cancellable,
-                          ide_test_manager_run_all_cb,
-                          g_object_ref (task));
+      ide_test_manager_run_async (self,
+                                  next_test,
+                                  cancellable,
+                                  ide_test_manager_run_all_cb,
+                                  g_object_ref (task));
     }
 
   state->n_active--;
@@ -360,7 +376,6 @@ ide_test_manager_run_all_async (IdeTestManager      *self,
   state = g_slice_new0 (RunAll);
   state->tests = g_ptr_array_ref (ar);
   state->pipeline = g_object_ref (pipeline);
-  state->pty = g_object_ref (self->pty);
   state->n_active = 0;
   ide_task_set_task_data (task, state, run_all_free);
 
@@ -370,12 +385,11 @@ ide_test_manager_run_all_async (IdeTestManager      *self,
 
       state->n_active++;
 
-      ide_test_run_async (test,
-                          state->pipeline,
-                          state->pty,
-                          cancellable,
-                          ide_test_manager_run_all_cb,
-                          g_object_ref (task));
+      ide_test_manager_run_async (self,
+                                  test,
+                                  cancellable,
+                                  ide_test_manager_run_all_cb,
+                                  g_object_ref (task));
     }
 
   if (state->n_active == 0)
@@ -477,6 +491,12 @@ ide_test_manager_run_async (IdeTestManager      *self,
   build_manager = ide_build_manager_from_context (context);
   pipeline = ide_build_manager_get_pipeline (build_manager);
 
+  if (self->pty_producer == -1)
+    {
+      IdePtyFd consumer_fd = ide_pty_intercept_get_fd (&self->intercept);
+      self->pty_producer = ide_pty_intercept_create_producer (consumer_fd, TRUE);
+    }
+
   if (pipeline == NULL)
     ide_task_return_new_error (task,
                                G_IO_ERROR,
@@ -485,7 +505,7 @@ ide_test_manager_run_async (IdeTestManager      *self,
   else
     ide_test_run_async (test,
                         pipeline,
-                        self->pty,
+                        self->pty_producer,
                         cancellable,
                         ide_test_manager_run_cb,
                         g_steal_pointer (&task));
diff --git a/src/libide/foundry/ide-test-private.h b/src/libide/foundry/ide-test-private.h
new file mode 100644
index 000000000..da7fc741a
--- /dev/null
+++ b/src/libide/foundry/ide-test-private.h
@@ -0,0 +1,37 @@
+/* ide-test-private.h
+ *
+ * Copyright 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 "ide-test.h"
+
+G_BEGIN_DECLS
+
+void     ide_test_run_async  (IdeTest              *self,
+                              IdePipeline          *pipeline,
+                              int                   pty_fd,
+                              GCancellable         *cancellable,
+                              GAsyncReadyCallback   callback,
+                              gpointer              user_data);
+gboolean ide_test_run_finish (IdeTest              *self,
+                              GAsyncResult         *result,
+                              GError              **error);
+
+G_END_DECLS
diff --git a/src/libide/foundry/ide-test.c b/src/libide/foundry/ide-test.c
index 55790ccc9..fd59facb7 100644
--- a/src/libide/foundry/ide-test.c
+++ b/src/libide/foundry/ide-test.c
@@ -22,15 +22,17 @@
 
 #include "config.h"
 
+#include <unistd.h>
+
 #include <libide-io.h>
 #include <libide-threading.h>
 
-#include "ide-run-command.h"
-#include "ide-run-context.h"
 #include "ide-foundry-enums.h"
 #include "ide-pipeline.h"
+#include "ide-run-command.h"
+#include "ide-run-context.h"
 #include "ide-runtime.h"
-#include "ide-test.h"
+#include "ide-test-private.h"
 
 struct _IdeTest
 {
@@ -284,7 +286,7 @@ ide_test_wait_check_cb (GObject      *object,
 void
 ide_test_run_async (IdeTest             *self,
                     IdePipeline         *pipeline,
-                    VtePty              *pty,
+                    int                  pty_fd,
                     GCancellable        *cancellable,
                     GAsyncReadyCallback  callback,
                     gpointer             user_data)
@@ -302,7 +304,6 @@ ide_test_run_async (IdeTest             *self,
 
   g_return_if_fail (IDE_IS_TEST (self));
   g_return_if_fail (IDE_IS_PIPELINE (pipeline));
-  g_return_if_fail (!pty || VTE_IS_PTY (pty));
   g_return_if_fail (IDE_IS_RUN_COMMAND (self->run_command));
 
   task = ide_task_new (self, cancellable, callback, user_data);
@@ -327,8 +328,14 @@ ide_test_run_async (IdeTest             *self,
       run_context = ide_pipeline_create_run_context (pipeline, self->run_command);
     }
 
-  if (pty != NULL)
-    ide_run_context_set_pty (run_context, pty);
+  if (pty_fd > -1)
+    {
+      ide_run_context_take_fd (run_context, dup (pty_fd), STDIN_FILENO);
+      ide_run_context_take_fd (run_context, dup (pty_fd), STDOUT_FILENO);
+      ide_run_context_take_fd (run_context, dup (pty_fd), STDERR_FILENO);
+
+      ide_run_context_setenv (run_context, "TERM", "xterm-256color");
+    }
 
   if (!(subprocess = ide_run_context_spawn (run_context, &error)))
     {
diff --git a/src/libide/foundry/ide-test.h b/src/libide/foundry/ide-test.h
index de4883ce1..22c60a97a 100644
--- a/src/libide/foundry/ide-test.h
+++ b/src/libide/foundry/ide-test.h
@@ -57,16 +57,5 @@ IDE_AVAILABLE_IN_ALL
 const char    *ide_test_get_icon_name   (IdeTest              *self);
 IDE_AVAILABLE_IN_ALL
 IdeRunCommand *ide_test_get_run_command (IdeTest              *self);
-IDE_AVAILABLE_IN_ALL
-void           ide_test_run_async       (IdeTest              *self,
-                                         IdePipeline          *pipeline,
-                                         VtePty               *pty,
-                                         GCancellable         *cancellable,
-                                         GAsyncReadyCallback   callback,
-                                         gpointer              user_data);
-IDE_AVAILABLE_IN_ALL
-gboolean        ide_test_run_finish     (IdeTest              *self,
-                                         GAsyncResult         *result,
-                                         GError              **error);
 
 G_END_DECLS


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