[gnome-software] Support installing local xdg-app bundles



commit caab4097a4458fb2e8e1c83f4de2c433e518d79b
Author: Richard Hughes <richard hughsie com>
Date:   Fri Feb 26 14:49:40 2016 +0000

    Support installing local xdg-app bundles

 configure.ac                             |    2 +-
 src/gnome-software-local-file.desktop.in |    2 +-
 src/plugins/gs-plugin-xdg-app.c          |  203 ++++++++++++++++++++++++++++--
 3 files changed, 196 insertions(+), 11 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 6206126..b64752a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -164,7 +164,7 @@ AC_ARG_ENABLE(xdg-app,
               enable_xdg_app=maybe)
 AS_IF([test "x$enable_xdg_app" != "xno"], [
     PKG_CHECK_MODULES(XDG_APP,
-                      [xdg-app >= 0.4.12],
+                      [xdg-app >= 0.4.14],
                       [have_xdg_app=yes],
                       [have_xdg_app=no])
 ], [
diff --git a/src/gnome-software-local-file.desktop.in b/src/gnome-software-local-file.desktop.in
index b77386c..1be2ea3 100644
--- a/src/gnome-software-local-file.desktop.in
+++ b/src/gnome-software-local-file.desktop.in
@@ -8,4 +8,4 @@ Type=Application
 Icon=system-software-install
 StartupNotify=true
 NoDisplay=true
-MimeType=application/x-rpm;application/x-redhat-package-manager;application/x-deb;application/x-app-package;application/vnd.ms-cab-compressed;
+MimeType=application/x-rpm;application/x-redhat-package-manager;application/x-deb;application/x-app-package;application/vnd.ms-cab-compressed;application/vnd.xdgapp;
diff --git a/src/plugins/gs-plugin-xdg-app.c b/src/plugins/gs-plugin-xdg-app.c
index 6f7c6e8..b2fa374 100644
--- a/src/plugins/gs-plugin-xdg-app.c
+++ b/src/plugins/gs-plugin-xdg-app.c
@@ -1341,16 +1341,28 @@ gs_plugin_app_install (GsPlugin *plugin,
                }
        }
 
+       /* use the source for local apps */
+       if (gs_app_get_state (app) == AS_APP_STATE_AVAILABLE_LOCAL) {
+               g_autoptr(GFile) file = NULL;
+               file = g_file_new_for_path (gs_app_get_source_default (app));
+               xref = xdg_app_installation_install_bundle (plugin->priv->installation,
+                                                           file,
+                                                           gs_plugin_xdg_app_progress_cb,
+                                                           &helper,
+                                                           cancellable, error);
+       } else {
+               g_debug ("installing %s", gs_app_get_id (app));
+               xref = xdg_app_installation_install (plugin->priv->installation,
+                                                    gs_app_get_origin (app),
+                                                    gs_app_get_xdgapp_kind (app),
+                                                    gs_app_get_xdgapp_name (app),
+                                                    gs_app_get_xdgapp_arch (app),
+                                                    gs_app_get_xdgapp_branch (app),
+                                                    gs_plugin_xdg_app_progress_cb, &helper,
+                                                    cancellable, error);
+       }
+
        /* now the main application */
-       g_debug ("installing %s", gs_app_get_id (app));
-       xref = xdg_app_installation_install (plugin->priv->installation,
-                                            gs_app_get_origin (app),
-                                            gs_app_get_xdgapp_kind (app),
-                                            gs_app_get_xdgapp_name (app),
-                                            gs_app_get_xdgapp_arch (app),
-                                            gs_app_get_xdgapp_branch (app),
-                                            gs_plugin_xdg_app_progress_cb, &helper,
-                                            cancellable, error);
        return xref != NULL;
 }
 
@@ -1392,3 +1404,176 @@ gs_plugin_app_update (GsPlugin *plugin,
                                            cancellable, error);
        return xref != NULL;
 }
