[gnome-software] Support installing local xdg-app bundles
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Support installing local xdg-app bundles
- Date: Fri, 26 Feb 2016 15:15:46 +0000 (UTC)
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]