[gnome-software/wip/hughsie/symlinks: 1/2] Use a symlink cache for the flatpak AppStream support
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/hughsie/symlinks: 1/2] Use a symlink cache for the flatpak AppStream support
- Date: Wed, 8 Jun 2016 09:37:12 +0000 (UTC)
commit 29ace513def5c8f5f618897274eb786a3759ff76
Author: Richard Hughes <richard hughsie com>
Date: Tue Jun 7 17:57:29 2016 +0100
Use a symlink cache for the flatpak AppStream support
The idea is to encode the scope and user-specified origin in the filename as
flatpak remotes have metadata with the filename `appstream.xml.gz` that have
origin harcoded to 'flatpak'. This requires the corresponding appstream-glib
functionality to work.
The gnome-software process will keep the symlink cache up to date. I'm using
the AppStream-specified ~/.local/share/app-info/xmls at the moment, but if we
decide that the data is actually gnome-software specific then it can move.
src/plugins/Makefile.am | 4 +
src/plugins/gs-appstream.c | 8 +-
src/plugins/gs-flatpak-symlinks.c | 239 +++++++++++++++++++++++++++++++++++++
src/plugins/gs-flatpak-symlinks.h | 36 ++++++
src/plugins/gs-flatpak.c | 11 ++
src/plugins/gs-plugin-appstream.c | 2 -
6 files changed, 296 insertions(+), 4 deletions(-)
---
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index c5389c2..c551f61 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -168,6 +168,8 @@ libgs_plugin_flatpak_system_la_SOURCES = \
gs-appstream.h \
gs-flatpak.c \
gs-flatpak.h \
+ gs-flatpak-symlinks.c \
+ gs-flatpak-symlinks.h \
gs-plugin-flatpak-system.c
libgs_plugin_flatpak_system_la_LIBADD = $(GS_PLUGIN_LIBS) $(FLATPAK_LIBS)
libgs_plugin_flatpak_system_la_LDFLAGS = -module -avoid-version
@@ -178,6 +180,8 @@ libgs_plugin_flatpak_user_la_SOURCES = \
gs-appstream.h \
gs-flatpak.c \
gs-flatpak.h \
+ gs-flatpak-symlinks.c \
+ gs-flatpak-symlinks.h \
gs-plugin-flatpak-user.c
libgs_plugin_flatpak_user_la_LIBADD = $(GS_PLUGIN_LIBS) $(FLATPAK_LIBS)
libgs_plugin_flatpak_user_la_LDFLAGS = -module -avoid-version
diff --git a/src/plugins/gs-appstream.c b/src/plugins/gs-appstream.c
index 08794b4..ffbfd7f 100644
--- a/src/plugins/gs-appstream.c
+++ b/src/plugins/gs-appstream.c
@@ -535,8 +535,12 @@ gs_appstream_refine_app (GsPlugin *plugin,
/* set origin */
if (as_app_get_origin (item) != NULL &&
- gs_app_get_origin (app) == NULL) {
- gs_app_set_origin (app, as_app_get_origin (item));
+ gs_app_get_origin (app) == NULL ) {
+ tmp = as_app_get_origin (item);
+ if (g_str_has_prefix (tmp, "flatpak:"))
+ gs_app_set_origin (app, tmp + 8);
+ if (g_str_has_prefix (tmp, "user-flatpak:"))
+ gs_app_set_origin (app, tmp + 13);
}
/* set description */
diff --git a/src/plugins/gs-flatpak-symlinks.c b/src/plugins/gs-flatpak-symlinks.c
new file mode 100644
index 0000000..08ec3db
--- /dev/null
+++ b/src/plugins/gs-flatpak-symlinks.c
@@ -0,0 +1,239 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 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.
+ */
+
+#include <config.h>
+
+#include <flatpak.h>
+#include <string.h>
+
+#include "gs-flatpak-symlinks.h"
+
+static gboolean
+gs_flatpak_symlinks_remote_valid (FlatpakRemote *xremote)
+{
+ if (xremote == NULL)
+ return FALSE;
+ if (flatpak_remote_get_disabled (xremote))
+ return FALSE;
+ if (flatpak_remote_get_noenumerate (xremote))
+ return FALSE;
+ return TRUE;
+}
+
+/* encode the symlink name with ${scope}:${name}[.xml.gz] */
+static gboolean
+gs_flatpak_symlinks_check_exist (FlatpakRemote *xremote,
+ const gchar *cache_dir,
+ const gchar *prefix,
+ const gchar *kind,
+ GError **error)
+{
+ g_autofree gchar *appstream_dir_fn = NULL;
+ g_autofree gchar *flatpak_remote_fn = NULL;
+ g_autofree gchar *subdir = NULL;
+ g_autofree gchar *symlink_source = NULL;
+ g_autofree gchar *symlink_target = NULL;
+ g_autofree gchar *xml_dir = NULL;
+ g_autoptr(GFile) appstream_dir = NULL;
+
+ /* get the AppStream data location */
+ appstream_dir = flatpak_remote_get_appstream_dir (xremote, NULL);
+ if (appstream_dir == NULL) {
+ g_debug ("no appstream dir for %s, skipping",
+ flatpak_remote_get_name (xremote));
+ return TRUE;
+ }
+
+ /* ensure all the remotes have an XML symlink */
+ appstream_dir_fn = g_file_get_path (appstream_dir);
+ subdir = g_build_filename (cache_dir, kind, NULL);
+ if (g_strcmp0 (kind, "xmls") == 0) {
+ flatpak_remote_fn = g_strdup_printf ("%s:%s.xml.gz",
+ prefix,
+ flatpak_remote_get_name (xremote));
+ symlink_target = g_build_filename (appstream_dir_fn,
+ "appstream.xml.gz",
+ NULL);
+ } else {
+ flatpak_remote_fn = g_strdup_printf ("%s:%s",
+ prefix,
+ flatpak_remote_get_name (xremote));
+ symlink_target = g_build_filename (appstream_dir_fn,
+ "icons",
+ NULL);
+ }
+ if (!g_file_test (symlink_target, G_FILE_TEST_EXISTS)) {
+ g_debug ("remote %s has no %s, skipping",
+ flatpak_remote_get_name (xremote),
+ symlink_target);
+ return TRUE;
+ }
+ symlink_source = g_build_filename (subdir,
+ flatpak_remote_fn,
+ NULL);
+ if (!gs_mkdir_parent (symlink_source, error))
+ return FALSE;
+
+ /* check XML symbolic link is correct */
+ if (g_file_test (symlink_source, G_FILE_TEST_EXISTS)) {
+ g_autofree gchar *symlink_target_actual = NULL;
+
+ /* same */
+ symlink_target_actual = g_file_read_link (symlink_source, NULL);
+ if (g_strcmp0 (symlink_target_actual, symlink_target) == 0) {
+ g_debug ("symlink %s already points to %s",
+ symlink_source, symlink_target);
+ return TRUE;
+ }
+ g_warning ("symlink incorrect expected %s target to "
+ "be %s, got %s, deleting",
+ symlink_source,
+ symlink_target,
+ symlink_target_actual);
+ if (!gs_utils_unlink (symlink_target_actual, error))
+ return FALSE;
+ }
+
+ /* create it if required */
+ if (!g_file_test (symlink_source, G_FILE_TEST_EXISTS)) {
+ g_debug ("creating missing symbolic link from %s to %s",
+ symlink_source, symlink_target);
+ if (!gs_utils_symlink (symlink_target, symlink_source, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* encode the symlink name with ${scope}:${name}, i.e. the origin */
+static gboolean
+gs_flatpak_symlinks_check_valid (FlatpakInstallation *installation,
+ const gchar *cache_dir,
+ const gchar *prefix,
+ const gchar *kind,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *tmp;
+ g_autofree gchar *subdir = NULL;
+ g_autoptr(GDir) dir = NULL;
+
+ subdir = g_build_filename (cache_dir, kind, NULL);
+ if (!g_file_test (subdir, G_FILE_TEST_EXISTS))
+ return TRUE;
+ dir = g_dir_open (subdir, 0, error);
+ if (dir == NULL)
+ return FALSE;
+ while ((tmp = g_dir_read_name (dir)) != NULL) {
+ gchar *str;
+ g_autofree gchar *fn = NULL;
+ g_autofree gchar *origin = NULL;
+ g_autofree gchar *prefix_colon = g_strdup_printf ("%s:", prefix);
+ g_autoptr(FlatpakRemote) xremote = NULL;
+
+ if (!g_str_has_prefix (tmp, prefix_colon))
+ continue;
+ if (!g_file_test (tmp, G_FILE_TEST_IS_SYMLINK))
+ continue;
+
+ /* can we find a valid remote for this file */
+ origin = g_strdup (tmp + strlen (prefix_colon));
+ str = g_strrstr (origin, ".xml.gz");
+ if (str != NULL)
+ *str = '\0';
+ xremote = flatpak_installation_get_remote_by_name (installation,
+ origin,
+ cancellable,
+ NULL);
+ if (gs_flatpak_symlinks_remote_valid (xremote)) {
+ g_debug ("%s remote symlink is valid", origin);
+ continue;
+ }
+ fn = g_build_filename (subdir, tmp, NULL);
+ g_debug ("deleting %s symlink as no longer valid", fn);
+ if (!gs_utils_unlink (fn, error))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+gboolean
+gs_flatpak_symlinks_rebuild (FlatpakInstallation *installation,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *prefix = "flatpak";
+ guint i;
+ g_autofree gchar *cache_dir = NULL;
+ g_autoptr(GPtrArray) xremotes = NULL;
+
+ /* use the correct symlink target */
+ cache_dir = g_build_filename (g_get_user_data_dir (),
+ "app-info",
+ NULL);
+ if (flatpak_installation_get_is_user (installation))
+ prefix = "user-flatpak";
+
+ /* go through each remote checking the symlink is in place */
+ xremotes = flatpak_installation_list_remotes (installation,
+ cancellable,
+ error);
+ if (xremotes == NULL)
+ return FALSE;
+ for (i = 0; i < xremotes->len; i++) {
+ FlatpakRemote *xremote = g_ptr_array_index (xremotes, i);
+ if (!gs_flatpak_symlinks_remote_valid (xremote))
+ continue;
+ g_debug ("found remote %s:%s",
+ prefix,
+ flatpak_remote_get_name (xremote));
+ if (!gs_flatpak_symlinks_check_exist (xremote,
+ cache_dir,
+ prefix,
+ "xmls",
+ error))
+ return FALSE;
+ if (!gs_flatpak_symlinks_check_exist (xremote,
+ cache_dir,
+ prefix,
+ "icons",
+ error))
+ return FALSE;
+ }
+
+ /* go through each symlink and check the remote still valid */
+ if (!gs_flatpak_symlinks_check_valid (installation,
+ cache_dir,
+ prefix,
+ "xmls",
+ cancellable,
+ error))
+ return FALSE;
+ if (!gs_flatpak_symlinks_check_valid (installation,
+ cache_dir,
+ prefix,
+ "icons",
+ cancellable,
+ error))
+ return FALSE;
+
+ /* success */
+ return TRUE;
+}
diff --git a/src/plugins/gs-flatpak-symlinks.h b/src/plugins/gs-flatpak-symlinks.h
new file mode 100644
index 0000000..aeda415
--- /dev/null
+++ b/src/plugins/gs-flatpak-symlinks.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef __GS_FLATPAK_SYMLINKS_H
+#define __GS_FLATPAK_SYMLINKS_H
+
+#include <gnome-software.h>
+
+G_BEGIN_DECLS
+
+gboolean gs_flatpak_symlinks_rebuild (FlatpakInstallation *installation,
+ GCancellable *cancellable,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GS_FLATPAK_SYMLINKS_H */
+
diff --git a/src/plugins/gs-flatpak.c b/src/plugins/gs-flatpak.c
index 188dc9c..61b845c 100644
--- a/src/plugins/gs-flatpak.c
+++ b/src/plugins/gs-flatpak.c
@@ -33,6 +33,7 @@
#include "gs-appstream.h"
#include "gs-flatpak.h"
+#include "gs-flatpak-symlinks.h"
struct _GsFlatpak {
GObject parent_instance;
@@ -51,7 +52,13 @@ gs_plugin_flatpak_changed_cb (GFileMonitor *monitor,
GFileMonitorEvent event_type,
GsFlatpak *self)
{
+ g_autoptr(GError) error = NULL;
+
gs_plugin_updates_changed (self->plugin);
+
+ /* ensure the AppStream symlink cache is up to date */
+ if (!gs_flatpak_symlinks_rebuild (self->installation, NULL, &error))
+ g_warning ("failed to check symlinks: %s", error->message);
}
gboolean
@@ -93,6 +100,10 @@ gs_flatpak_setup (GsFlatpak *self, GCancellable *cancellable, GError **error)
g_signal_connect (self->monitor, "changed",
G_CALLBACK (gs_plugin_flatpak_changed_cb), self);
+ /* ensure the AppStream symlink cache is up to date */
+ if (!gs_flatpak_symlinks_rebuild (self->installation, cancellable, error))
+ return FALSE;
+
/* success */
return TRUE;
}
diff --git a/src/plugins/gs-plugin-appstream.c b/src/plugins/gs-plugin-appstream.c
index dc63a93..3c9eaf7 100644
--- a/src/plugins/gs-plugin-appstream.c
+++ b/src/plugins/gs-plugin-appstream.c
@@ -153,8 +153,6 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
AS_STORE_LOAD_FLAG_APP_INFO_USER |
AS_STORE_LOAD_FLAG_APPDATA |
AS_STORE_LOAD_FLAG_DESKTOP |
- AS_STORE_LOAD_FLAG_FLATPAK_USER |
- AS_STORE_LOAD_FLAG_FLATPAK_SYSTEM |
AS_STORE_LOAD_FLAG_APP_INSTALL,
NULL,
error);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]