[gnome-builder/wip/chergert/gnome-builder-flatpak] flatpak: add API to query for known runtime, with download size



commit acb626f58e86e414825d7460f6b366d984c4c11d
Author: Christian Hergert <chergert redhat com>
Date:   Wed Apr 10 16:14:39 2019 -0700

    flatpak: add API to query for known runtime, with download size
    
    This allows querying if a runtime is available, and what size it will be
    if we need to install it.
    
    This is useful when checking to see if we have an SDK extension avilable
    and how much space it would take to install.

 .../flatpak/daemon/ipc-flatpak-service-impl.c      | 166 +++++++++++++++++++++
 .../daemon/org.gnome.Builder.Flatpak.Service.xml   |  11 ++
 src/plugins/flatpak/daemon/test-flatpak.c          |  20 ++-
 3 files changed, 195 insertions(+), 2 deletions(-)
---
diff --git a/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.c 
b/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.c
index fd24d11e8..7b1efc3af 100644
--- a/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.c
+++ b/src/plugins/flatpak/daemon/ipc-flatpak-service-impl.c
@@ -44,6 +44,13 @@ typedef struct
   GFileMonitor *monitor;
 } Install;
 
+typedef struct
+{
+  GDBusMethodInvocation *invocation;
+  GPtrArray             *installs;
+  FlatpakRef            *target;
+} IsKnown;
+
 struct _IpcFlatpakServiceImpl
 {
   IpcFlatpakServiceSkeleton parent;
@@ -72,6 +79,25 @@ static GVariant *runtime_to_variant                          (const Runtime
 static void      runtime_free                                (Runtime                *runtime);
 static gboolean  runtime_equal                               (const Runtime          *a,
                                                               const Runtime          *b);
+static void      is_known_free                               (IsKnown                *state);
+static FlatpakInstallation *installation_copy                (FlatpakInstallation    *installation);
+
+static FlatpakInstallation *
+installation_copy (FlatpakInstallation *installation)
+{
+  return flatpak_installation_new_for_path (flatpak_installation_get_path (installation),
+                                            flatpak_installation_get_is_user (installation),
+                                            NULL, NULL);
+}
+
+static void
+is_known_free (IsKnown *state)
+{
+  g_clear_pointer (&state->installs, g_ptr_array_unref);
+  g_clear_object (&state->invocation);
+  g_clear_object (&state->target);
+  g_slice_free (IsKnown, state);
+}
 
 static void
 add_runtime (IpcFlatpakServiceImpl *self,
@@ -293,6 +319,144 @@ ipc_flatpak_service_impl_list_runtimes (IpcFlatpakService     *service,
   return TRUE;
 }
 
+static void
+is_known_worker (GTask        *task,
+                 gpointer      source_object,
+                 gpointer      task_data,
+                 GCancellable *cancellable)
+{
+  g_autoptr(GPtrArray) remotes = NULL;
+  g_autoptr(GError) error = NULL;
+  IsKnown *state = task_data;
+  const gchar *ref_name;
+  const gchar *ref_arch;
+  const gchar *ref_branch;
+  gint64 download_size = 0;
+  gboolean found = FALSE;
+
+  g_assert (G_IS_TASK (task));
+  g_assert (IPC_IS_FLATPAK_SERVICE_IMPL (source_object));
+  g_assert (state != NULL);
+  g_assert (state->installs != NULL);
+  g_assert (G_IS_DBUS_METHOD_INVOCATION (state->invocation));
+  g_assert (FLATPAK_IS_REF (state->target));
+  g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+  ref_name = flatpak_ref_get_name (state->target);
+  ref_arch = flatpak_ref_get_arch (state->target);
+  ref_branch = flatpak_ref_get_branch (state->target);
+
+  for (guint z = 0; z < state->installs->len; z++)
+    {
+      FlatpakInstallation *install = g_ptr_array_index (state->installs, z);
+
+      if (!(remotes = flatpak_installation_list_remotes (install, NULL, &error)))
+        goto finish;
+
+      for (guint i = 0; i < remotes->len; i++)
+        {
+          FlatpakRemote *remote = g_ptr_array_index (remotes, i);
+          const gchar *remote_name = flatpak_remote_get_name (remote);
+          g_autoptr(GPtrArray) refs = NULL;
+
+          if (!(refs = flatpak_installation_list_remote_refs_sync (install, remote_name, NULL, NULL)))
+            continue;
+
+          for (guint j = 0; j < refs->len; j++)
+            {
+              FlatpakRemoteRef *remote_ref = g_ptr_array_index (refs, j);
+
+              if (g_str_equal (ref_name, flatpak_ref_get_name (FLATPAK_REF (remote_ref))) &&
+                  g_str_equal (ref_arch, flatpak_ref_get_arch (FLATPAK_REF (remote_ref))) &&
+                  g_str_equal (ref_branch, flatpak_ref_get_branch (FLATPAK_REF (remote_ref))))
+                {
+                  found = TRUE;
+                  download_size = flatpak_remote_ref_get_download_size (remote_ref);
+                  goto finish;
+                }
+            }
+        }
+    }
+
+finish:
+  ipc_flatpak_service_complete_runtime_is_known (g_task_get_source_object (task),
+                                                 g_steal_pointer (&state->invocation),
+                                                 found,
+                                                 download_size);
+
+  if (error != NULL)
+    g_task_return_error (task, g_steal_pointer (&error));
+  else
+    g_task_return_boolean (task, TRUE);
+}
+
+static gboolean
+ipc_flatpak_service_impl_runtime_is_known (IpcFlatpakService     *service,
+                                           GDBusMethodInvocation *invocation,
+                                           const gchar           *name)
+{
+  IpcFlatpakServiceImpl *self = (IpcFlatpakServiceImpl *)service;
+  g_autofree gchar *full_name = NULL;
+  g_autoptr(FlatpakRef) ref = NULL;
+  g_autoptr(GError) error = NULL;
+  g_autoptr(GTask) task = NULL;
+  const gchar *ref_name;
+  const gchar *ref_arch;
+  const gchar *ref_branch;
+  GHashTableIter iter;
+  Install *install;
+  IsKnown *state;
+
+  g_assert (IPC_IS_FLATPAK_SERVICE_IMPL (self));
+  g_assert (G_IS_DBUS_METHOD_INVOCATION (invocation));
+  g_assert (name != NULL);
+
+  /* Homogenize names into runtime/name/arch/branch */
+  if (g_str_has_prefix (name, "runtime/"))
+    name += strlen ("runtime/");
+  full_name = g_strdup_printf ("runtime/%s", name);
+
+  /* Parse the ref, so we can try to locate it */
+  if (!(ref = flatpak_ref_parse (full_name, &error)))
+    return complete_wrapped_error (invocation, error);
+
+  ref_name = flatpak_ref_get_name (ref);
+  ref_arch = flatpak_ref_get_arch (ref);
+  ref_branch = flatpak_ref_get_branch (ref);
+
+  /* First check if we know about the runtime from those installed */
+  for (guint i = 0; i < self->runtimes->len; i++)
+    {
+      const Runtime *runtime = g_ptr_array_index (self->runtimes, i);
+
+      if (g_str_equal (ref_name, runtime->name) &&
+          g_str_equal (ref_arch, runtime->arch) &&
+          g_str_equal (ref_branch, runtime->branch))
+        {
+          ipc_flatpak_service_complete_runtime_is_known (service, invocation, TRUE, 0);
+          return TRUE;
+        }
+    }
+
+  state = g_slice_new0 (IsKnown);
+  state->installs = g_ptr_array_new_with_free_func (g_object_unref);
+  state->target = g_object_ref (ref);
+  state->invocation = g_steal_pointer (&invocation);
+
+  task = g_task_new (self, NULL, NULL, NULL);
+  g_task_set_source_tag (task, ipc_flatpak_service_impl_runtime_is_known);
+  g_task_set_task_data (task, state, (GDestroyNotify) is_known_free);
+
+  /* Now check remote refs */
+  g_hash_table_iter_init (&iter, self->installs);
+  while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&install))
+    g_ptr_array_add (state->installs, installation_copy (install->installation));
+
+  g_task_run_in_thread (task, is_known_worker);
+
+  return TRUE;
+}
+
 static void
 ipc_flatpak_service_impl_install_changed_cb (IpcFlatpakServiceImpl *self,
                                              GFile                 *file,
@@ -325,6 +489,7 @@ 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;
+  iface->handle_runtime_is_known = ipc_flatpak_service_impl_runtime_is_known;
 }
 
 G_DEFINE_TYPE_WITH_CODE (IpcFlatpakServiceImpl, ipc_flatpak_service_impl, IPC_TYPE_FLATPAK_SERVICE_SKELETON,
@@ -336,6 +501,7 @@ ipc_flatpak_service_impl_finalize (GObject *object)
   IpcFlatpakServiceImpl *self = (IpcFlatpakServiceImpl *)object;
 
   g_clear_pointer (&self->installs, g_hash_table_unref);
+  g_clear_pointer (&self->runtimes, g_ptr_array_unref);
 
   G_OBJECT_CLASS (ipc_flatpak_service_impl_parent_class)->finalize (object);
 }
diff --git a/src/plugins/flatpak/daemon/org.gnome.Builder.Flatpak.Service.xml 
b/src/plugins/flatpak/daemon/org.gnome.Builder.Flatpak.Service.xml
index 7d2acd42f..45641018e 100644
--- a/src/plugins/flatpak/daemon/org.gnome.Builder.Flatpak.Service.xml
+++ b/src/plugins/flatpak/daemon/org.gnome.Builder.Flatpak.Service.xml
@@ -46,5 +46,16 @@
     <method name="ListRuntimes">
       <arg name="runtimes" direction="out" type="a(sssssb)"/>
     </method>
+    <!--
+      RuntimeIsKnown:
+      @name: a runtime name to lookup in form name/arch/branch
+
+      Checks to see if any installation knows about the runtime.
+    -->
+    <method name="RuntimeIsKnown">
+      <arg name="name" direction="in" type="s"/>
+      <arg name="is_known" direction="out" type="b"/>
+      <arg name="download_size" direction="out" type="x"/>
+    </method>
   </interface>
 </node>
diff --git a/src/plugins/flatpak/daemon/test-flatpak.c b/src/plugins/flatpak/daemon/test-flatpak.c
index 927ecef49..43504d34a 100644
--- a/src/plugins/flatpak/daemon/test-flatpak.c
+++ b/src/plugins/flatpak/daemon/test-flatpak.c
@@ -59,11 +59,14 @@ add_install_cb (GObject      *object,
                 gpointer      user_data)
 {
   IpcFlatpakService *service = (IpcFlatpakService *)object;
+  g_autofree gchar *sizestr = NULL;
   g_autoptr(GMainLoop) main_loop = user_data;
   g_autoptr(GVariant) runtimes = NULL;
   g_autoptr(GError) error = NULL;
   GVariantIter iter;
+  gboolean is_known = TRUE;
   gboolean ret;
+  gint64 download_size = 0;
 
   ret = ipc_flatpak_service_call_add_installation_finish (service, result, &error);
   g_assert_no_error (error);
@@ -84,12 +87,25 @@ add_install_cb (GObject      *object,
       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))
+      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_message ("Checking for a missing runtime");
+  ret = ipc_flatpak_service_call_runtime_is_known_sync (service, "me.hergert.FooBar/x86_64/master", 
&is_known, &download_size, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_true (ret);
+  g_assert_false (is_known);
+  g_message ("  Not found");
+
+  g_message ("Checking if org.gnome.Sdk/x86_64/3.24 is known");
+  ret = ipc_flatpak_service_call_runtime_is_known_sync (service, "org.gnome.Sdk/x86_64/3.24", &is_known, 
&download_size, NULL, &error);
+  g_assert_no_error (error);
+  g_assert_true (ret);
+  g_assert_true (is_known);
+  sizestr = g_format_size (download_size);
+  g_message ("  Found, Download Size: <=%s", sizestr);
 
   g_main_loop_quit (main_loop);
 }


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