+
+/**
+ * gs_plugin_xdg_app_content_type_matches:
+ */
+static gboolean
+gs_plugin_xdg_app_content_type_matches (const gchar *filename,
+                                     gboolean *matches,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+       const gchar *tmp;
+       guint i;
+       g_autoptr(GFile) file = NULL;
+       g_autoptr(GFileInfo) info = NULL;
+       const gchar *mimetypes[] = {
+               "application/vnd.xdgapp",
+               NULL };
+
+       /* get content type */
+       file = g_file_new_for_path (filename);
+       info = g_file_query_info (file,
+                                 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                                 G_FILE_QUERY_INFO_NONE,
+                                 cancellable,
+                                 error);
+       if (info == NULL)
+               return FALSE;
+       tmp = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE);
+
+       /* match any */
+       *matches = FALSE;
+       for (i = 0; mimetypes[i] != NULL; i++) {
+               if (g_strcmp0 (tmp, mimetypes[i]) == 0) {
+                       *matches = TRUE;
+                       break;
+               }
+       }
+       return TRUE;
+}
+
+/**
+ * gs_plugin_filename_to_app:
+ */
+gboolean
+gs_plugin_filename_to_app (GsPlugin *plugin,
+                          GList **list,
+                          const gchar *filename,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+       gboolean supported;
+       g_autofree gchar *id_prefixed = NULL;
+       g_autoptr(GBytes) appstream_gz = NULL;
+       g_autoptr(GBytes) icon_data = NULL;
+       g_autoptr(GBytes) metadata = NULL;
+       g_autoptr(GError) error_local = NULL;
+       g_autoptr(GFile) file = NULL;
+       g_autoptr(GsApp) app = NULL;
+       g_autoptr(XdgAppBundleRef) xref_bundle = NULL;
+
+       /* does this match any of the mimetypes we support */
+       if (!gs_plugin_xdg_app_content_type_matches (filename,
+                                                    &supported,
+                                                    cancellable,
+                                                    error))
+               return FALSE;
+       if (!supported)
+               return TRUE;
+
+       /* load bundle */
+       file = g_file_new_for_path (filename);
+       xref_bundle = xdg_app_bundle_ref_new (file, &error_local);
+       if (xref_bundle == NULL) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_NOT_SUPPORTED,
+                            "Error loading bundle: %s",
+                            error_local->message);
+               return FALSE;
+       }
+
+       /* create a virtual ID */
+       id_prefixed = gs_plugin_xdg_app_build_id (XDG_APP_REF (xref_bundle));
+
+       /* load metadata */
+       app = gs_app_new (id_prefixed);
+       gs_app_set_kind (app, AS_APP_KIND_DESKTOP);
+       gs_app_set_state (app, AS_APP_STATE_AVAILABLE_LOCAL);
+       gs_app_set_size (app, xdg_app_bundle_ref_get_installed_size (xref_bundle));
+       gs_plugin_xdg_app_set_metadata (app, XDG_APP_REF (xref_bundle));
+       metadata = xdg_app_bundle_ref_get_metadata (xref_bundle);
+       if (!gs_plugin_xdg_app_set_app_metadata (app,
+                                                g_bytes_get_data (metadata, NULL),
+                                                g_bytes_get_size (metadata),
+                                                error))
+               return FALSE;
+
+       /* load AppStream */
+       appstream_gz = xdg_app_bundle_ref_get_appstream (xref_bundle);
+       if (appstream_gz != NULL) {
+               g_autoptr(GZlibDecompressor) decompressor = NULL;
+               g_autoptr(GInputStream) stream_gz = NULL;
+               g_autoptr(GInputStream) stream_data = NULL;
+               g_autoptr(GBytes) appstream = NULL;
+               g_autoptr(AsStore) store = NULL;
+               g_autofree gchar *id = NULL;
+               AsApp *item;
+
+               /* decompress data */
+               decompressor = g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP);
+               stream_gz = g_memory_input_stream_new_from_bytes (appstream_gz);
+               if (stream_gz == NULL)
+                       return FALSE;
+               stream_data = g_converter_input_stream_new (stream_gz,
+                                                           G_CONVERTER (decompressor));
+
+               appstream = g_input_stream_read_bytes (stream_data,
+                                                      0x100000, /* 1Mb */
+                                                      cancellable,
+                                                      error);
+               if (appstream == NULL)
+                       return FALSE;
+               store = as_store_new ();
+               if (!as_store_from_bytes (store, appstream, cancellable, error))
+                       return FALSE;
+
+               /* find app */
+               id = g_strdup_printf ("%s.desktop", gs_app_get_xdgapp_name (app));
+               item = as_store_get_app_by_id (store, id);
+               if (item == NULL) {
+                       g_set_error (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "application %s not found",
+                                    id);
+                       return FALSE;
+               }
+
+               /* copy details from AppStream to app */
+               if (!gs_appstream_refine_app (plugin, app, item, error))
+                       return FALSE;
+       }
+
+       /* load icon */
+       icon_data = xdg_app_bundle_ref_get_icon (xref_bundle, 64);
+       if (icon_data != NULL) {
+               g_autoptr(GInputStream) stream_icon = NULL;
+               g_autoptr(GdkPixbuf) pixbuf = NULL;
+               stream_icon = g_memory_input_stream_new_from_bytes (icon_data);
+               pixbuf = gdk_pixbuf_new_from_stream (stream_icon, cancellable, error);
+               if (pixbuf == NULL)
+                       return FALSE;
+               gs_app_set_pixbuf (app, pixbuf);
+       } else {
+               g_autoptr(AsIcon) icon = NULL;
+               icon = as_icon_new ();
+               as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
+               as_icon_set_name (icon, "application-x-executable");
+               gs_app_set_icon (app, icon);
+       }
+
+
+       /* set the source so we can install it higher up */
+       gs_app_add_source (app, filename);
+
+       /* not quite true: this just means we can update this specific app */
+       if (xdg_app_bundle_ref_get_origin (xref_bundle))
+               gs_app_add_quirk (app, AS_APP_QUIRK_HAS_SOURCE);
+
+       g_debug ("created local app: %s", gs_app_to_string (app));
+       gs_plugin_add_app (list, app);
+       return TRUE;
+}


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