[gnome-builder/wip/gtk4-port] libide/foundry: start on new run context design



commit f2af388bd29c61a9dae32780ccfb86dd78e50a16
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jun 16 17:22:45 2022 -0700

    libide/foundry: start on new run context design
    
    This is a layered run context design where we will allow tooling at various
    layers to inject things as we process the creation of the launcher.
    
    The goal is to simplify and/or remove IdeRunner completely in favor of this
    and unify how the tooling injects/processes bits at each layer.

 src/libide/foundry/ide-run-context.c | 340 +++++++++++++++++++++++++++++++++++
 src/libide/foundry/ide-run-context.h | 102 +++++++++++
 src/libide/foundry/meson.build       |   2 +
 3 files changed, 444 insertions(+)
---
diff --git a/src/libide/foundry/ide-run-context.c b/src/libide/foundry/ide-run-context.c
new file mode 100644
index 000000000..5d6c05bd6
--- /dev/null
+++ b/src/libide/foundry/ide-run-context.c
@@ -0,0 +1,340 @@
+/* ide-run-context.c
+ *
+ * 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
+ */
+
+#define G_LOG_DOMAIN "ide-run-context"
+
+#include "config.h"
+
+#include "ide-run-context.h"
+
+typedef struct
+{
+  GList                 qlink;
+  char                 *cwd;
+  GArray               *argv;
+  GArray               *env;
+  IdeUnixFDMap         *unix_fd_map;
+  IdeRunContextHandler  handler;
+  gpointer              handler_data;
+  GDestroyNotify        handler_data_destroy;
+} IdeRunContextLayer;
+
+struct _IdeRunContext
+{
+  GObject            parent_instance;
+  GQueue             layers;
+  IdeRunContextLayer root;
+  guint              ended : 1;
+};
+
+G_DEFINE_FINAL_TYPE (IdeRunContext, ide_run_context, G_TYPE_OBJECT)
+
+static void
+ide_run_context_layer_clear (IdeRunContextLayer *layer)
+{
+  g_assert (layer != NULL);
+  g_assert (layer->qlink.data == layer);
+  g_assert (layer->qlink.prev == NULL);
+  g_assert (layer->qlink.next == NULL);
+
+  g_clear_pointer (&layer->cwd, g_free);
+  g_clear_pointer (&layer->argv, g_array_unref);
+  g_clear_pointer (&layer->env, g_array_unref);
+  g_clear_object (&layer->unix_fd_map);
+}
+
+static void
+ide_run_context_layer_free (IdeRunContextLayer *layer)
+{
+  ide_run_context_layer_clear (layer);
+  g_slice_free (IdeRunContextLayer, layer);
+}
+
+static IdeRunContextLayer *
+ide_run_context_current_layer (IdeRunContext *self)
+{
+  return self->layers.head->data;
+}
+
+static void
+ide_run_context_dispose (GObject *object)
+{
+  IdeRunContext *self = (IdeRunContext *)object;
+  IdeRunContextLayer *layer;
+
+  while ((layer = g_queue_peek_head (&self->layers)))
+    {
+      g_queue_unlink (&self->layers, &layer->qlink);
+      if (layer != &self->root)
+        ide_run_context_layer_free (layer);
+    }
+
+  ide_run_context_layer_clear (&self->root);
+
+  G_OBJECT_CLASS (ide_run_context_parent_class)->dispose (object);
+}
+
+static void
+ide_run_context_class_init (IdeRunContextClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = ide_run_context_dispose;
+}
+
+static void
+ide_run_context_init (IdeRunContext *self)
+{
+  self->root.qlink.data = self;
+  g_queue_push_head_link (&self->layers, &self->root.qlink);
+}
+
+static void
+strptr_free (gpointer data)
+{
+  char **strptr = data;
+  g_clear_pointer (strptr, g_free);
+}
+
+void
+ide_run_context_push (IdeRunContext        *self,
+                      IdeRunContextHandler  handler,
+                      gpointer              handler_data,
+                      GDestroyNotify        handler_data_destroy)
+{
+  IdeRunContextLayer *layer;
+
+  g_return_if_fail (IDE_IS_RUN_CONTEXT (self));
+
+  layer = g_slice_new0 (IdeRunContextLayer);
+  layer->qlink.data = layer;
+  layer->argv = g_array_new (TRUE, FALSE, sizeof (char *));
+  layer->env = g_array_new (TRUE, FALSE, sizeof (char *));
+  layer->unix_fd_map = ide_unix_fd_map_new ();
+  layer->handler = handler;
+  layer->handler_data = handler_data;
+  layer->handler_data_destroy = handler_data_destroy;
+
+  g_array_set_clear_func (layer->argv, strptr_free);
+  g_array_set_clear_func (layer->env, strptr_free);
+
+  g_queue_push_head_link (&self->layers, &layer->qlink);
+}
+
+const char * const *
+ide_run_context_get_argv (IdeRunContext *self)
+{
+  IdeRunContextLayer *layer;
+
+  g_return_val_if_fail (IDE_IS_RUN_CONTEXT (self), NULL);
+
+  layer = ide_run_context_current_layer (self);
+
+  return (const char * const *)&g_array_index (layer->argv, char *, 0);
+}
+
+const char * const *
+ide_run_context_get_environ (IdeRunContext *self)
+{
+  IdeRunContextLayer *layer;
+
+  g_return_val_if_fail (IDE_IS_RUN_CONTEXT (self), NULL);
+
+  layer = ide_run_context_current_layer (self);
+
+  return (const char * const *)&g_array_index (layer->env, char *, 0);
+}
+
+void
+ide_run_context_set_environ (IdeRunContext      *self,
+                             const char * const *environ)
+{
+  IdeRunContextLayer *layer;
+
+  g_return_if_fail (IDE_IS_RUN_CONTEXT (self));
+
+  layer = ide_run_context_current_layer (self);
+
+  g_array_set_size (layer->env, 0);
+
+  if (environ != NULL)
+    {
+      char **copy = g_strdupv ((char **)environ);
+      g_array_append_vals (layer->env, copy, g_strv_length (copy));
+    }
+}
+
+const char *
+ide_run_context_get_cwd (IdeRunContext *self)
+{
+  IdeRunContextLayer *layer;
+
+  g_return_val_if_fail (IDE_IS_RUN_CONTEXT (self), NULL);
+
+  layer = ide_run_context_current_layer (self);
+
+  return layer->cwd;
+}
+
+void
+ide_run_context_set_cwd (IdeRunContext *self,
+                         const char    *cwd)
+{
+  IdeRunContextLayer *layer;
+
+  g_return_if_fail (IDE_IS_RUN_CONTEXT (self));
+
+  layer = ide_run_context_current_layer (self);
+
+  if (g_strcmp0 (cwd, layer->cwd) != 0)
+    {
+      g_free (layer->cwd);
+      layer->cwd = g_strdup (cwd);
+    }
+}
+
+void
+ide_run_context_prepend_argv (IdeRunContext *self,
+                              const char    *arg)
+{
+  IdeRunContextLayer *layer;
+  char *copy;
+
+  g_return_if_fail (IDE_IS_RUN_CONTEXT (self));
+  g_return_if_fail (arg != NULL);
+
+  layer = ide_run_context_current_layer (self);
+
+  copy = g_strdup (arg);
+  g_array_insert_val (layer->argv, 0, copy);
+}
+
+void
+ide_run_context_append_argv (IdeRunContext *self,
+                             const char    *arg)
+{
+  IdeRunContextLayer *layer;
+  char *copy;
+
+  g_return_if_fail (IDE_IS_RUN_CONTEXT (self));
+  g_return_if_fail (arg != NULL);
+
+  layer = ide_run_context_current_layer (self);
+
+  copy = g_strdup (arg);
+  g_array_append_val (layer->argv, copy);
+}
+
+void
+ide_run_context_append_args (IdeRunContext      *self,
+                             const char * const *args)
+{
+  IdeRunContextLayer *layer;
+  char **copy;
+
+  g_return_if_fail (IDE_IS_RUN_CONTEXT (self));
+  g_return_if_fail (args != NULL);
+
+  layer = ide_run_context_current_layer (self);
+
+  copy = g_strdupv ((char **)args);
+  g_array_append_vals (layer->argv, copy, g_strv_length (copy));
+}
+
+gboolean
+ide_run_context_append_args_parsed (IdeRunContext  *self,
+                                    const char     *args,
+                                    GError        **error)
+{
+  IdeRunContextLayer *layer;
+  char **argv = NULL;
+  int argc;
+
+  g_return_val_if_fail (IDE_IS_RUN_CONTEXT (self), FALSE);
+  g_return_val_if_fail (args != NULL, FALSE);
+
+  if (!g_shell_parse_argv (args, &argc, &argv, error))
+    return FALSE;
+
+  layer = ide_run_context_current_layer (self);
+  g_array_append_vals (layer->argv, argv, argc);
+
+  return TRUE;
+}
+
+void
+ide_run_context_take_fd (IdeRunContext *self,
+                         int            source_fd,
+                         int            dest_fd)
+{
+  IdeRunContextLayer *layer;
+
+  g_return_if_fail (IDE_IS_RUN_CONTEXT (self));
+  g_return_if_fail (source_fd > -1);
+  g_return_if_fail (dest_fd > -1);
+
+  layer = ide_run_context_current_layer (self);
+
+  ide_unix_fd_map_take (layer->unix_fd_map, source_fd, dest_fd);
+}
+
+const char *
+ide_run_context_getenv (IdeRunContext *self,
+                        const char    *key)
+{
+  /* TODO: */
+  return NULL;
+}
+
+void
+ide_run_context_setenv (IdeRunContext *self,
+                        const char    *key,
+                        const char    *value)
+{
+  /* TODO */
+}
+
+void
+ide_run_context_unsetenv (IdeRunContext *self,
+                          const char    *key)
+{
+  /* TODO */
+}
+
+/**
+ * ide_run_context_end:
+ * @self: a #IdeRunContext
+ *
+ * Returns: (transfer full): an #IdeSubprocessLauncher if successful; otherwise
+ *   %NULL and @error is set.
+ */
+IdeSubprocessLauncher *
+ide_run_context_end (IdeRunContext  *self,
+                     GError        **error)
+{
+  g_return_val_if_fail (IDE_IS_RUN_CONTEXT (self), NULL);
+  g_return_val_if_fail (self->ended == FALSE, NULL);
+
+  self->ended = TRUE;
+
+  /* TODO: Process layers */
+
+  return NULL;
+}
diff --git a/src/libide/foundry/ide-run-context.h b/src/libide/foundry/ide-run-context.h
new file mode 100644
index 000000000..3fd4fd4ff
--- /dev/null
+++ b/src/libide/foundry/ide-run-context.h
@@ -0,0 +1,102 @@
+/* ide-run-context.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
+
+#if !defined (IDE_FOUNDRY_INSIDE) && !defined (IDE_FOUNDRY_COMPILATION)
+# error "Only <libide-foundry.h> can be included directly."
+#endif
+
+#include <libide-threading.h>
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_RUN_CONTEXT (ide_run_context_get_type())
+
+IDE_AVAILABLE_IN_ALL
+G_DECLARE_FINAL_TYPE (IdeRunContext, ide_run_context, IDE, RUN_CONTEXT, GObject)
+
+/**
+ * IdeRunContextHandler:
+ *
+ * Returns: %TRUE if successful; otherwise %FALSE and @error must be set.
+ */
+typedef gboolean (*IdeRunContextHandler) (IdeRunContext       *self,
+                                          const char * const  *argv,
+                                          const char * const  *env,
+                                          const char          *cwd,
+                                          IdeUnixFDMap        *fd_map,
+                                          gpointer             user_data,
+                                          GError             **error);
+
+IDE_AVAILABLE_IN_ALL
+IdeRunContext         *ide_run_context_new                (void);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_push               (IdeRunContext         *self,
+                                                           IdeRunContextHandler   handler,
+                                                           gpointer               handler_data,
+                                                           GDestroyNotify         handler_data_destroy);
+IDE_AVAILABLE_IN_ALL
+const char * const    *ide_run_context_get_argv           (IdeRunContext         *self);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_set_argv           (IdeRunContext         *self,
+                                                           const char * const    *argv);
+IDE_AVAILABLE_IN_ALL
+const char * const    *ide_run_context_get_environ        (IdeRunContext         *self);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_set_environ        (IdeRunContext         *self,
+                                                           const char * const    *environ);
+IDE_AVAILABLE_IN_ALL
+const char            *ide_run_context_get_cwd            (IdeRunContext         *self);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_set_cwd            (IdeRunContext         *self,
+                                                           const char            *cwd);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_take_fd            (IdeRunContext         *self,
+                                                           int                    source_fd,
+                                                           int                    dest_fd);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_prepend_argv       (IdeRunContext         *self,
+                                                           const char            *arg);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_append_argv        (IdeRunContext         *self,
+                                                           const char            *arg);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_append_args        (IdeRunContext         *self,
+                                                           const char * const    *args);
+IDE_AVAILABLE_IN_ALL
+gboolean               ide_run_context_append_args_parsed (IdeRunContext         *self,
+                                                           const char            *args,
+                                                           GError               **error);
+IDE_AVAILABLE_IN_ALL
+const char            *ide_run_context_getenv             (IdeRunContext         *self,
+                                                           const char            *key);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_setenv             (IdeRunContext         *self,
+                                                           const char            *key,
+                                                           const char            *value);
+IDE_AVAILABLE_IN_ALL
+void                   ide_run_context_unsetenv           (IdeRunContext         *self,
+                                                           const char            *key);
+IDE_AVAILABLE_IN_ALL
+IdeSubprocessLauncher *ide_run_context_end                (IdeRunContext         *self,
+                                                           GError               **error);
+
+G_END_DECLS
diff --git a/src/libide/foundry/meson.build b/src/libide/foundry/meson.build
index ebfe90d7d..ee4d8569d 100644
--- a/src/libide/foundry/meson.build
+++ b/src/libide/foundry/meson.build
@@ -42,6 +42,7 @@ libide_foundry_public_headers = [
   'ide-pipeline.h',
   'ide-run-command.h',
   'ide-run-command-provider.h',
+  'ide-run-context.h',
   'ide-run-manager.h',
   'ide-runner-addin.h',
   'ide-runner.h',
@@ -119,6 +120,7 @@ libide_foundry_public_sources = [
   'ide-pipeline.c',
   'ide-run-command.c',
   'ide-run-command-provider.c',
+  'ide-run-context.c',
   'ide-run-manager.c',
   'ide-runner-addin.c',
   'ide-runner.c',


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