[gnome-software/wip/hughsie/xdg-app: 39/39] Add xdg-app support
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/hughsie/xdg-app: 39/39] Add xdg-app support
- Date: Mon, 18 Jan 2016 15:04:56 +0000 (UTC)
commit 74ab500f05ecc6af9a11fc31b95bee0f7c35156c
Author: Richard Hughes <richard hughsie com>
Date: Tue Dec 22 09:20:22 2015 +0000
Add xdg-app support
configure.ac | 17 +
src/gs-shell-details.c | 1 +
src/gs-shell-installed.c | 5 +-
src/gs-update-list.c | 2 +
src/plugins/Makefile.am | 15 +
src/plugins/gs-plugin-appstream.c | 1 +
src/plugins/gs-plugin-packagekit-refresh.c | 2 +
src/plugins/gs-plugin-packagekit.c | 1 +
src/plugins/gs-plugin-xdg-app.c | 871 ++++++++++++++++++++++++++++
9 files changed, 914 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 82e5d75..dd3a15f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -105,6 +105,22 @@ AS_IF([test "x$enable_firmware" != "xno"], [
have_firmware=no
])
+# xdg-app
+AC_ARG_ENABLE(xdg-app,
+ [AS_HELP_STRING([--enable-xdg-app],
+ [enable xdg-app support [default=auto]])],,
+ enable_xdg_app=maybe)
+
+AS_IF([test "x$enable_xdg_app" != "xno"], [
+ PKG_CHECK_MODULES(XDG_APP,
+ [xdg-app],
+ [have_xdg_app=yes],
+ [have_xdg_app=no])
+], [
+ have_xdg_app=no
+])
+AM_CONDITIONAL(HAVE_XDG_APP, test "$have_xdg_app" != no)
+
AS_IF([test "x$have_firmware" = "xyes"], [
AC_DEFINE(HAVE_FIRMWARE,1,[Build firmware support])
], [
@@ -183,5 +199,6 @@ echo "
cppflags: ${CPPFLAGS}
Dogtail: ${enable_dogtail}
Firmware support: ${have_firmware}
+ XDG-APP support: ${have_xdg_app}
"
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index 06dbcff..2604c45 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -1064,6 +1064,7 @@ gs_shell_details_load (GsShellDetails *self)
GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN |
GS_PLUGIN_REFINE_FLAGS_REQUIRE_MENU_PATH |
GS_PLUGIN_REFINE_FLAGS_REQUIRE_URL |
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION |
GS_PLUGIN_REFINE_FLAGS_REQUIRE_ADDONS,
self->cancellable,
gs_shell_details_app_refine_cb,
diff --git a/src/gs-shell-installed.c b/src/gs-shell-installed.c
index 88ee197..a9f5063 100644
--- a/src/gs-shell-installed.c
+++ b/src/gs-shell-installed.c
@@ -333,9 +333,12 @@ gs_shell_installed_get_app_sort_key (GsApp *app)
case AS_ID_KIND_WEB_APP:
g_string_append (key, "1:");
break;
- default:
+ case AS_ID_KIND_RUNTIME:
g_string_append (key, "2:");
break;
+ default:
+ g_string_append (key, "9:");
+ break;
}
/* sort normal, system, other */
diff --git a/src/gs-update-list.c b/src/gs-update-list.c
index da49992..4fa7c17 100644
--- a/src/gs-update-list.c
+++ b/src/gs-update-list.c
@@ -103,6 +103,8 @@ is_addon_id_kind (GsApp *app)
return FALSE;
if (id_kind == AS_ID_KIND_FIRMWARE)
return FALSE;
+ if (id_kind == AS_ID_KIND_RUNTIME)
+ return FALSE;
return TRUE;
}
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 66e926b..383b6ef 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -11,6 +11,7 @@ AM_CPPFLAGS = \
$(SQLITE_CFLAGS) \
$(FWUPD_CFLAGS) \
$(LIMBA_CFLAGS) \
+ $(XDG_APP_CFLAGS) \
-DBINDIR=\"$(bindir)\" \
-DDATADIR=\"$(datadir)\" \
-DGS_MODULESETDIR=\"$(datadir)/gnome-software/modulesets.d\" \
@@ -52,6 +53,10 @@ if HAVE_FIRMWARE
plugin_LTLIBRARIES += libgs_plugin_fwupd.la
endif
+if HAVE_XDG_APP
+plugin_LTLIBRARIES += libgs_plugin_xdg_app.la
+endif
+
if HAVE_LIMBA
plugin_LTLIBRARIES += libgs_plugin_limba.la
endif
@@ -106,6 +111,16 @@ libgs_plugin_limba_la_LDFLAGS = -module -avoid-version
libgs_plugin_limba_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
endif
+if HAVE_XDG_APP
+libgs_plugin_xdg_app_la_SOURCES = \
+ appstream-common.c \
+ appstream-common.h \
+ gs-plugin-xdg-app.c
+libgs_plugin_xdg_app_la_LIBADD = $(GS_PLUGIN_LIBS) $(XDG_APP_LIBS)
+libgs_plugin_xdg_app_la_LDFLAGS = -module -avoid-version
+libgs_plugin_xdg_app_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+endif
+
libgs_plugin_moduleset_la_SOURCES = \
gs-moduleset.c \
gs-moduleset.h \
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index c8a2710..4162f6b 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -88,6 +88,7 @@ gs_plugin_initialize (GsPlugin *plugin)
gs_plugin_check_distro_id (plugin, "ubuntu")) {
plugin->use_pkg_descriptions = TRUE;
}
+//gs_plugin_set_enabled(plugin, FALSE);
}
/**
diff --git a/src/plugins/gs-plugin-packagekit-refresh.c b/src/plugins/gs-plugin-packagekit-refresh.c
index 76b0cf9..aea6080 100644
--- a/src/plugins/gs-plugin-packagekit-refresh.c
+++ b/src/plugins/gs-plugin-packagekit-refresh.c
@@ -128,6 +128,8 @@ gs_plugin_refresh (GsPlugin *plugin,
if ((flags & GS_PLUGIN_REFRESH_FLAGS_UPDATES) == 0)
return TRUE;
+return TRUE;
+
/* cache age of 0 is user-initiated */
pk_client_set_background (PK_CLIENT (plugin->priv->task), cache_age > 0);
diff --git a/src/plugins/gs-plugin-packagekit.c b/src/plugins/gs-plugin-packagekit.c
index 0210db3..05af288 100644
--- a/src/plugins/gs-plugin-packagekit.c
+++ b/src/plugins/gs-plugin-packagekit.c
@@ -63,6 +63,7 @@ gs_plugin_initialize (GsPlugin *plugin)
pk_client_set_background (PK_CLIENT (plugin->priv->task), FALSE);
pk_client_set_interactive (PK_CLIENT (plugin->priv->task), FALSE);
pk_client_set_cache_age (PK_CLIENT (plugin->priv->task), G_MAXUINT);
+//gs_plugin_set_enabled(plugin, FALSE);
}
/**
diff --git a/src/plugins/gs-plugin-xdg-app.c b/src/plugins/gs-plugin-xdg-app.c
new file mode 100644
index 0000000..139fbe7
--- /dev/null
+++ b/src/plugins/gs-plugin-xdg-app.c
@@ -0,0 +1,871 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2015 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Notes:
+ *
+ * All GsApp's created have management-plugin set to XgdApp
+ * Some GsApp's created have have XgdApp::type of app or runtime
+ * The GsApp:origin is the remote name, e.g. test-repo
+ *
+ * Some outstanding notes:
+ *
+ * - How can I get the AppStream metadata using libxdgapp?
+ * - Where is the privaledge elevation helper?
+ */
+
+#include <config.h>
+
+#include <xdg-app.h>
+
+#include <gs-plugin.h>
+
+#include "appstream-common.h"
+
+struct GsPluginPrivate {
+ XdgAppInstallation *installation;
+ GFileMonitor *monitor;
+};
+
+/**
+ * gs_plugin_get_name:
+ */
+const gchar *
+gs_plugin_get_name (void)
+{
+ return "xdg-app";
+}
+
+/**
+ * gs_plugin_initialize:
+ */
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+ /* create private area */
+ plugin->priv = GS_PLUGIN_GET_PRIVATE (GsPluginPrivate);
+}
+
+/**
+ * gs_plugin_destroy:
+ */
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+ if (plugin->priv->installation != NULL)
+ g_object_unref (plugin->priv->installation);
+ if (plugin->priv->monitor != NULL)
+ g_object_unref (plugin->priv->monitor);
+}
+
+/**
+ * gs_plugin_xdg_app_changed_cb:
+ */
+static void
+gs_plugin_xdg_app_changed_cb (GFileMonitor *monitor,
+ GFile *child,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GsPlugin *plugin)
+{
+ gs_plugin_updates_changed (plugin);
+}
+
+/**
+ * gs_plugin_ensure_installation:
+ */
+static gboolean
+gs_plugin_ensure_installation (GsPlugin *plugin,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(AsProfileTask) ptask = NULL;
+ if (plugin->priv->installation != NULL)
+ return TRUE;
+
+ /* FIXME: this should default to system-wide, but we need a permissions
+ * helper to elevate privs */
+ ptask = as_profile_start_literal (plugin->profile, "xdg-app::ensure-origin");
+ plugin->priv->installation = xdg_app_installation_new_user (cancellable, error);
+ if (plugin->priv->installation == NULL)
+ return FALSE;
+
+ /* watch for changes */
+ plugin->priv->monitor =
+ xdg_app_installation_create_monitor (plugin->priv->installation,
+ cancellable,
+ error);
+ if (plugin->priv->monitor == NULL)
+ return FALSE;
+ g_signal_connect (plugin->priv->monitor, "changed",
+ G_CALLBACK (gs_plugin_xdg_app_changed_cb), plugin);
+
+ /* success */
+ return TRUE;
+}
+
+/**
+ * gs_plugin_xdg_app_set_metadata:
+ */
+static void
+gs_plugin_xdg_app_set_metadata (GsApp *app, XdgAppInstalledRef *app_ref)
+{
+ gs_app_set_management_plugin (app, "XgdApp");
+ gs_app_set_metadata (app, "XgdApp::branch",
+ xdg_app_ref_get_branch (XDG_APP_REF (app_ref)));
+ gs_app_set_metadata (app, "XgdApp::commit",
+ xdg_app_ref_get_commit (XDG_APP_REF (app_ref)));
+ gs_app_set_metadata (app, "XgdApp::name",
+ xdg_app_ref_get_name (XDG_APP_REF(app_ref)));
+ gs_app_set_metadata (app, "XgdApp::arch",
+ xdg_app_ref_get_arch (XDG_APP_REF (app_ref)));
+ gs_app_set_origin (app, xdg_app_installed_ref_get_origin (app_ref));
+
+ switch (xdg_app_ref_get_kind (XDG_APP_REF(app_ref))) {
+ case XDG_APP_REF_KIND_APP:
+ gs_app_set_metadata (app, "XgdApp::type", "app");
+ break;
+ case XDG_APP_REF_KIND_RUNTIME:
+ gs_app_set_metadata (app, "XgdApp::type", "runtime");
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ * gs_plugin_xdg_app_create_installed:
+ */
+static GsApp *
+gs_plugin_xdg_app_create_installed (GsPlugin *plugin,
+ XdgAppInstalledRef *app_ref,
+ GError **error)
+{
+ AsApp *item;
+ AsIcon *ic;
+ g_autofree gchar *appdata_path = NULL;
+ g_autofree gchar *desktop_id = NULL;
+ g_autofree gchar *desktop_path = NULL;
+ g_autofree gchar *icon_fn = NULL;
+ g_autofree gchar *id = NULL;
+ g_autoptr(AsIcon) icon = NULL;
+ g_autoptr(AsStore) store = NULL;
+ g_autoptr(GsApp) app = NULL;
+
+ g_return_val_if_fail (app_ref != NULL, NULL);
+
+ /*
+ * Only show the current application in GNOME Software
+ *
+ * You can have multiple versions/branches of a particular app-id
+ * installed but only one of them is "current" where this means:
+ * 1) the default to launch unless you specify a version
+ * 2) The one that gets its exported files exported
+ */
+ if (!xdg_app_installed_ref_get_is_current (app_ref) &&
+ xdg_app_ref_get_kind (XDG_APP_REF(app_ref)) == XDG_APP_REF_KIND_APP) {
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "%s not current, ignoring",
+ xdg_app_ref_get_name (XDG_APP_REF (app_ref)));
+ return NULL;
+ }
+
+ /* create new object */
+ app = gs_app_new (NULL);
+ gs_app_set_kind (app, GS_APP_KIND_NORMAL);
+ gs_plugin_xdg_app_set_metadata (app, app_ref);
+
+ switch (xdg_app_ref_get_kind (XDG_APP_REF(app_ref))) {
+ case XDG_APP_REF_KIND_APP:
+ id = g_strdup_printf ("%s.desktop",
+ xdg_app_ref_get_name (XDG_APP_REF(app_ref)));
+ gs_app_set_id_kind (app, AS_ID_KIND_DESKTOP);
+ break;
+ case XDG_APP_REF_KIND_RUNTIME:
+ id = g_strdup_printf ("%s.runtime",
+ xdg_app_ref_get_name (XDG_APP_REF(app_ref)));
+ gs_app_set_metadata (app, "XgdApp::type", "runtime");
+ gs_app_set_id_kind (app, AS_ID_KIND_RUNTIME);
+ gs_app_set_name (app, GS_APP_QUALITY_NORMAL,
+ xdg_app_ref_get_name (XDG_APP_REF (app_ref)));
+ gs_app_set_summary (app, GS_APP_QUALITY_NORMAL,
+ "Framework for applications");
+ icon = as_icon_new ();
+ as_icon_set_kind (icon, AS_ICON_KIND_STOCK);
+ as_icon_set_name (icon, "system-run-symbolic");
+ gs_app_set_icon (app, icon);
+ break;
+ default:
+ g_set_error_literal (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "XdgAppRefKind not known");
+ return NULL;
+ }
+
+ /* we know the full application ID now */
+ gs_app_set_id (app, id);
+
+ /* refine using AppData allowing us to work without AppStream data */
+ store = as_store_new ();
+ desktop_path = g_build_filename (xdg_app_installed_ref_get_deploy_dir (app_ref),
+ "files",
+ "share",
+ "applications",
+ NULL);
+ appdata_path = g_build_filename (xdg_app_installed_ref_get_deploy_dir (app_ref),
+ "files",
+ "share",
+ "appdata",
+ NULL);
+ if (g_file_test (desktop_path, G_FILE_TEST_EXISTS)) {
+ if (!as_store_load_path (store, desktop_path, NULL, error))
+ return FALSE;
+ }
+ if (g_file_test (appdata_path, G_FILE_TEST_EXISTS)) {
+ if (!as_store_load_path (store, appdata_path, NULL, error))
+ return FALSE;
+ }
+
+ /* load any extra locations */
+ if (!as_store_load_path (store, "./appstream-extra", NULL, error))
+ return FALSE;
+
+ /* get app */
+ switch (xdg_app_ref_get_kind (XDG_APP_REF(app_ref))) {
+ case XDG_APP_REF_KIND_APP:
+ desktop_id = g_strdup_printf ("%s.desktop",
+ xdg_app_ref_get_name (XDG_APP_REF (app_ref)));
+ break;
+ case XDG_APP_REF_KIND_RUNTIME:
+ desktop_id = g_strdup_printf ("%s.runtime",
+ xdg_app_ref_get_name (XDG_APP_REF (app_ref)));
+ break;
+ default:
+ break;
+ }
+ item = as_store_get_app_by_id (store, desktop_id);
+ if (item != NULL) {
+ /* convert the icon name into an icon filename */
+ ic = as_app_get_icon_default (item);
+ if (ic != NULL && as_icon_get_kind (ic) == AS_ICON_KIND_LOCAL) {
+ const gchar *tmp;
+ tmp = xdg_app_installed_ref_get_deploy_dir (app_ref);
+ icon_fn = as_utils_find_icon_filename_full (tmp,
+ as_icon_get_name (ic),
+ AS_UTILS_FIND_ICON_HI_DPI,
+ error);
+ if (icon_fn == NULL)
+ return NULL;
+ g_debug ("converted icon %s to %s", as_icon_get_name (ic), icon_fn);
+ as_icon_set_filename (ic, icon_fn);
+ }
+
+ /* refine GsApp from AsApp */
+ if (!gs_appstream_refine_app (plugin, app, item, error))
+ return NULL;
+ }
+ return g_object_ref (app);
+}
+
+typedef struct {
+ GsApp *app;
+ GsPlugin *plugin;
+} GsPluginHelper;
+
+/**
+ * gs_plugin_xdg_app_progress_cb:
+ */
+static void
+gs_plugin_xdg_app_progress_cb (const gchar *status,
+ guint progress,
+ gboolean estimating,
+ gpointer user_data)
+{
+ GsPluginHelper *helper = (GsPluginHelper *) user_data;
+ if (helper->app == NULL)
+ return;
+ gs_plugin_progress_update (helper->plugin, helper->app, progress);
+}
+
+/**
+ * gs_plugin_add_installed:
+ */
+gboolean
+gs_plugin_add_installed (GsPlugin *plugin,
+ GList **list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(GPtrArray) xrefs = NULL;
+ guint i;
+
+ /* ensure we can set up the repo */
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ /* get apps and runtimes */
+ xrefs = xdg_app_installation_list_installed_refs (plugin->priv->installation,
+ cancellable, error);
+ if (xrefs == NULL)
+ return FALSE;
+ for (i = 0; i < xrefs->len; i++) {
+ XdgAppInstalledRef *xref = g_ptr_array_index (xrefs, i);
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GsApp) app = NULL;
+ app = gs_plugin_xdg_app_create_installed (plugin, xref, &error_local);
+ if (app == NULL) {
+ g_warning ("failed to add xdg-app: %s", error_local->message);
+ continue;
+ }
+ gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+ gs_plugin_add_app (list, app);
+ }
+
+ return TRUE;
+}
+
+/**
+ * gs_plugin_add_sources:
+ */
+gboolean
+gs_plugin_add_sources (GsPlugin *plugin,
+ GList **list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(GPtrArray) xremotes = NULL;
+ guint i;
+
+ /* ensure we can set up the repo */
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ xremotes = xdg_app_installation_list_remotes (plugin->priv->installation,
+ cancellable,
+ error);
+ if (xremotes == NULL)
+ return FALSE;
+ for (i = 0; i < xremotes->len; i++) {
+ XdgAppRemote *xremote = g_ptr_array_index (xremotes, i);
+ g_autoptr(GsApp) app = NULL;
+ app = gs_app_new (xdg_app_remote_get_name (xremote));
+ gs_app_set_management_plugin (app, "XgdApp");
+ gs_app_set_kind (app, GS_APP_KIND_SOURCE);
+ gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+ gs_app_set_name (app,
+ GS_APP_QUALITY_LOWEST,
+ xdg_app_remote_get_name (xremote));
+ gs_app_set_summary (app,
+ GS_APP_QUALITY_LOWEST,
+ xdg_app_remote_get_title (xremote));
+ gs_app_set_url (app,
+ AS_URL_KIND_HOMEPAGE,
+ xdg_app_remote_get_url (xremote));
+ gs_plugin_add_app (list, app);
+ }
+ return TRUE;
+}
+
+/**
+ * gs_plugin_add_updates:
+ */
+gboolean
+gs_plugin_add_updates (GsPlugin *plugin,
+ GList **list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ guint i;
+ g_autoptr(GPtrArray) xrefs = NULL;
+
+ /* ensure we can set up the repo */
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ /* get all the installed apps (no network I/O) */
+ xrefs = xdg_app_installation_list_installed_refs (plugin->priv->installation,
+ cancellable,
+ error);
+ if (xrefs == NULL)
+ return FALSE;
+ for (i = 0; i < xrefs->len; i++) {
+ XdgAppInstalledRef *xref = g_ptr_array_index (xrefs, i);
+ const gchar *commit;
+ const gchar *latest_commit;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GError) error_local = NULL;
+
+ /* check the application has already been downloaded */
+ commit = xdg_app_ref_get_commit (XDG_APP_REF (xref));
+ latest_commit = xdg_app_installed_ref_get_latest_commit (xref);
+ if (g_strcmp0 (commit, latest_commit) == 0) {
+ g_debug ("no downloaded update for %s",
+ xdg_app_ref_get_name (XDG_APP_REF (xref)));
+ continue;
+ }
+
+ /* we have an update to show */
+ g_debug ("%s has a downloaded update %s->%s",
+ xdg_app_ref_get_name (XDG_APP_REF (xref)),
+ commit, latest_commit);
+ app = gs_plugin_xdg_app_create_installed (plugin, xref, &error_local);
+ if (app == NULL) {
+ g_warning ("failed to add xdg-app: %s", error_local->message);
+ continue;
+ }
+ if (gs_app_get_state (app) == AS_APP_STATE_INSTALLED)
+ gs_app_set_state (app, AS_APP_STATE_UNKNOWN);
+ gs_app_set_state (app, AS_APP_STATE_UPDATABLE_LIVE);
+ gs_plugin_add_app (list, app);
+ }
+
+ return TRUE;
+}
+
+/**
+ * gs_plugin_refresh:
+ */
+gboolean
+gs_plugin_refresh (GsPlugin *plugin,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginHelper helper;
+ guint i;
+ gboolean ret;
+ g_autoptr(GPtrArray) xrefs = NULL;
+ g_autoptr(GPtrArray) xremotes = NULL;
+
+ /* not us */
+ if ((flags & GS_PLUGIN_REFRESH_FLAGS_UPDATES) == 0)
+ return TRUE;
+
+ /* ensure we can set up the repo */
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ /* update AppStream metadata */
+ xremotes = xdg_app_installation_list_remotes (plugin->priv->installation,
+ cancellable,
+ error);
+ if (xremotes == NULL)
+ return FALSE;
+ for (i = 0; i < xremotes->len; i++) {
+ g_autoptr(GError) error_local = NULL;
+ XdgAppRemote *xremote = g_ptr_array_index (xremotes, i);
+
+ ret = xdg_app_installation_update_appdata_sync (plugin->priv->installation,
+ xdg_app_remote_get_name (xremote),
+ NULL, /* arch */
+ NULL, /* out_changed */
+ cancellable,
+ &error_local);
+ if (!ret) {
+ if (g_error_matches (error_local,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED)) {
+ g_debug ("Failed to get AppStream metadata: %s",
+ error_local->message);
+ continue;
+ }
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "Failed to get AppStream metadata: %s",
+ error_local->message);
+ return FALSE;
+ }
+ }
+
+ /* use helper: FIXME: new()&ref? */
+ helper.plugin = plugin;
+
+ /* get all the updates available from all remotes */
+ xrefs = xdg_app_installation_list_installed_refs_for_update (plugin->priv->installation,
+ cancellable,
+ error);
+ if (xrefs == NULL)
+ return FALSE;
+ for (i = 0; i < xrefs->len; i++) {
+ XdgAppInstalledRef *xref = g_ptr_array_index (xrefs, i);
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(XdgAppInstalledRef) xref2 = NULL;
+
+ /* try to create a GsApp so we can do progress reporting */
+ app = gs_plugin_xdg_app_create_installed (plugin, xref, NULL);
+ helper.app = app;
+
+ /* fetch but do not deploy */
+ g_debug ("pulling update for %s",
+ xdg_app_ref_get_name (XDG_APP_REF (xref)));
+ xref2 = xdg_app_installation_update (plugin->priv->installation,
+ XDG_APP_UPDATE_FLAGS_NO_DEPLOY,
+ xdg_app_ref_get_kind (XDG_APP_REF (xref)),
+ xdg_app_ref_get_name (XDG_APP_REF (xref)),
+ xdg_app_ref_get_arch (XDG_APP_REF (xref)),
+ xdg_app_ref_get_branch (XDG_APP_REF (xref)),
+ gs_plugin_xdg_app_progress_cb, &helper,
+ cancellable, error);
+ if (xref2 == NULL)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gs_plugin_refine_item_origin:
+ */
+static gboolean
+gs_plugin_refine_item_origin (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *origin;
+ guint i;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(GPtrArray) xremotes = NULL;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* already set */
+ origin = gs_app_get_origin_ui (app);
+ if (origin != NULL)
+ return TRUE;
+
+ /* ensure we can set up the repo */
+ ptask = as_profile_start_literal (plugin->profile, "xdg-app::refine-origin");
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ /* find list of remotes */
+ xremotes = xdg_app_installation_list_remotes (plugin->priv->installation,
+ cancellable,
+ error);
+ if (xremotes == NULL)
+ return FALSE;
+ for (i = 0; i < xremotes->len; i++) {
+ XdgAppRemote *xremote = g_ptr_array_index (xremotes, i);
+ if (g_strcmp0 (gs_app_get_origin (app),
+ xdg_app_remote_get_name (xremote)) == 0) {
+ gs_app_set_origin_ui (app, xdg_app_remote_get_title (xremote));
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * gs_plugin_refine_item_size:
+ */
+static gboolean
+gs_plugin_refine_item_size (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *commit;
+ gboolean ret;
+ guint64 download_size;
+ guint64 installed_size;
+ g_autoptr(GError) error_local = NULL;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ commit = gs_app_get_metadata_item (app, "XgdApp::commit");
+ if (commit == NULL)
+ return TRUE;
+ ptask = as_profile_start_literal (plugin->profile, "xdg-app::refine-size");
+ ret = xdg_app_installation_fetch_remote_size_sync (plugin->priv->installation,
+ gs_app_get_origin (app),
+ commit,
+ &download_size,
+ &installed_size,
+ cancellable, &error_local);
+ if (!ret) {
+ g_warning ("libxdgapp failed to return application size: %s",
+ error_local->message);
+ installed_size = GS_APP_SIZE_MISSING;
+ }
+ gs_app_set_size (app, installed_size);
+
+ return TRUE;
+}
+
+/**
+ * gs_plugin_refine_item_action:
+ */
+static gboolean
+gs_plugin_refine_item_action (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ guint i;
+ g_autoptr(GPtrArray) xrefs = NULL;
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* can already handle install/remove */
+ if (gs_app_get_management_plugin (app) != NULL)
+ return TRUE;
+
+ /* get apps and runtimes */
+ ptask = as_profile_start_literal (plugin->profile, "xdg-app::refine-action");
+ xrefs = xdg_app_installation_list_installed_refs (plugin->priv->installation,
+ cancellable, error);
+ if (xrefs == NULL)
+ return FALSE;
+ for (i = 0; i < xrefs->len; i++) {
+ g_autofree gchar *id = NULL;
+ XdgAppInstalledRef *xref = g_ptr_array_index (xrefs, i);
+ if (xdg_app_ref_get_kind (XDG_APP_REF(xref)) != XDG_APP_REF_KIND_APP)
+ continue;
+ id = g_strdup_printf ("%s.desktop",
+ xdg_app_ref_get_name (XDG_APP_REF(xref)));
+ if (g_strcmp0 (id, gs_app_get_id (app)) != 0)
+ continue;
+
+ /* 'claim' this application for our own */
+ g_debug ("claiming %s for xdg-app", gs_app_get_id (app));
+ gs_plugin_xdg_app_set_metadata (app, xref);
+ if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN)
+ gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+ }
+
+ return TRUE;
+}
+
+/**
+ * gs_plugin_refine_item:
+ */
+static gboolean
+gs_plugin_refine_item (GsPlugin *plugin,
+ GsApp *app,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(AsProfileTask) ptask = NULL;
+
+ /* profile */
+ ptask = as_profile_start (plugin->profile,
+ "xdg-app::refine{%s}",
+ gs_app_get_id (app));
+
+ /* check if this desktop ID can be handled by the plugin */
+ if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SETUP_ACTION) {
+ if (!gs_plugin_refine_item_action (plugin, app, cancellable, error))
+ return FALSE;
+ }
+
+ /* only process this app if was created by this plugin */
+ if (g_strcmp0 (gs_app_get_management_plugin (app), "XgdApp") != 0)
+ return TRUE;
+
+ /* size */
+ if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SIZE) {
+ if (!gs_plugin_refine_item_size (plugin, app, cancellable, error))
+ return FALSE;
+ }
+
+ /* origin */
+ if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ORIGIN) {
+ if (!gs_plugin_refine_item_origin (plugin, app, cancellable, error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gs_plugin_refine:
+ */
+gboolean
+gs_plugin_refine (GsPlugin *plugin,
+ GList **list,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GList *l;
+ GsApp *app;
+
+ /* ensure we can set up the repo */
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ for (l = *list; l != NULL; l = l->next) {
+ app = GS_APP (l->data);
+ if (!gs_plugin_refine_item (plugin, app, flags, cancellable, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * gs_plugin_launch:
+ */
+gboolean
+gs_plugin_launch (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *branch = NULL;
+
+ /* only process this app if was created by this plugin */
+ if (g_strcmp0 (gs_app_get_management_plugin (app), "XgdApp") != 0)
+ return TRUE;
+
+ /* ensure we can set up the repo */
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ branch = gs_app_get_metadata_item (app, "XgdApp::branch");
+ if (branch == NULL)
+ branch = "master";
+ return xdg_app_installation_launch (plugin->priv->installation,
+ gs_app_get_metadata_item (app, "XgdApp::name"),
+ NULL,
+ branch,
+ NULL,
+ cancellable,
+ error);
+}
+
+/**
+ * gs_plugin_app_remove:
+ */
+gboolean
+gs_plugin_app_remove (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginHelper helper;
+
+ /* only process this app if was created by this plugin */
+ if (g_strcmp0 (gs_app_get_management_plugin (app), "XgdApp") != 0)
+ return TRUE;
+
+ /* ensure we can set up the repo */
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ /* use helper: FIXME: new()&ref? */
+ helper.app = app;
+ helper.plugin = plugin;
+
+ /* remove */
+ gs_app_set_state (app, AS_APP_STATE_REMOVING);
+ return xdg_app_installation_uninstall (plugin->priv->installation,
+ XDG_APP_REF_KIND_APP,
+ gs_app_get_metadata_item (app, "XgdApp::name"),
+ gs_app_get_metadata_item (app, "XgdApp::arch"),
+ gs_app_get_metadata_item (app, "XgdApp::branch"),
+ gs_plugin_xdg_app_progress_cb, &helper,
+ cancellable, error);
+}
+
+/**
+ * gs_plugin_app_install:
+ */
+gboolean
+gs_plugin_app_install (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginHelper helper;
+ g_autoptr(XdgAppInstalledRef) xref = NULL;
+
+ /* only process this app if was created by this plugin */
+ if (g_strcmp0 (gs_app_get_management_plugin (app), "XgdApp") != 0)
+ return TRUE;
+
+ /* ensure we can set up the repo */
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ /* use helper: FIXME: new()&ref? */
+ helper.app = app;
+ helper.plugin = plugin;
+
+ /* install */
+ gs_app_set_state (app, AS_APP_STATE_INSTALLING);
+ xref = xdg_app_installation_install (plugin->priv->installation,
+ gs_app_get_origin (app),
+ XDG_APP_REF_KIND_APP,
+ gs_app_get_metadata_item (app, "XgdApp::name"),
+ gs_app_get_metadata_item (app, "XgdApp::arch"),
+ gs_app_get_metadata_item (app, "XgdApp::branch"),
+ gs_plugin_xdg_app_progress_cb, &helper,
+ cancellable, error);
+ return xref != NULL;
+}
+
+/**
+ * gs_plugin_app_update:
+ *
+ * This is only called when updating device firmware live.
+ */
+gboolean
+gs_plugin_app_update (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginHelper helper;
+ XdgAppRefKind kind = XDG_APP_REF_KIND_APP;
+ g_autoptr(XdgAppInstalledRef) xref = NULL;
+
+ /* only process this app if was created by this plugin */
+ if (g_strcmp0 (gs_app_get_management_plugin (app), "XgdApp") != 0)
+ return TRUE;
+
+ /* ensure we can set up the repo */
+ if (!gs_plugin_ensure_installation (plugin, cancellable, error))
+ return FALSE;
+
+ /* use helper: FIXME: new()&ref? */
+ helper.app = app;
+ helper.plugin = plugin;
+
+ /* special case */
+ if (g_strcmp0 (gs_app_get_metadata_item (app, "XgdApp::type"), "runtime") == 0)
+ kind = XDG_APP_REF_KIND_RUNTIME;
+
+ /* install */
+ gs_app_set_state (app, AS_APP_STATE_INSTALLING);
+ xref = xdg_app_installation_update (plugin->priv->installation,
+ XDG_APP_UPDATE_FLAGS_NONE,
+ kind,
+ gs_app_get_metadata_item (app, "XgdApp::name"),
+ gs_app_get_metadata_item (app, "XgdApp::arch"),
+ gs_app_get_metadata_item (app, "XgdApp::branch"),
+ gs_plugin_xdg_app_progress_cb, &helper,
+ cancellable, error);
+ return xref != NULL;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]