[gnome-software] snap: Expose snap channels as app alternates
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] snap: Expose snap channels as app alternates
- Date: Wed, 2 Oct 2019 14:09:58 +0000 (UTC)
commit b8b35b97d059047f42ad07f80917a1c140be90c4
Author: Robert Ancell <robert ancell canonical com>
Date: Mon Oct 1 17:04:57 2018 +1300
snap: Expose snap channels as app alternates
plugins/snap/gs-plugin-snap.c | 193 +++++++++++++++++++++++++++++++++++++-----
1 file changed, 173 insertions(+), 20 deletions(-)
---
diff --git a/plugins/snap/gs-plugin-snap.c b/plugins/snap/gs-plugin-snap.c
index 57ca8e77..db9a1de1 100644
--- a/plugins/snap/gs-plugin-snap.c
+++ b/plugins/snap/gs-plugin-snap.c
@@ -21,6 +21,27 @@ struct GsPluginData {
GHashTable *store_snaps;
};
+typedef struct {
+ SnapdSnap *snap;
+ gboolean full_details;
+} CacheEntry;
+
+static CacheEntry *
+cache_entry_new (SnapdSnap *snap, gboolean full_details)
+{
+ CacheEntry *entry = g_slice_new (CacheEntry);
+ entry->snap = g_object_ref (snap);
+ entry->full_details = full_details;
+ return entry;
+}
+
+static void
+cache_entry_free (CacheEntry *entry)
+{
+ g_object_unref (entry->snap);
+ g_slice_free (CacheEntry, entry);
+}
+
static SnapdClient *
get_client (GsPlugin *plugin, GError **error)
{
@@ -55,7 +76,7 @@ gs_plugin_initialize (GsPlugin *plugin)
}
priv->store_snaps = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, (GDestroyNotify) g_object_unref);
+ g_free, (GDestroyNotify) cache_entry_free);
gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "desktop-categories");
gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_BETTER_THAN, "packagekit");
@@ -174,21 +195,24 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
}
static SnapdSnap *
-store_snap_cache_lookup (GsPlugin *plugin, const gchar *name)
+store_snap_cache_lookup (GsPlugin *plugin, const gchar *name, gboolean need_details)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
+ CacheEntry *entry;
g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->store_snaps_lock);
- SnapdSnap *snap;
- snap = g_hash_table_lookup (priv->store_snaps, name);
- if (snap == NULL)
+ entry = g_hash_table_lookup (priv->store_snaps, name);
+ if (entry == NULL)
return NULL;
- return g_object_ref (snap);
+ if (need_details && !entry->full_details)
+ return NULL;
+
+ return g_object_ref (entry->snap);
}
static void
-store_snap_cache_update (GsPlugin *plugin, GPtrArray *snaps)
+store_snap_cache_update (GsPlugin *plugin, GPtrArray *snaps, gboolean full_details)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->store_snaps_lock);
@@ -196,7 +220,7 @@ store_snap_cache_update (GsPlugin *plugin, GPtrArray *snaps)
for (i = 0; i < snaps->len; i++) {
SnapdSnap *snap = snaps->pdata[i];
- g_hash_table_insert (priv->store_snaps, g_strdup (snapd_snap_get_name (snap)), g_object_ref
(snap));
+ g_hash_table_insert (priv->store_snaps, g_strdup (snapd_snap_get_name (snap)),
cache_entry_new (snap, full_details));
}
}
@@ -216,7 +240,7 @@ find_snaps (GsPlugin *plugin, SnapdFindFlags flags, const gchar *section, const
return NULL;
}
- store_snap_cache_update (plugin, snaps);
+ store_snap_cache_update (plugin, snaps, flags & SNAPD_FIND_FLAGS_MATCH_NAME);
return g_steal_pointer (&snaps);
}
@@ -529,13 +553,13 @@ gs_plugin_add_search (GsPlugin *plugin,
}
static SnapdSnap *
-get_store_snap (GsPlugin *plugin, const gchar *name, GCancellable *cancellable, GError **error)
+get_store_snap (GsPlugin *plugin, const gchar *name, gboolean need_details, GCancellable *cancellable,
GError **error)
{
SnapdSnap *snap = NULL;
g_autoptr(GPtrArray) snaps = NULL;
/* use cached version if available */
- snap = store_snap_cache_lookup (plugin, name);
+ snap = store_snap_cache_lookup (plugin, name, need_details);
if (snap != NULL)
return g_object_ref (snap);
@@ -546,6 +570,94 @@ get_store_snap (GsPlugin *plugin, const gchar *name, GCancellable *cancellable,
return g_object_ref (g_ptr_array_index (snaps, 0));
}
+static int
+track_value (const gchar *track, GStrv tracks)
+{
+ int r = 0;
+ while (tracks[r] != NULL && strcmp (track, tracks[r]) != 0)
+ r++;
+ return r;
+}
+
+static int
+risk_value (const gchar *risk)
+{
+ if (strcmp (risk, "stable") == 0)
+ return 0;
+ else if (strcmp (risk, "candidate") == 0)
+ return 1;
+ else if (strcmp (risk, "beta") == 0)
+ return 2;
+ else if (strcmp (risk, "edge") == 0)
+ return 3;
+ else
+ return 4;
+}
+
+static int
+compare_channel (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ SnapdChannel *channel_a = *(SnapdChannel **)a, *channel_b = *(SnapdChannel **)b;
+ GStrv tracks = user_data;
+ int r;
+
+ r = track_value (snapd_channel_get_track (channel_a), tracks) - track_value (snapd_channel_get_track
(channel_b), tracks);
+ if (r != 0)
+ return r;
+
+ r = g_strcmp0 (snapd_channel_get_risk (channel_a), snapd_channel_get_risk (channel_b));
+ if (r != 0) {
+ int r2;
+
+ r2 = risk_value (snapd_channel_get_risk (channel_a)) - risk_value (snapd_channel_get_risk
(channel_b));
+ if (r2 != 0)
+ return r2;
+ else
+ return r;
+ }
+
+ return g_strcmp0 (snapd_channel_get_branch (channel_a), snapd_channel_get_branch (channel_b));
+}
+
+gboolean
+gs_plugin_add_alternates (GsPlugin *plugin,
+ GsApp *app,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(SnapdSnap) snap = NULL;
+ GStrv tracks;
+ GPtrArray *channels;
+ g_autoptr(GPtrArray) sorted_channels = NULL;
+
+ snap = get_store_snap (plugin, gs_app_get_metadata_item (app, "snap::name"), TRUE, cancellable, NULL);
+ if (snap == NULL) {
+ g_warning ("Failed to get store snap %s\n", gs_app_get_metadata_item (app, "snap::name"));
+ return TRUE;
+ }
+
+ tracks = snapd_snap_get_tracks (snap);
+ channels = snapd_snap_get_channels (snap);
+ sorted_channels = g_ptr_array_new ();
+ for (guint i = 0; i < channels->len; i++) {
+ SnapdChannel *channel = g_ptr_array_index (channels, i);
+ g_ptr_array_add (sorted_channels, channel);
+ }
+ g_ptr_array_sort_with_data (sorted_channels, compare_channel, tracks);
+
+ for (guint i = 0; i < sorted_channels->len; i++) {
+ SnapdChannel *channel = g_ptr_array_index (sorted_channels, i);
+ g_autoptr(GsApp) a = gs_app_new (NULL);
+ gs_app_set_bundle_kind (a, AS_BUNDLE_KIND_SNAP);
+ gs_app_set_metadata (a, "snap::name", gs_app_get_metadata_item (app, "snap::name"));
+ gs_app_set_branch (a, snapd_channel_get_name (channel));
+ gs_app_list_add (list, a);
+ }
+
+ return TRUE;
+}
+
static gboolean
load_snap_icon (GsApp *app, SnapdClient *client, SnapdSnap *snap, GCancellable *cancellable)
{
@@ -690,7 +802,7 @@ load_icon (GsPlugin *plugin, SnapdClient *client, GsApp *app, const gchar *id, S
}
if (store_snap == NULL)
- store_snap = get_store_snap (plugin, gs_app_get_metadata_item (app, "snap::name"),
cancellable, NULL);
+ store_snap = get_store_snap (plugin, gs_app_get_metadata_item (app, "snap::name"), FALSE,
cancellable, NULL);
if (store_snap != NULL)
return load_store_icon (app, store_snap);
@@ -781,7 +893,7 @@ gs_plugin_refine_app (GsPlugin *plugin,
{
GsPluginData *priv = gs_plugin_get_data (plugin);
g_autoptr(SnapdClient) client = NULL;
- const gchar *name;
+ const gchar *snap_name, *channel, *name;
g_autoptr(SnapdSnap) local_snap = NULL;
g_autoptr(SnapdSnap) store_snap = NULL;
SnapdSnap *snap;
@@ -796,14 +908,27 @@ gs_plugin_refine_app (GsPlugin *plugin,
if (client == NULL)
return FALSE;
+ snap_name = gs_app_get_metadata_item (app, "snap::name");
+ channel = gs_app_get_branch (app);
+
/* get information from local snaps and store */
- local_snap = snapd_client_get_snap_sync (client, gs_app_get_metadata_item (app, "snap::name"),
cancellable, NULL);
- if (local_snap == NULL || (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS) != 0)
- store_snap = get_store_snap (plugin, gs_app_get_metadata_item (app, "snap::name"),
cancellable, NULL);
+ local_snap = snapd_client_get_snap_sync (client, snap_name, cancellable, NULL);
+ if (local_snap == NULL || (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_SCREENSHOTS) != 0 || channel !=
NULL)
+ store_snap = get_store_snap (plugin, snap_name, channel != NULL, cancellable, NULL);
if (local_snap == NULL && store_snap == NULL)
return TRUE;
- if (local_snap != NULL)
+ /* Get default channel to install */
+ if (channel == NULL) {
+ if (local_snap != NULL)
+ channel = snapd_snap_get_tracking_channel (local_snap);
+ else
+ channel = snapd_snap_get_channel (store_snap);
+
+ gs_app_set_branch (app, channel);
+ }
+
+ if (local_snap != NULL && g_strcmp0 (snapd_snap_get_tracking_channel (local_snap), channel) == 0)
gs_app_set_state (app, AS_APP_STATE_INSTALLED);
else
gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
@@ -829,6 +954,16 @@ gs_plugin_refine_app (GsPlugin *plugin,
snap = local_snap != NULL ? local_snap : store_snap;
gs_app_set_version (app, snapd_snap_get_version (snap));
+ if (channel != NULL && store_snap != NULL) {
+ GPtrArray *channels = snapd_snap_get_channels (store_snap);
+ guint i;
+ for (i = 0; i < channels->len; i++) {
+ SnapdChannel *c = channels->pdata[i];
+ if (g_strcmp0 (snapd_channel_get_name (c), channel) != 0)
+ gs_app_set_version (app, snapd_channel_get_version (c));
+ }
+ }
+
switch (snapd_snap_get_snap_type (snap)) {
case SNAPD_SNAP_TYPE_APP:
gs_app_set_kind (app, AS_APP_KIND_DESKTOP);
@@ -838,7 +973,7 @@ gs_plugin_refine_app (GsPlugin *plugin,
case SNAPD_SNAP_TYPE_OS:
gs_app_set_kind (app, AS_APP_KIND_RUNTIME);
break;
- default:
+ default:
case SNAPD_SNAP_TYPE_UNKNOWN:
gs_app_set_kind (app, AS_APP_KIND_UNKNOWN);
break;
@@ -873,7 +1008,7 @@ gs_plugin_refine_app (GsPlugin *plugin,
/* load icon if requested */
if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON && gs_app_get_pixbuf (app) == NULL)
- load_icon (plugin, client, app, gs_app_get_metadata_item (app, "snap::name"), local_snap,
store_snap, cancellable);
+ load_icon (plugin, client, app, snap_name, local_snap, store_snap, cancellable);
return TRUE;
}
@@ -903,7 +1038,10 @@ gs_plugin_app_install (GsPlugin *plugin,
GError **error)
{
g_autoptr(SnapdClient) client = NULL;
+ const gchar *name, *channel;
SnapdInstallFlags flags = SNAPD_INSTALL_FLAGS_NONE;
+ gboolean result;
+ g_autoptr(GError) error_local = NULL;
/* We can only install apps we know of */
if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0)
@@ -913,15 +1051,30 @@ gs_plugin_app_install (GsPlugin *plugin,
if (client == NULL)
return FALSE;
+ name = gs_app_get_metadata_item (app, "snap::name");
+ channel = gs_app_get_branch (app);
+
gs_app_set_state (app, AS_APP_STATE_INSTALLING);
+
if (g_strcmp0 (gs_app_get_metadata_item (app, "snap::confinement"), "classic") == 0)
flags |= SNAPD_INSTALL_FLAGS_CLASSIC;
- if (!snapd_client_install2_sync (client, flags, gs_app_get_metadata_item (app, "snap::name"), NULL,
NULL, progress_cb, app, cancellable, error)) {
+ result = snapd_client_install2_sync (client, flags, name, channel, NULL, progress_cb, app,
cancellable, &error_local);
+
+ /* if already installed then just try to switch channel */
+ if (!result && g_error_matches (error_local, SNAPD_ERROR, SNAPD_ERROR_ALREADY_INSTALLED)) {
+ g_clear_error (&error_local);
+ result = snapd_client_refresh_sync (client, name, channel, progress_cb, app, cancellable,
&error_local);
+ }
+
+ if (!result) {
gs_app_set_state_recover (app);
+ g_propagate_error (error, g_steal_pointer (&error_local));
snapd_error_convert (error);
return FALSE;
}
+
gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+
return TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]