[gnome-builder/wip/chergert/gnome-builder-flatpak: 75/79] flatpak: start on gnome-builder-flatpak daemon



commit af4b52beac666da6a12ee2a038049032a9122f47
Author: Christian Hergert <chergert redhat com>
Date:   Wed Apr 10 14:48:18 2019 -0700

    flatpak: start on gnome-builder-flatpak daemon
    
    This starts on a deamon that will provide the ultimate goal of us moving
    our libflatpak integration out of process. Doing so provides us some
    resilience as well as a simplified plugin implementation that can focus
    more on bridging the two systems than the mechanics of tracking changes.

 src/plugins/flatpak/daemon/gnome-builder-flatpak.c | 115 +++++++
 .../flatpak/daemon/ipc-flatpak-service-impl.c      | 365 +++++++++++++++++++++
 .../flatpak/daemon/ipc-flatpak-service-impl.h      |  33 ++
 src/plugins/flatpak/daemon/ipc-flatpak-util.h      |  42 +++
 src/plugins/flatpak/daemon/meson.build             |  33 ++
 .../daemon/org.gnome.Builder.Flatpak.Service.xml   |  50 +++
 src/plugins/flatpak/daemon/test-flatpak.c          | 155 +++++++++
 src/plugins/flatpak/meson.build                    |   2 +
 8 files changed, 795 insertions(+)
