[gnome-builder] flatpak: add GbpFlatpakClient



commit ff482b0272e5ea644fd12e4715b72a866d6dcf17
Author: Christian Hergert <chergert redhat com>
Date:   Fri Apr 30 15:13:16 2021 -0700

    flatpak: add GbpFlatpakClient
    
    This client helper manages spawnin the gnome-builder-flatpak daemon as well
    as creating proxies to the specific services.

 src/plugins/flatpak/gbp-flatpak-client.c | 384 +++++++++++++++++++++++++++++++
 src/plugins/flatpak/gbp-flatpak-client.h |  45 ++++
 src/plugins/flatpak/meson.build          |   1 +
 3 files changed, 430 insertions(+)
---
diff --git a/src/plugins/flatpak/gbp-flatpak-client.c b/src/plugins/flatpak/gbp-flatpak-client.c
new file mode 100644
index 000000000..b9ed620da
--- /dev/null
+++ b/src/plugins/flatpak/gbp-flatpak-client.c
@@ -0,0 +1,384 @@
+/* gbp-flatpak-client.c
+ *
+ * Copyright 2019-2021 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-flatpak-client"
+
+#include "config.h"
+
+#include <gio/gunixinputstream.h>
+#include <gio/gunixoutputstream.h>
+#include <glib/gi18n.h>
+#include <glib-unix.h>
+#include <libide-threading.h>
+
+#include "gbp-flatpak-client.h"
+
+struct _GbpFlatpakClient
+{
+  IdeObject                parent_instance;
+  IdeSubprocessSupervisor *supervisor;
+  GDBusConnection         *connection;
+  IpcFlatpakService       *service;
+  GQueue                   get_service;
+  gint                     state;
+};
+
+enum {
+  STATE_INITIAL,
+  STATE_SPAWNING,
+  STATE_RUNNING,
+  STATE_SHUTDOWN,
+};
+
+G_DEFINE_TYPE (GbpFlatpakClient, gbp_flatpak_client, IDE_TYPE_OBJECT)
+
+static void
+gbp_flatpak_client_register_installations (GbpFlatpakClient  *self,
+                                           IpcFlatpakService *service)
+{
+  g_autofree char *user_path = NULL;
+  g_autofree char *system_path = NULL;
+
+  g_assert (GBP_IS_FLATPAK_CLIENT (self));
+  g_assert (IPC_IS_FLATPAK_SERVICE (service));
+
+  /*
+   * First we want to load the user installation so that it is at index 0.
+   * This naturally prefers the user installation for various operations
+   * which is precisely what we want.
+   *
+   * We can't use flatpak_installation_new_user() since that will not map to
+   * the user's real flatpak user installation. It will instead map to the
+   * reidrected XDG_DATA_DIRS version. Therefore, we synthesize the path to the
+   * location we know it should be at.
+   */
+  user_path = g_build_filename (g_get_home_dir (), ".local", "share", "flatpak", NULL);
+  ipc_flatpak_service_call_add_installation (service, user_path, TRUE, NULL, NULL, NULL);
+
+  /* We can't really access any of the system installations other than the
+   * one we know about (as flatpak_get_system_installations() never really
+   * worked correctly within the Flatpak environment.
+   *
+   * We could try to fix this for distro shipped versions, but they can deal
+   * with the fallout there because we only support Flatpak upstream and the
+   * distros we work on ourselves are all going Flatpak for apps.
+   */
+  ipc_flatpak_service_call_add_installation (service, "/var/lib/flatpak", FALSE, NULL, NULL, NULL);
+}
+
+static void
+gbp_flatpak_client_subprocess_spawned (GbpFlatpakClient        *self,
+                                       IdeSubprocess           *subprocess,
+                                       IdeSubprocessSupervisor *supervisor)
+{
+  g_autoptr(GIOStream) stream = NULL;
+  GOutputStream *output;
+  GInputStream *input;
+  GList *queued;
+  gint fd;
+
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_FLATPAK_CLIENT (self));
+  g_assert (IDE_IS_SUBPROCESS (subprocess));
+  g_assert (IDE_IS_SUBPROCESS_SUPERVISOR (supervisor));
+
+  ide_object_lock (IDE_OBJECT (self));
+
+  g_assert (self->service == NULL);
+
+  if (self->state == STATE_SPAWNING)
+    self->state = STATE_RUNNING;
+
+  input = ide_subprocess_get_stdout_pipe (subprocess);
+  output = ide_subprocess_get_stdin_pipe (subprocess);
+  stream = g_simple_io_stream_new (input, output);
+
+  g_assert (G_IS_UNIX_INPUT_STREAM (input));
+  g_assert (G_IS_UNIX_OUTPUT_STREAM (output));
+
+  fd = g_unix_input_stream_get_fd (G_UNIX_INPUT_STREAM (input));
+  g_unix_set_fd_nonblocking (fd, TRUE, NULL);
+
+  fd = g_unix_output_stream_get_fd (G_UNIX_OUTPUT_STREAM (output));
+  g_unix_set_fd_nonblocking (fd, TRUE, NULL);
+
+  self->connection = g_dbus_connection_new_sync (stream, NULL,
+                                                 G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
+                                                 NULL, NULL, NULL);
+  g_dbus_connection_set_exit_on_close (self->connection, FALSE);
+  g_dbus_connection_start_message_processing (self->connection);
+
+  self->service = ipc_flatpak_service_proxy_new_sync (self->connection,
+                                                      G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
+                                                      NULL,
+                                                      "/org/gnome/Builder/Flatpak",
+                                                      NULL,
+                                                      NULL);
+
+  /* We can have long running operations, so set no timeout */
+  g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (self->service), G_MAXINT);
+
+  queued = g_steal_pointer (&self->get_service.head);
+
+  self->get_service.head = NULL;
+  self->get_service.tail = NULL;
+  self->get_service.length = 0;
+
+  gbp_flatpak_client_register_installations (self, self->service);
+
+  for (const GList *iter = queued; iter != NULL; iter = iter->next)
+    {
+      IdeTask *task = iter->data;
+
+      ide_task_return_object (task, g_object_ref (self->service));
+    }
+
+  g_list_free_full (queued, g_object_unref);
+
+  ide_object_unlock (IDE_OBJECT (self));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_flatpak_client_subprocess_exited (GbpFlatpakClient        *self,
+                                      IdeSubprocess           *subprocess,
+                                      IdeSubprocessSupervisor *supervisor)
+{
+  IDE_ENTRY;
+
+  g_assert (GBP_IS_FLATPAK_CLIENT (self));
+  g_assert (IDE_IS_SUBPROCESS (subprocess));
+  g_assert (IDE_IS_SUBPROCESS_SUPERVISOR (supervisor));
+
+  ide_object_lock (IDE_OBJECT (self));
+
+  if (self->state == STATE_RUNNING)
+    self->state = STATE_SPAWNING;
+
+  g_clear_object (&self->service);
+
+  ide_object_unlock (IDE_OBJECT (self));
+
+  IDE_EXIT;
+}
+
+static void
+gbp_flatpak_client_destroy (IdeObject *object)
+{
+  GbpFlatpakClient *self = (GbpFlatpakClient *)object;
+  g_autoptr(IdeSubprocessSupervisor) supervisor = g_steal_pointer (&self->supervisor);
+
+  if (supervisor != NULL)
+    ide_subprocess_supervisor_stop (supervisor);
+
+  IDE_OBJECT_CLASS (gbp_flatpak_client_parent_class)->destroy (object);
+}
+
+static void
+gbp_flatpak_client_parent_set (IdeObject *object,
+                               IdeObject *parent)
+{
+  GbpFlatpakClient *self=  (GbpFlatpakClient *)object;
+  g_autoptr(IdeSubprocessLauncher) launcher = NULL;
+
+  g_assert (GBP_IS_FLATPAK_CLIENT (self));
+  g_assert (!parent || IDE_IS_OBJECT (parent));
+
+  if (parent == NULL)
+    return;
+
+  ide_object_lock (IDE_OBJECT (self));
+
+  launcher = ide_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE |
+                                          G_SUBPROCESS_FLAGS_STDIN_PIPE);
+  ide_subprocess_launcher_set_cwd (launcher, g_get_home_dir ());
+  ide_subprocess_launcher_set_clear_env (launcher, FALSE);
+#if 0
+  ide_subprocess_launcher_push_argv (launcher, "gdbserver");
+  ide_subprocess_launcher_push_argv (launcher, "localhost:8888");
+#endif
+  ide_subprocess_launcher_push_argv (launcher, PACKAGE_LIBEXECDIR"/gnome-builder-flatpak");
+
+  self->supervisor = ide_subprocess_supervisor_new ();
+  ide_subprocess_supervisor_set_launcher (self->supervisor, launcher);
+
+  g_signal_connect_object (self->supervisor,
+                           "spawned",
+                           G_CALLBACK (gbp_flatpak_client_subprocess_spawned),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  g_signal_connect_object (self->supervisor,
+                           "exited",
+                           G_CALLBACK (gbp_flatpak_client_subprocess_exited),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  ide_object_unlock (IDE_OBJECT (self));
+}
+
+static void
+gbp_flatpak_client_class_init (GbpFlatpakClientClass *klass)
+{
+  IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
+
+  i_object_class->destroy = gbp_flatpak_client_destroy;
+  i_object_class->parent_set = gbp_flatpak_client_parent_set;
+}
+
+static void
+gbp_flatpak_client_init (GbpFlatpakClient *self)
+{
+}
+
+GbpFlatpakClient *
+gbp_flatpak_client_from_context (IdeContext *context)
+{
+  GbpFlatpakClient *ret;
+
+  g_return_val_if_fail (IDE_IS_CONTEXT (context), NULL);
+  g_return_val_if_fail (!ide_object_in_destruction (IDE_OBJECT (context)), NULL);
+
+  if (!(ret = ide_context_peek_child_typed (context, GBP_TYPE_FLATPAK_CLIENT)))
+    {
+      g_autoptr(GbpFlatpakClient) client = NULL;
+
+      client = ide_object_ensure_child_typed (IDE_OBJECT (context), GBP_TYPE_FLATPAK_CLIENT);
+      ret = ide_context_peek_child_typed (context, GBP_TYPE_FLATPAK_CLIENT);
+    }
+
+  return ret;
+}
+
+static void
+gbp_flatpak_client_get_service_cb (GObject      *object,
+                                   GAsyncResult *result,
+                                   gpointer      user_data)
+{
+  GbpFlatpakClient *self = (GbpFlatpakClient *)object;
+  g_autoptr(IpcFlatpakService) service = NULL;
+  g_autoptr(IdeTask) task = user_data;
+  g_autoptr(GError) error = NULL;
+
+  g_assert (GBP_IS_FLATPAK_CLIENT (self));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (IDE_IS_TASK (task));
+
+  if (!(service = gbp_flatpak_client_get_service_finish (self, result, &error)))
+    ide_task_return_error (task, g_steal_pointer (&error));
+  else
+    ide_task_return_object (task, g_steal_pointer (&service));
+}
+
+IpcFlatpakService *
+gbp_flatpak_client_get_service (GbpFlatpakClient  *self,
+                                GCancellable      *cancellable,
+                                GError           **error)
+{
+  g_autoptr(IdeTask) task = NULL;
+  g_autoptr(GMainContext) gcontext = NULL;
+  IpcFlatpakService *ret = NULL;
+
+  g_assert (GBP_IS_FLATPAK_CLIENT (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  ide_object_lock (IDE_OBJECT (self));
+  if (self->service != NULL)
+    ret = g_object_ref (self->service);
+  ide_object_unlock (IDE_OBJECT (self));
+
+  if (ret != NULL)
+    return g_steal_pointer (&ret);
+
+  task = ide_task_new (self, cancellable, NULL, NULL);
+  ide_task_set_source_tag (task, gbp_flatpak_client_get_service);
+
+  gcontext = g_main_context_ref_thread_default ();
+
+  gbp_flatpak_client_get_service_async (self,
+                                        cancellable,
+                                        gbp_flatpak_client_get_service_cb,
+                                        g_object_ref (task));
+
+  while (!ide_task_get_completed (task))
+    g_main_context_iteration (gcontext, TRUE);
+
+  return ide_task_propagate_object (task, error);
+}
+
+void
+gbp_flatpak_client_get_service_async (GbpFlatpakClient    *self,
+                                      GCancellable        *cancellable,
+                                      GAsyncReadyCallback  callback,
+                                      gpointer             user_data)
+{
+  g_autoptr(IdeTask) task = NULL;
+
+  g_assert (GBP_IS_FLATPAK_CLIENT (self));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  ide_object_lock (IDE_OBJECT (self));
+
+  task = ide_task_new (self, cancellable, callback, user_data);
+  ide_task_set_source_tag (task, gbp_flatpak_client_get_service_async);
+
+  switch (self->state)
+    {
+    case STATE_INITIAL:
+      self->state = STATE_SPAWNING;
+      g_queue_push_tail (&self->get_service, g_steal_pointer (&task));
+      ide_subprocess_supervisor_start (self->supervisor);
+      break;
+
+    case STATE_SPAWNING:
+      g_queue_push_tail (&self->get_service, g_steal_pointer (&task));
+      break;
+
+    case STATE_RUNNING:
+      ide_task_return_object (task, g_object_ref (self->service));
+      break;
+
+    case STATE_SHUTDOWN:
+      ide_task_return_new_error (task,
+                                 G_IO_ERROR,
+                                 G_IO_ERROR_CLOSED,
+                                 _("The client has been closed"));
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+  ide_object_unlock (IDE_OBJECT (self));
+}
+
+IpcFlatpakService *
+gbp_flatpak_client_get_service_finish (GbpFlatpakClient  *self,
+                                       GAsyncResult      *result,
+                                       GError           **error)
+{
+  g_assert (GBP_IS_FLATPAK_CLIENT (self));
+  g_assert (IDE_IS_TASK (result));
+
+  return ide_task_propagate_object (IDE_TASK (result), error);
+}
diff --git a/src/plugins/flatpak/gbp-flatpak-client.h b/src/plugins/flatpak/gbp-flatpak-client.h
new file mode 100644
index 000000000..cd43c544d
--- /dev/null
+++ b/src/plugins/flatpak/gbp-flatpak-client.h
@@ -0,0 +1,45 @@
+/* gbp-flatpak-client.h
+ *
+ * Copyright 2019 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>
+
+#include "daemon/ipc-flatpak-service.h"
+
+G_BEGIN_DECLS
+
+#define GBP_TYPE_FLATPAK_CLIENT (gbp_flatpak_client_get_type())
+
+G_DECLARE_FINAL_TYPE (GbpFlatpakClient, gbp_flatpak_client, GBP, FLATPAK_CLIENT, IdeObject)
+
+GbpFlatpakClient  *gbp_flatpak_client_from_context       (IdeContext           *context);
+IpcFlatpakService *gbp_flatpak_client_get_service        (GbpFlatpakClient     *self,
+                                                          GCancellable         *cancellable,
+                                                          GError              **error);
+void               gbp_flatpak_client_get_service_async  (GbpFlatpakClient     *self,
+                                                          GCancellable         *cancellable,
+                                                          GAsyncReadyCallback   callback,
+                                                          gpointer              user_data);
+IpcFlatpakService *gbp_flatpak_client_get_service_finish (GbpFlatpakClient     *self,
+                                                          GAsyncResult         *result,
+                                                          GError              **error);
+
+G_END_DECLS
diff --git a/src/plugins/flatpak/meson.build b/src/plugins/flatpak/meson.build
index 42cca06f4..d357a776f 100644
--- a/src/plugins/flatpak/meson.build
+++ b/src/plugins/flatpak/meson.build
@@ -20,6 +20,7 @@ plugins_sources += files([
   'gbp-flatpak-build-system-discovery.c',
   'gbp-flatpak-build-target-provider.c',
   'gbp-flatpak-build-target.c',
+  'gbp-flatpak-client.c',
   'gbp-flatpak-clone-widget.c',
   'gbp-flatpak-config-provider.c',
   'gbp-flatpak-dependency-updater.c',


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