---
diff --git a/src/plugins/flatpak/daemon/gnome-builder-flatpak.c 
b/src/plugins/flatpak/daemon/gnome-builder-flatpak.c
new file mode 100644
index 000000000..2edd5af26
--- /dev/null
+++ b/src/plugins/flatpak/daemon/gnome-builder-flatpak.c
@@ -0,0 +1,115 @@
+/* gnome-builder-flatpak.c
+ *
+ * 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
+ */
+
+#include <glib-unix.h>
+#include <gio/gunixinputstream.h>
+#include <gio/gunixoutputstream.h>
+#include <flatpak/flatpak.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+
+#include "ipc-flatpak-service.h"
+#include "ipc-flatpak-service-impl.h"
+
+static GDBusConnection *
+create_connection (GIOStream  *stream,
+                   GMainLoop  *main_loop,
+                   GError    **error)
+{
+  GDBusConnection *ret;
+
+  g_assert (G_IS_IO_STREAM (stream));
+  g_assert (main_loop != NULL);
+  g_assert (error != NULL);
+
+  if ((ret = g_dbus_connection_new_sync (stream, NULL,
+                                          G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
+                                          NULL, NULL, error)))
+    {
+      g_dbus_connection_set_exit_on_close (ret, FALSE);
+      g_signal_connect_swapped (ret, "closed", G_CALLBACK (g_main_loop_quit), main_loop);
+    }
+
+  return ret;
+}
+
+static void
+log_func (const gchar    *log_domain,
+          GLogLevelFlags  flags,
+          const gchar    *message,
+          gpointer        user_data)
+{
+  g_printerr ("gnome-builder-flatpak: %s\n", message);
+}
+
+gint
+main (gint argc,
+      gchar *argv[])
+{
+  g_autoptr(GDBusConnection) connection = NULL;
+  g_autoptr(IpcFlatpakService) service = NULL;
+  g_autoptr(GOutputStream) stdout_stream = NULL;
+  g_autoptr(GInputStream) stdin_stream = NULL;
+  g_autoptr(GIOStream) stream = NULL;
+  g_autoptr(GMainLoop) main_loop = NULL;
+  g_autoptr(GError) error = NULL;
+
+  g_set_prgname ("gnome-builder-flatpak");
+  g_set_application_name ("gnome-builder-flatpak");
+
+  prctl (PR_SET_PDEATHSIG, SIGTERM);
+
+  signal (SIGPIPE, SIG_IGN);
+
+  g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_func, NULL);
+
+  if (!g_unix_set_fd_nonblocking (STDIN_FILENO, TRUE, &error) ||
+      !g_unix_set_fd_nonblocking (STDOUT_FILENO, TRUE, &error))
+    goto error;
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  stdin_stream = g_unix_input_stream_new (STDIN_FILENO, FALSE);
+  stdout_stream = g_unix_output_stream_new (STDOUT_FILENO, FALSE);
+  stream = g_simple_io_stream_new (stdin_stream, stdout_stream);
+
+  if (!(connection = create_connection (stream, main_loop, &error)))
+    goto error;
+
+  service = ipc_flatpak_service_impl_new ();
+
+  if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (service),
+                                         connection,
+                                         "/org/gnome/Builder/Flatpak",
+                                         &error))
+    goto error;
+
+  g_dbus_connection_start_message_processing (connection);
+  g_main_loop_run (main_loop);
+
+  return EXIT_SUCCESS;
+
+error:
+  if (error != NULL)
+    g_error ("%s", error->message);
+
+  return EXIT_FAILURE;
+}
diff --git a/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.c 
b/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.c
new file mode 100644
index 000000000..fd24d11e8
--- /dev/null
+++ b/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.c
@@ -0,0 +1,365 @@
+/* ipc-flatpak-service-impl.c
+ *
+ * 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
+ */
+
+#define G_LOG_DOMAIN "ipc-flatpak-service-impl"
+
+#include "config.h"
+
+#include <flatpak/flatpak.h>
+
+#include "ipc-flatpak-service-impl.h"
+#include "ipc-flatpak-util.h"
+
+typedef struct
+{
+  FlatpakInstallation *installation;
+  gchar *name;
+  gchar *arch;
+  gchar *branch;
+  gchar *sdk_name;
+  gchar *sdk_branch;
+  gboolean sdk_extension : 1;
+} Runtime;
+
+typedef struct
+{
+  FlatpakInstallation *installation;
+  GFileMonitor *monitor;
+} Install;
+
+struct _IpcFlatpakServiceImpl
+{
+  IpcFlatpakServiceSkeleton parent;
+  GHashTable *installs;
+  GPtrArray *runtimes;
+};
+
+static void      ipc_flatpak_service_impl_install_changed_cb (IpcFlatpakServiceImpl  *self,
+                                                              GFile                  *file,
+                                                              GFile                  *other_file,
+                                                              GFileMonitorEvent       event,
+                                                              GFileMonitor           *monitor);
+static gboolean  ipc_flatpak_service_impl_add_installation   (IpcFlatpakService      *service,
+                                                              GDBusMethodInvocation  *invocation,
+                                                              const gchar            *path,
+                                                              gboolean                is_user);
+static void      add_runtime                                 (IpcFlatpakServiceImpl  *service,
+                                                              Runtime                *runtime);
+static Install  *install_new                                 (IpcFlatpakServiceImpl  *self,
+                                                              FlatpakInstallation    *installation,
+                                                              GError                **error);
+static void      install_free                                (Install                *install);
+static void      install_reload                              (IpcFlatpakServiceImpl  *self,
+                                                              Install                *install);
+static GVariant *runtime_to_variant                          (const Runtime          *runtime);
+static void      runtime_free                                (Runtime                *runtime);
+static gboolean  runtime_equal                               (const Runtime          *a,
+                                                              const Runtime          *b);
+
+static void
+add_runtime (IpcFlatpakServiceImpl *self,
+             Runtime               *runtime)
+{
+  g_autoptr(GVariant) variant = NULL;
+
+  g_assert (IPC_IS_FLATPAK_SERVICE_IMPL (self));
+  g_assert (runtime != NULL);
+
+  for (guint i = 0; i < self->runtimes->len; i++)
+    {
+      const Runtime *other = g_ptr_array_index (self->runtimes, i);
+
+      /* Ignore if we know about it already */
+      if (runtime_equal (other, runtime))
+        return;
+    }
+
+  variant = runtime_to_variant (runtime);
+  g_ptr_array_add (self->runtimes, g_steal_pointer (&runtime));
+
+  ipc_flatpak_service_emit_runtime_added (IPC_FLATPAK_SERVICE (self), variant);
+}
+
+static void
+runtime_free (Runtime *runtime)
+{
+  g_clear_pointer (&runtime->name, g_free);
+  g_clear_pointer (&runtime->arch, g_free);
+  g_clear_pointer (&runtime->branch, g_free);
+  g_clear_pointer (&runtime->sdk_name, g_free);
+  g_clear_pointer (&runtime->sdk_branch, g_free);
+  g_slice_free (Runtime, runtime);
+}
+
+static gboolean
+runtime_equal (const Runtime *a,
+               const Runtime *b)
+{
+  return g_str_equal (a->name, b->name) &&
+         g_str_equal (a->arch, b->arch) &&
+         g_str_equal (a->branch, b->branch);
+}
+
+static GVariant *
+runtime_to_variant (const Runtime *runtime)
+{
+  return g_variant_take_ref (g_variant_new ("(sssssb)",
+                                            runtime->name,
+                                            runtime->arch,
+                                            runtime->branch,
+                                            runtime->sdk_name,
+                                            runtime->sdk_branch,
+                                            runtime->sdk_extension));
+}
+
+static Install *
+install_new (IpcFlatpakServiceImpl  *self,
+             FlatpakInstallation    *installation,
+             GError                **error)
+{
+  g_autoptr(GFileMonitor) monitor = NULL;
+  Install *ret;
+
+  if (!(monitor = flatpak_installation_create_monitor (installation, NULL, error)))
+    return NULL;
+
+  ret = g_slice_new0 (Install);
+  ret->installation = g_object_ref (installation);
+  ret->monitor = g_steal_pointer (&monitor);
+
+  g_signal_connect_object (ret->monitor,
+                           "changed",
+                           G_CALLBACK (ipc_flatpak_service_impl_install_changed_cb),
+                           self,
+                           G_CONNECT_SWAPPED);
+
+  return g_steal_pointer (&ret);
+}
+
+static void
+install_free (Install *install)
+{
+  g_clear_object (&install->installation);
+  g_clear_object (&install->monitor);
+  g_slice_free (Install, install);
+}
+
+static void
+install_reload (IpcFlatpakServiceImpl *self,
+                Install               *install)
+{
+  g_autoptr(GPtrArray) refs = NULL;
+
+  g_assert (IPC_IS_FLATPAK_SERVICE_IMPL (self));
+  g_assert (install != NULL);
+
+  if (!(refs = flatpak_installation_list_installed_refs_by_kind (install->installation,
+                                                                 FLATPAK_REF_KIND_RUNTIME,
+                                                                 NULL, NULL)))
+    return;
+
+  for (guint i = 0; i < refs->len; i++)
+    {
+      FlatpakInstalledRef *ref = g_ptr_array_index (refs, i);
+      g_autoptr(FlatpakRef) sdk_ref = NULL;
+      g_autoptr(GBytes) bytes = NULL;
+      g_autoptr(GKeyFile) keyfile = g_key_file_new ();
+      g_autofree gchar *sdk_full_ref = NULL;
+      g_autofree gchar *name = NULL;
+      g_autofree gchar *runtime = NULL;
+      g_autofree gchar *sdk = NULL;
+      g_autofree gchar *exten_of = NULL;
+      Runtime *state;
+
+      if (!(bytes = flatpak_installed_ref_load_metadata (ref, NULL, NULL)) ||
+          !g_key_file_load_from_bytes (keyfile, bytes, G_KEY_FILE_NONE, NULL))
+        continue;
+
+      if (!(name = g_key_file_get_string (keyfile, "Runtime", "name", NULL)) ||
+          !(runtime = g_key_file_get_string (keyfile, "Runtime", "runtime", NULL)) ||
+          !(sdk = g_key_file_get_string (keyfile, "Runtime", "sdk", NULL)))
+        continue;
+
+      if (g_key_file_has_group (keyfile, "ExtensionOf"))
+        {
+          /* Skip if this item is an extension, but not an SDK extension */
+          if (!g_key_file_has_key (keyfile, "ExtensionOf", "ref", NULL) ||
+              strstr (name, ".Extension.") == NULL)
+            continue;
+
+          exten_of = g_key_file_get_string (keyfile, "ExtensionOf", "ref", NULL);
+        }
+
+      if (!g_str_has_prefix (sdk, "runtime/"))
+        sdk_full_ref = g_strdup_printf ("runtime/%s", sdk);
+      else
+        sdk_full_ref = g_strdup (sdk);
+
+      /* Make sure we can parse the SDK reference */
+      if (!(sdk_ref = flatpak_ref_parse (sdk_full_ref, NULL)))
+        continue;
+
+      state = g_slice_new0 (Runtime);
+      state->installation = g_object_ref (install->installation);
+      state->name = g_strdup (flatpak_ref_get_name (FLATPAK_REF (ref)));
+      state->arch = g_strdup (flatpak_ref_get_arch (FLATPAK_REF (ref)));
+      state->branch = g_strdup (flatpak_ref_get_branch (FLATPAK_REF (ref)));
+      state->sdk_name = g_strdup (flatpak_ref_get_name (sdk_ref));
+      state->sdk_branch = g_strdup (flatpak_ref_get_branch (sdk_ref));
+      state->sdk_extension = exten_of != NULL;
+
+      add_runtime (self, g_steal_pointer (&state));
+    }
+}
+
+static gboolean
+ipc_flatpak_service_impl_add_installation (IpcFlatpakService     *service,
+                                           GDBusMethodInvocation *invocation,
+                                           const gchar           *path,
+                                           gboolean               is_user)
+{
+  IpcFlatpakServiceImpl *self = (IpcFlatpakServiceImpl *)service;
+  g_autoptr(FlatpakInstallation) installation = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GFile) file = NULL;
+
+  g_assert (IPC_IS_FLATPAK_SERVICE_IMPL (self));
+  g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
+  g_assert (path != NULL);
+
+  file = g_file_new_for_path (path);
+
+  if (!g_hash_table_contains (self->installs, file))
+    {
+      Install *install;
+
+      if (!(installation = flatpak_installation_new_for_path (file, is_user, NULL, &error)) ||
+          !(install = install_new (self, installation, &error)))
+        return complete_wrapped_error (invocation, error);
+
+      install_reload (self, install);
+
+      g_hash_table_insert (self->installs,
+                           g_steal_pointer (&file),
+                           g_steal_pointer (&install));
+    }
+
+  ipc_flatpak_service_complete_add_installation (service, invocation);
+
+  return TRUE;
+}
+
+static gboolean
+ipc_flatpak_service_impl_list_runtimes (IpcFlatpakService     *service,
+                                        GDBusMethodInvocation *invocation)
+{
+  IpcFlatpakServiceImpl *self = (IpcFlatpakServiceImpl *)service;
+  g_autoptr(GError) error = NULL;
+  GVariantBuilder builder;
+
+  g_assert (IPC_IS_FLATPAK_SERVICE_IMPL (self));
+  g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sssssb)"));
+
+  for (guint i = 0; i < self->runtimes->len; i++)
+    {
+      const Runtime *runtime = g_ptr_array_index (self->runtimes, i);
+      g_autoptr(GVariant) item = runtime_to_variant (runtime);
+      g_variant_builder_add_value (&builder, item);
+    }
+
+  ipc_flatpak_service_complete_list_runtimes (service,
+                                              invocation,
+                                              g_variant_builder_end (&builder));
+
+  return TRUE;
+}
+
+static void
+ipc_flatpak_service_impl_install_changed_cb (IpcFlatpakServiceImpl *self,
+                                             GFile                 *file,
+                                             GFile                 *other_file,
+                                             GFileMonitorEvent      event,
+                                             GFileMonitor          *monitor)
+{
+  GHashTableIter iter;
+  Install *install;
+
+  g_assert (IPC_IS_FLATPAK_SERVICE_IMPL (self));
+  g_assert (G_IS_FILE (file));
+  g_assert (!other_file || G_IS_FILE (other_file));
+  g_assert (G_IS_FILE_MONITOR (monitor));
+
+  g_hash_table_iter_init (&iter, self->installs);
+
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&install))
+    {
+      if (install->monitor == monitor)
+        {
+          install_reload (self, install);
+          break;
+        }
+    }
+}
+
+static void
+service_iface_init (IpcFlatpakServiceIface *iface)
+{
+  iface->handle_add_installation = ipc_flatpak_service_impl_add_installation;
+  iface->handle_list_runtimes = ipc_flatpak_service_impl_list_runtimes;
+}
+
+G_DEFINE_TYPE_WITH_CODE (IpcFlatpakServiceImpl, ipc_flatpak_service_impl, IPC_TYPE_FLATPAK_SERVICE_SKELETON,
+                         G_IMPLEMENT_INTERFACE (IPC_TYPE_FLATPAK_SERVICE, service_iface_init))
+
+static void
+ipc_flatpak_service_impl_finalize (GObject *object)
+{
+  IpcFlatpakServiceImpl *self = (IpcFlatpakServiceImpl *)object;
+
+  g_clear_pointer (&self->installs, g_hash_table_unref);
+
+  G_OBJECT_CLASS (ipc_flatpak_service_impl_parent_class)->finalize (object);
+}
+
+static void
+ipc_flatpak_service_impl_class_init (IpcFlatpakServiceImplClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ipc_flatpak_service_impl_finalize;
+}
+
+static void
+ipc_flatpak_service_impl_init (IpcFlatpakServiceImpl *self)
+{
+  self->installs = g_hash_table_new_full (g_file_hash,
+                                               (GEqualFunc) g_file_equal,
+                                               g_object_unref,
+                                               (GDestroyNotify) install_free);
+  self->runtimes = g_ptr_array_new_with_free_func ((GDestroyNotify) runtime_free);
+}
+
+IpcFlatpakService *
+ipc_flatpak_service_impl_new (void)
+{
+  return g_object_new (IPC_TYPE_FLATPAK_SERVICE_IMPL, NULL);
+}
diff --git a/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.h 
b/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.h
new file mode 100644
index 000000000..0ab95b9d8
--- /dev/null
+++ b/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.h
@@ -0,0 +1,33 @@
+/* ipc-flatpak-service-impl.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 "ipc-flatpak-service.h"
+
+G_BEGIN_DECLS
+
+#define IPC_TYPE_FLATPAK_SERVICE_IMPL (ipc_flatpak_service_impl_get_type())
+
+G_DECLARE_FINAL_TYPE (IpcFlatpakServiceImpl, ipc_flatpak_service_impl, IPC, FLATPAK_SERVICE_IMPL, 
IpcFlatpakServiceSkeleton)
+
+IpcFlatpakService *ipc_flatpak_service_impl_new (void);
+
+G_END_DECLS
diff --git a/src/plugins/flatpak/daemon/ipc-flatpak-util.h b/src/plugins/flatpak/daemon/ipc-flatpak-util.h
new file mode 100644
index 000000000..d09099f75
--- /dev/null
+++ b/src/plugins/flatpak/daemon/ipc-flatpak-util.h
@@ -0,0 +1,42 @@
+/* ipc-flatpak-util.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 <gio/gio.h>
+
+G_BEGIN_DECLS
+
+static inline gboolean
+complete_wrapped_error (GDBusMethodInvocation *invocation,
+                        const GError          *error)
+{
+  g_autoptr(GError) wrapped = NULL;
+
+  wrapped = g_error_new (G_IO_ERROR,
+                         G_IO_ERROR_FAILED,
+                         "The operation failed. The original error was \"%s\"",
+                         error->message);
+  g_dbus_method_invocation_return_gerror (invocation, wrapped);
+
+  return TRUE;
+}
+
+G_END_DECLS
diff --git a/src/plugins/flatpak/daemon/meson.build b/src/plugins/flatpak/daemon/meson.build
new file mode 100644
index 000000000..508ba7065
--- /dev/null
+++ b/src/plugins/flatpak/daemon/meson.build
@@ -0,0 +1,33 @@
+gnome_builder_flatpak_deps = [
+  libgiounix_dep,
+  dependency('flatpak', version: '>= 1.0.0'),
+  dependency('ostree-1'),
+  dependency('libsoup-2.4', version: '>= 2.52.0'),
+]
+
+ipc_flatpak_service_src = gnome.gdbus_codegen('ipc-flatpak-service',
+           sources: 'org.gnome.Builder.Flatpak.Service.xml',
+  interface_prefix: 'org.gnome.Builder.',
+         namespace: 'Ipc',
+)
+
+gnome_builder_flatpak_sources = [
+  'gnome-builder-flatpak.c',
+  'ipc-flatpak-service-impl.c',
+  ipc_flatpak_service_src,
+]
+
+gnome_builder_flatpak = executable('gnome-builder-flatpak', gnome_builder_flatpak_sources,
+           install: true,
+       install_dir: get_option('libexecdir'),
+      dependencies: gnome_builder_flatpak_deps,
+)
+
+test_flatpak_sources = [
+  'test-flatpak.c',
+  ipc_flatpak_service_src,
+]
+
+test_flatpak = executable('test-flatpak', 'test-flatpak.c', test_flatpak_sources,
+  dependencies: [ libgiounix_dep ],
+)
diff --git a/src/plugins/flatpak/daemon/org.gnome.Builder.Flatpak.Service.xml 
b/src/plugins/flatpak/daemon/org.gnome.Builder.Flatpak.Service.xml
new file mode 100644
index 000000000..7d2acd42f
--- /dev/null
+++ b/src/plugins/flatpak/daemon/org.gnome.Builder.Flatpak.Service.xml
@@ -0,0 +1,50 @@
+<!DOCTYPE node PUBLIC
+        "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+        "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"; >
+<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd";>
+  <!--
+    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
+  -->
+  <interface name="org.gnome.Builder.Flatpak.Service">
+    <signal name="RuntimeAdded">
+      <!--
+        Param is (name, arch, branch, sdk_name, sdk_branch, is_sdk_extension)
+      -->
+      <arg name="runtime" direction="in" type="(sssssb)"/>
+    </signal>
+    <!--
+      AddInstallation:
+      @path: the path of the installation
+      @is_user: if the installation is a user installation
+
+      Adds an installation to the list of monitored installations.
+    -->
+    <method name="AddInstallation">
+      <arg name="path" direction="in" type="ay"/>
+      <arg name="is_user" direction="in" type="b"/>
+    </method>
+    <!--
+      ListRuntimes:
+
+      Lists the available runtimes for use as development.
+    -->
+    <method name="ListRuntimes">
+      <arg name="runtimes" direction="out" type="a(sssssb)"/>
+    </method>
+  </interface>
+</node>
diff --git a/src/plugins/flatpak/daemon/test-flatpak.c b/src/plugins/flatpak/daemon/test-flatpak.c
new file mode 100644
index 000000000..927ecef49
--- /dev/null
+++ b/src/plugins/flatpak/daemon/test-flatpak.c
@@ -0,0 +1,155 @@
+/* test-flatpak.c
+ *
+ * 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
+ */
+
+#include <glib-unix.h>
+#include <gio/gunixinputstream.h>
+#include <gio/gunixoutputstream.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "ipc-flatpak-service.h"
+
+static void
+on_runtime_added_cb (IpcFlatpakService *service,
+                     GVariant          *info)
+{
+  const gchar *name;
+  const gchar *arch;
+  const gchar *branch;
+  const gchar *sdk_name;
+  const gchar *sdk_branch;
+  gboolean sdk_extension;
+
+  g_assert (IPC_IS_FLATPAK_SERVICE (service));
+  g_assert (info != NULL);
+  g_assert (g_variant_is_of_type (info, G_VARIANT_TYPE ("(sssssb)")));
+
+  g_variant_get (info, "(&s&s&s&s&sb)",
+                 &name, &arch, &branch, &sdk_name, &sdk_branch, &sdk_extension);
+
+  if (!sdk_extension)
+    g_message ("Runtime Added: %s/%s/%s with SDK %s//%s",
+               name, arch, branch, sdk_name, sdk_branch);
+  else
+    g_message ("SDK Extension Added: %s/%s/%s with SDK %s//%s",
+               name, arch, branch, sdk_name, sdk_branch);
+}
+
+static void
+add_install_cb (GObject      *object,
+                GAsyncResult *result,
+                gpointer      user_data)
+{
+  IpcFlatpakService *service = (IpcFlatpakService *)object;
+  g_autoptr(GMainLoop) main_loop = user_data;
+  g_autoptr(GVariant) runtimes = NULL;
+  g_autoptr(GError) error = NULL;
+  GVariantIter iter;
+  gboolean ret;
+
+  ret = ipc_flatpak_service_call_add_installation_finish (service, result, &error);
+  g_assert_no_error (error);
+  g_assert_true (ret);
+  g_message ("Installation added");
+
+  g_message ("Listing runtimes");
+  ret = ipc_flatpak_service_call_list_runtimes_sync (service, &runtimes, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_true (ret);
+
+  if (g_variant_iter_init (&iter, runtimes))
+    {
+      const gchar *name;
+      const gchar *arch;
+      const gchar *branch;
+      const gchar *sdk_name;
+      const gchar *sdk_branch;
+      gboolean sdk_extension;
+
+      while (g_variant_iter_next (&iter, "(&s&s&s&s&sb)",
+                                  &name, &arch, &branch, &sdk_name, &sdk_branch, &sdk_extension))
+        g_message ("  %s/%s/%s with SDK %s//%s (Extension: %d)",
+                   name, arch, branch, sdk_name, sdk_branch, sdk_extension);
+    }
+
+
+  g_main_loop_quit (main_loop);
+}
+
+gint
+main (gint argc,
+      gchar *argv[])
+{
+  g_autofree gchar *home_install = g_build_filename (g_get_home_dir (), ".local", "share", "flatpak", NULL);
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GIOStream) stream = NULL;
+  g_autoptr(GInputStream) stdout_stream = NULL;
+  g_autoptr(GOutputStream) stdin_stream = NULL;
+  g_autoptr(GDBusConnection) connection = NULL;
+  g_autoptr(GSubprocess) subprocess = NULL;
+  g_autoptr(GSubprocessLauncher) launcher = NULL;
+  g_autoptr(IpcFlatpakService) service = NULL;
+  GMainLoop *main_loop;
+
+  launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE);
+  subprocess = g_subprocess_launcher_spawn (launcher, &error, "./gnome-builder-flatpak", NULL);
+
+  if (subprocess == NULL)
+    g_error ("%s", error->message);
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  stdin_stream = g_subprocess_get_stdin_pipe (subprocess);
+  stdout_stream = g_subprocess_get_stdout_pipe (subprocess);
+  stream = g_simple_io_stream_new (stdout_stream, stdin_stream);
+  connection = g_dbus_connection_new_sync (stream,
+                                           NULL,
+                                           G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING,
+                                           NULL,
+                                           NULL,
+                                           &error);
+  g_assert_no_error (error);
+  g_assert_true (G_IS_DBUS_CONNECTION (connection));
+
+  g_dbus_connection_set_exit_on_close (connection, FALSE);
+  g_dbus_connection_start_message_processing (connection);
+
+  g_message ("Creating flatpak service proxy");
+  service = ipc_flatpak_service_proxy_new_sync (connection, 0, NULL, "/org/gnome/Builder/Flatpak", NULL, 
&error);
+  g_assert_no_error (error);
+  g_assert_true (IPC_IS_FLATPAK_SERVICE (service));
+
+  g_signal_connect (service,
+                    "runtime-added",
+                    G_CALLBACK (on_runtime_added_cb),
+                    NULL);
+
+  g_message ("Adding user installation to daemon");
+  ipc_flatpak_service_call_add_installation (service,
+                                             home_install,
+                                             TRUE,
+                                             NULL,
+                                             add_install_cb,
+                                             g_main_loop_ref (main_loop));
+
+  g_main_loop_run (main_loop);
+
+  return EXIT_SUCCESS;
+}
diff --git a/src/plugins/flatpak/meson.build b/src/plugins/flatpak/meson.build
index 6fab01c1e..5b84734fd 100644
--- a/src/plugins/flatpak/meson.build
+++ b/src/plugins/flatpak/meson.build
@@ -4,6 +4,8 @@ if not get_option('plugin_git')
   error('-Dplugin_git=true is required for flatpak')
 endif
 
+subdir('daemon')
+
 plugins_sources += files([
   'flatpak-plugin.c',
   'gbp-flatpak-application-addin.c',


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