[gnome-software/wip/rancell/snapd-glib] Fist stab at using snapd-glib
- From: Robert Ancell <rancell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/rancell/snapd-glib] Fist stab at using snapd-glib
- Date: Thu, 1 Sep 2016 03:05:59 +0000 (UTC)
commit b39e2990091f2ea14bcc6a72e65bdb4f49519e6d
Author: Robert Ancell <robert ancell canonical com>
Date: Thu Sep 1 15:05:32 2016 +1200
Fist stab at using snapd-glib
configure.ac | 23 ++
src/plugins/Makefile.am | 15 +-
src/plugins/gs-plugin-snap.c | 709 ++++++++++++------------------------------
src/plugins/gs-snapd.c | 380 ----------------------
src/plugins/gs-snapd.h | 55 ----
5 files changed, 232 insertions(+), 950 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index f4dd16b..20f7c8d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -368,6 +368,28 @@ AC_ARG_ENABLE(webapps,
enable_webapps=yes)
AM_CONDITIONAL(HAVE_WEBAPPS, [test "x$enable_webapps" = "xyes"])
+# Snap
+AC_ARG_ENABLE(snap,
+ [AS_HELP_STRING([--enable-snap],
+ [enable Snap support [default=auto]])],,
+ enable_snap=maybe)
+AS_IF([test "x$enable_snap" != "xno"], [
+ PKG_CHECK_MODULES(SNAP,
+ [snapd-glib],
+ [have_snap=yes],
+ [have_snap=no])
+], [
+ have_snap=no
+])
+AS_IF([test "x$have_snap" = "xyes"], [
+ AC_DEFINE(HAVE_SNAP,1,[Build Snap support])
+], [
+ AS_IF([test "x$enable_snap" = "xyes"], [
+ AC_MSG_ERROR([Snap support requested but 'snapd-glib' was not found])
+ ])
+])
+AM_CONDITIONAL(HAVE_SNAP, test "$have_snap" != no)
+
# this refers to the gnome-software plugin API version
# this is not in any way related to a package or soname version
GS_PLUGIN_API_VERSION=11
@@ -429,4 +451,5 @@ echo "
ODRS support: ${enable_odrs}
Webapps support: ${enable_webapps}
Ubuntu Reviews support: ${enable_ubuntu_reviews}
+ Snap support: ${have_snap}
"
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index f021cae..6f23aa9 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -14,6 +14,7 @@ AM_CPPFLAGS = \
$(LIMBA_CFLAGS) \
$(OSTREE_CFLAGS) \
$(FLATPAK_CFLAGS) \
+ $(SNAP_CFLAGS) \
$(RPM_CFLAGS) \
$(OAUTH_CFLAGS) \
-DI_KNOW_THE_GNOME_SOFTWARE_API_IS_SUBJECT_TO_CHANGE \
@@ -44,7 +45,6 @@ plugin_LTLIBRARIES = \
libgs_plugin_repos.la \
libgs_plugin_fedora-tagger-usage.la \
libgs_plugin_icons.la \
- libgs_plugin_snap.la \
libgs_plugin_ubuntuone.la
if HAVE_PACKAGEKIT
@@ -102,6 +102,10 @@ if HAVE_RPM
plugin_LTLIBRARIES += libgs_plugin_rpm.la
endif
+if HAVE_SNAP
+plugin_LTLIBRARIES += libgs_plugin_snap.la
+endif
+
libgs_plugin_dummy_la_SOURCES = gs-plugin-dummy.c
libgs_plugin_dummy_la_LIBADD = $(GS_PLUGIN_LIBS)
libgs_plugin_dummy_la_LDFLAGS = -module -avoid-version
@@ -344,16 +348,15 @@ libgs_plugin_packagekit_proxy_la_LIBADD = $(GS_PLUGIN_LIBS)
libgs_plugin_packagekit_proxy_la_LDFLAGS = -module -avoid-version
libgs_plugin_packagekit_proxy_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+if HAVE_SNAP
libgs_plugin_snap_la_SOURCES = \
- gs-plugin-snap.c \
- gs-snapd.h \
- gs-snapd.c
+ gs-plugin-snap.c
libgs_plugin_snap_la_LIBADD = \
$(GS_PLUGIN_LIBS) \
- $(SOUP_LIBS) \
- $(JSON_GLIB_LIBS)
+ $(SNAP_LIBS)
libgs_plugin_snap_la_LDFLAGS = -module -avoid-version
libgs_plugin_snap_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+endif
libgs_plugin_ubuntuone_la_SOURCES = \
gs-plugin-ubuntuone.c
diff --git a/src/plugins/gs-plugin-snap.c b/src/plugins/gs-plugin-snap.c
index 87c73f5..c5136e8 100644
--- a/src/plugins/gs-plugin-snap.c
+++ b/src/plugins/gs-plugin-snap.c
@@ -21,7 +21,7 @@
#include <config.h>
-#include <json-glib/json-glib.h>
+#include <snapd-glib/snapd-glib.h>
#include <gnome-software.h>
#include "gs-snapd.h"
@@ -30,18 +30,17 @@ struct GsPluginData {
GsAuth *auth;
};
-typedef gboolean (*AppFilterFunc)(const gchar *id, JsonObject *object, gpointer data);
-
void
gs_plugin_initialize (GsPlugin *plugin)
{
GsPluginData *priv = gs_plugin_alloc_data (plugin, sizeof(GsPluginData));
- if (!gs_snapd_exists ()) {
+ // FIXME
+ /*if (!gs_snapd_exists ()) {
g_debug ("disabling '%s' as snapd not running",
gs_plugin_get_name (plugin));
gs_plugin_set_enabled (plugin, FALSE);
- }
+ }*/
priv->auth = gs_auth_new ("snapd");
gs_auth_set_provider_name (priv->auth, "Snap Store");
@@ -70,122 +69,145 @@ gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
return TRUE;
}
-static JsonParser *
-parse_result (const gchar *response, const gchar *response_type, GError **error)
-{
- g_autoptr(JsonParser) parser = NULL;
- g_autoptr(GError) error_local = NULL;
-
- if (response_type == NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "snapd returned no content type");
- return NULL;
- }
- if (g_strcmp0 (response_type, "application/json") != 0) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "snapd returned unexpected content type %s", response_type);
- return NULL;
- }
-
- parser = json_parser_new ();
- if (!json_parser_load_from_data (parser, response, -1, &error_local)) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "Unable to parse snapd response: %s",
- error_local->message);
- return NULL;
- }
- if (!JSON_NODE_HOLDS_OBJECT (json_parser_get_root (parser))) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "snapd response does is not a valid JSON object");
- return NULL;
- }
-
- return g_object_ref (parser);
-}
-
-static void
-get_macaroon (GsPlugin *plugin, gchar **macaroon, gchar ***discharges)
+static SnapdAuthData *
+get_auth (GsPlugin *plugin)
{
GsAuth *auth;
const gchar *serialized_macaroon;
g_autoptr(GVariant) macaroon_variant = NULL;
- g_autoptr (GError) error_local = NULL;
-
- *macaroon = NULL;
- *discharges = NULL;
+ const gchar *macaroon;
+ g_auto(GStrv) discharges = NULL;
auth = gs_plugin_get_auth_by_id (plugin, "snapd");
if (auth == NULL)
- return;
+ return NULL;
serialized_macaroon = gs_auth_get_metadata_item (auth, "macaroon");
if (serialized_macaroon == NULL)
- return;
+ return NULL;
macaroon_variant = g_variant_parse (G_VARIANT_TYPE ("(sas)"),
serialized_macaroon,
NULL,
NULL,
NULL);
if (macaroon_variant == NULL)
- return;
- g_variant_get (macaroon_variant, "(s^as)", macaroon, discharges);
+ return NULL;
+ g_variant_get (macaroon_variant, "(&s^as)", &macaroon, &discharges);
+
+ return snapd_auth_data_new (macaroon, discharges);
}
-static void
-refine_app (GsPlugin *plugin, GsApp *app, JsonObject *package, gboolean from_search, GCancellable
*cancellable)
+static SnapdClient *
+get_client (GsPlugin *plugin, GCancellable *cancellable, GError **error)
{
- g_autofree gchar *macaroon = NULL;
- g_auto(GStrv) discharges = NULL;
- const gchar *status, *icon_url, *launch_name = NULL;
- g_autoptr(GdkPixbuf) icon_pixbuf = NULL;
- gint64 size = -1;
+ g_autoptr(SnapdClient) client = NULL;
- get_macaroon (plugin, &macaroon, &discharges);
+ client = snapd_client_new ();
+ if (!snapd_client_connect_sync (client, cancellable, error))
+ return NULL;
+ //snapd_client_set_auth_data (client, get_auth (plugin));
- status = json_object_get_string_member (package, "status");
- if (g_strcmp0 (status, "installed") == 0 || g_strcmp0 (status, "active") == 0) {
- const gchar *update_available;
+ return g_steal_pointer (&client);
+}
- update_available = json_object_has_member (package, "update_available") ?
- json_object_get_string_member (package, "update_available") : NULL;
- if (update_available)
- gs_app_set_state (app, AS_APP_STATE_UPDATABLE);
- else {
- if (gs_app_get_state (app) == AS_APP_STATE_AVAILABLE)
- gs_app_set_state (app, AS_APP_STATE_UNKNOWN);
- gs_app_set_state (app, AS_APP_STATE_INSTALLED);
- }
- } else if (g_strcmp0 (status, "not installed") == 0 || g_strcmp0 (status, "available") == 0) {
- gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+ GsPluginData *priv = gs_plugin_get_data (plugin);
+ g_clear_object (&priv->auth);
+}
+
+gboolean
+gs_plugin_add_installed (GsPlugin *plugin,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(SnapdClient) client = NULL;
+ g_autoptr(GPtrArray) snaps = NULL;
+ guint i;
+
+ client = get_client (plugin, cancellable, error);
+ if (client == NULL)
+ return FALSE;
+ snaps = snapd_client_list_sync (client, cancellable, error);
+ if (snaps == NULL) {
+ // FIXME: Convert error?
+ return FALSE;
}
- gs_app_set_name (app, GS_APP_QUALITY_HIGHEST,
- json_object_get_string_member (package, "summary"));
- gs_app_set_summary (app, GS_APP_QUALITY_HIGHEST,
- json_object_get_string_member (package, "description"));
- gs_app_set_version (app, json_object_get_string_member (package, "version"));
- if (json_object_has_member (package, "installed-size")) {
- size = json_object_get_int_member (package, "installed-size");
- if (size > 0)
- gs_app_set_size_installed (app, (guint64) size);
+ for (i = 0; i < snaps->len; i++) {
+ SnapdSnap *snap = snaps->pdata[i];
+ g_autoptr(GsApp) app = NULL;
+
+ if (snapd_snap_get_status (snap) != SNAPD_SNAP_STATUS_ACTIVE)
+ continue;
+
+ app = gs_app_new (snapd_snap_get_name (snap));
+ gs_app_set_scope (app, AS_APP_SCOPE_SYSTEM);
+ gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_SNAP);
+ gs_app_set_management_plugin (app, "snap");
+ gs_app_set_kind (app, AS_APP_KIND_DESKTOP);
+ gs_app_add_quirk (app, AS_APP_QUIRK_NOT_REVIEWABLE);
+ gs_app_list_add (list, app);
}
- if (json_object_has_member (package, "download-size")) {
- size = json_object_get_int_member (package, "download-size");
+
+ return TRUE;
+}
+
+gboolean
+gs_plugin_add_search (GsPlugin *plugin,
+ gchar **values,
+ GsAppList *list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(SnapdClient) client = NULL;
+ g_autofree gchar *query = NULL;
+ g_autoptr(GPtrArray) snaps = NULL;
+ guint i;
+
+ client = get_client (plugin, cancellable, error);
+ if (client == NULL)
+ return FALSE;
+ query = g_strjoinv (" ", values);
+
+ snaps = snapd_client_find_sync (client, SNAPD_FIND_FLAGS_NONE, query, NULL, cancellable, error);
+ if (snaps == NULL) {
+ // FIXME: Convert error?
+ return FALSE;
+ }
+ for (i = 0; i < snaps->len; i++) {
+ SnapdSnap *snap = snaps->pdata[i];
+ gint64 size;
+ g_autoptr(GsApp) app = NULL;
+
+ app = gs_app_new (snapd_snap_get_name (snap));
+ gs_app_set_scope (app, AS_APP_SCOPE_SYSTEM);
+ gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_SNAP);
+ gs_app_set_management_plugin (app, "snap");
+ gs_app_set_kind (app, AS_APP_KIND_DESKTOP);
+ gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+ gs_app_add_quirk (app, AS_APP_QUIRK_NOT_REVIEWABLE);
+ size = snapd_snap_get_download_size (snap);
if (size > 0)
gs_app_set_size_download (app, (guint64) size);
+ gs_app_list_add (list, app);
}
- gs_app_add_quirk (app, AS_APP_QUIRK_PROVENANCE);
- icon_url = json_object_get_string_member (package, "icon");
+
+ return TRUE;
+}
+
+static gboolean
+load_icon (GsPlugin *plugin, GsApp *app, SnapdClient *client, SnapdSnap *snap, GCancellable *cancellable,
GError **error)
+{
+ const gchar *icon_url;
+ g_autoptr(GdkPixbuf) icon_pixbuf = NULL;
+
+ icon_url = snapd_snap_get_icon (snap);
if (g_str_has_prefix (icon_url, "/")) {
- g_autofree gchar *icon_response = NULL;
+ /*g_autoptr(SnapdIcon) icon = NULL;
gsize icon_response_length;
+ icon = snapd_client_get_icon_sync (
if (gs_snapd_request ("GET", icon_url, NULL,
macaroon, discharges,
NULL, NULL,
@@ -202,7 +224,7 @@ refine_app (GsPlugin *plugin, GsApp *app, JsonObject *package, gboolean from_sea
icon_pixbuf = g_object_ref (gdk_pixbuf_loader_get_pixbuf (loader));
}
else
- g_printerr ("Failed to get icon\n");
+ g_printerr ("Failed to get icon\n");*/
}
else {
g_autoptr(SoupMessage) message = NULL;
@@ -230,213 +252,9 @@ refine_app (GsPlugin *plugin, GsApp *app, JsonObject *package, gboolean from_sea
gs_app_add_icon (app, icon);
}
- if (!from_search) {
- JsonArray *apps;
-
- apps = json_object_get_array_member (package, "apps");
- if (apps && json_array_get_length (apps) > 0)
- launch_name = json_object_get_string_member (json_array_get_object_element (apps, 0),
"name");
-
- if (launch_name)
- gs_app_set_metadata (app, "snap::launch-name", launch_name);
- else
- gs_app_add_quirk (app, AS_APP_QUIRK_NOT_LAUNCHABLE);
- }
-}
-
-static gboolean
-get_apps (GsPlugin *plugin,
- const gchar *sources,
- gchar **search_terms,
- GsAppList *list,
- AppFilterFunc filter_func,
- gpointer user_data,
- GCancellable *cancellable,
- GError **error)
-{
- g_autofree gchar *macaroon = NULL;
- g_auto(GStrv) discharges = NULL;
- guint status_code;
- GPtrArray *query_fields;
- g_autoptr (GString) path = NULL;
- g_autofree gchar *reason_phrase = NULL, *response_type = NULL, *response = NULL;
- g_autoptr(JsonParser) parser = NULL;
- JsonObject *root;
- JsonArray *result;
- GList *snaps;
- GList *l;
-
- get_macaroon (plugin, &macaroon, &discharges);
-
- /* Get all the apps */
- query_fields = g_ptr_array_new_with_free_func (g_free);
- if (sources != NULL) {
- g_autofree gchar *escaped = NULL;
- escaped = soup_uri_encode (sources, NULL);
- g_ptr_array_add (query_fields, g_strdup_printf ("sources=%s", escaped));
- }
- if (search_terms != NULL && search_terms[0] != NULL) {
- g_autoptr (GString) query = NULL;
- g_autofree gchar *escaped = NULL;
- gint i;
-
- query = g_string_new ("q=");
- escaped = soup_uri_encode (search_terms[0], NULL);
- g_string_append (query, escaped);
- for (i = 1; search_terms[i] != NULL; i++) {
- g_autofree gchar *e = soup_uri_encode (search_terms[0], NULL);
- g_string_append_printf (query, "+%s", e);
- }
- g_ptr_array_add (query_fields, g_strdup (query->str));
- path = g_string_new ("/v2/find");
- }
- else
- path = g_string_new ("/v2/snaps");
- g_ptr_array_add (query_fields, NULL);
- if (query_fields->len > 1) {
- g_autofree gchar *fields = NULL;
- g_string_append (path, "?");
- fields = g_strjoinv ("&", (gchar **) query_fields->pdata);
- g_string_append (path, fields);
- }
- g_ptr_array_free (query_fields, TRUE);
- if (!gs_snapd_request ("GET", path->str, NULL,
- macaroon, discharges,
- &status_code, &reason_phrase,
- &response_type, &response, NULL,
- cancellable, error))
- return FALSE;
-
- if (status_code != SOUP_STATUS_OK) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "snapd returned status code %u: %s",
- status_code, reason_phrase);
- return FALSE;
- }
-
- parser = parse_result (response, response_type, error);
- if (parser == NULL)
- return FALSE;
-
- root = json_node_get_object (json_parser_get_root (parser));
- result = json_object_get_array_member (root, "result");
- snaps = json_array_get_elements (result);
-
- for (l = snaps; l != NULL; l = l->next) {
- JsonObject *package = json_node_get_object (l->data);
- g_autoptr(GsApp) app = NULL;
- const gchar *id;
-
- id = json_object_get_string_member (package, "name");
-
- if (filter_func != NULL && !filter_func (id, package, user_data))
- continue;
-
- /* create a unique ID for deduplication, TODO: branch? */
- app = gs_app_new (id);
- gs_app_set_scope (app, AS_APP_SCOPE_SYSTEM);
- gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_SNAP);
- gs_app_set_management_plugin (app, "snap");
- gs_app_set_kind (app, AS_APP_KIND_DESKTOP);
- gs_app_add_quirk (app, AS_APP_QUIRK_NOT_REVIEWABLE);
- refine_app (plugin, app, package, TRUE, cancellable);
- gs_app_list_add (list, app);
- }
-
- g_list_free (snaps);
-
- return TRUE;
-}
-
-static gboolean
-get_app (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error)
-{
- g_autofree gchar *macaroon = NULL;
- g_auto(GStrv) discharges = NULL;
- guint status_code;
- g_autofree gchar *path = NULL;
- g_autofree gchar *reason_phrase = NULL;
- g_autofree gchar *response = NULL;
- g_autofree gchar *response_type = NULL;
- g_autoptr(JsonParser) parser = NULL;
- JsonObject *root;
- JsonObject *result;
-
- get_macaroon (plugin, &macaroon, &discharges);
-
- path = g_strdup_printf ("/v2/snaps/%s", gs_app_get_id (app));
- if (!gs_snapd_request ("GET", path, NULL,
- macaroon, discharges,
- &status_code, &reason_phrase,
- &response_type, &response, NULL,
- cancellable, error))
- return FALSE;
-
- if (status_code == SOUP_STATUS_NOT_FOUND)
- return TRUE;
-
- if (status_code != SOUP_STATUS_OK) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "snapd returned status code %u: %s",
- status_code, reason_phrase);
- return FALSE;
- }
-
- parser = parse_result (response, response_type, error);
- if (parser == NULL)
- return FALSE;
- root = json_node_get_object (json_parser_get_root (parser));
- result = json_object_get_object_member (root, "result");
- if (result == NULL) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "snapd returned no results for %s", gs_app_get_id (app));
- return FALSE;
- }
-
- refine_app (plugin, app, result, FALSE, cancellable);
-
return TRUE;
}
-void
-gs_plugin_destroy (GsPlugin *plugin)
-{
- GsPluginData *priv = gs_plugin_get_data (plugin);
- g_clear_object (&priv->auth);
-}
-
-static gboolean
-is_active (const gchar *id, JsonObject *object, gpointer data)
-{
- const gchar *status = json_object_get_string_member (object, "status");
- return g_strcmp0 (status, "active") == 0;
-}
-
-gboolean
-gs_plugin_add_installed (GsPlugin *plugin,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
-{
- return get_apps (plugin, "local", NULL, list, is_active, NULL, cancellable, error);
-}
-
-gboolean
-gs_plugin_add_search (GsPlugin *plugin,
- gchar **values,
- GsAppList *list,
- GCancellable *cancellable,
- GError **error)
-{
- return get_apps (plugin, NULL, values, list, NULL, values, cancellable, error);
-}
-
gboolean
gs_plugin_refine_app (GsPlugin *plugin,
GsApp *app,
@@ -444,149 +262,83 @@ gs_plugin_refine_app (GsPlugin *plugin,
GCancellable *cancellable,
GError **error)
{
+ g_autoptr(SnapdClient) client = NULL;
+ g_autoptr(SnapdSnap) snap = NULL;
+ gint64 size;
+ GPtrArray *apps;
+ const gchar *launch_name = NULL;
+
/* not us */
if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0)
return TRUE;
- // Get info from snapd
- return get_app (plugin, app, cancellable, error);
-}
-
-static gboolean
-send_package_action (GsPlugin *plugin,
- GsApp *app,
- const gchar *id,
- const gchar *action,
- GCancellable *cancellable,
- GError **error)
-{
- g_autofree gchar *macaroon = NULL;
- g_auto(GStrv) discharges = NULL;
- g_autofree gchar *content = NULL, *path = NULL;
- guint status_code;
- g_autofree gchar *reason_phrase = NULL;
- g_autofree gchar *response_type = NULL;
- g_autofree gchar *response = NULL;
- g_autofree gchar *status = NULL;
- g_autoptr(JsonParser) parser = NULL;
- JsonObject *root, *result, *task, *progress;
- JsonArray *tasks;
- GList *task_list, *l;
- gint64 done, total, task_done, task_total;
- const gchar *resource_path;
- const gchar *type;
- const gchar *change_id;
-
- get_macaroon (plugin, &macaroon, &discharges);
-
- content = g_strdup_printf ("{\"action\": \"%s\"}", action);
- path = g_strdup_printf ("/v2/snaps/%s", id);
- if (!gs_snapd_request ("POST", path, content,
- macaroon, discharges,
- &status_code, &reason_phrase,
- &response_type, &response, NULL,
- cancellable, error))
+ client = get_client (plugin, cancellable, error);
+ if (client == NULL)
return FALSE;
- if (status_code == SOUP_STATUS_UNAUTHORIZED) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_AUTH_REQUIRED,
- "Requires authentication with @snapd");
+ snap = snapd_client_list_one_sync (client, gs_app_get_id (app), cancellable, error);
+ if (snap == NULL) {
+ // FIXME: Convert error?
return FALSE;
}
- if (status_code != SOUP_STATUS_ACCEPTED) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "snapd returned status code %u: %s",
- status_code, reason_phrase);
- return FALSE;
+ switch (snapd_snap_get_status (snap)) {
+ default:
+ case SNAPD_SNAP_STATUS_UNKNOWN:
+ break;
+ case SNAPD_SNAP_STATUS_INSTALLED:
+ case SNAPD_SNAP_STATUS_ACTIVE:
+ if (gs_app_get_state (app) == AS_APP_STATE_AVAILABLE)
+ gs_app_set_state (app, AS_APP_STATE_UNKNOWN);
+ gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+ break;
+ case SNAPD_SNAP_STATUS_AVAILABLE:
+ case SNAPD_SNAP_STATUS_PRICED:
+ break;
}
- parser = parse_result (response, response_type, error);
- if (parser == NULL)
- return FALSE;
-
- root = json_node_get_object (json_parser_get_root (parser));
- type = json_object_get_string_member (root, "type");
-
- if (g_strcmp0 (type, "async") == 0) {
- change_id = json_object_get_string_member (root, "change");
- resource_path = g_strdup_printf ("/v2/changes/%s", change_id);
-
- while (TRUE) {
- g_autofree gchar *status_reason_phrase = NULL;
- g_autofree gchar *status_response_type = NULL;
- g_autofree gchar *status_response = NULL;
- g_autoptr(JsonParser) status_parser = NULL;
-
- /* Wait for a little bit before polling */
- g_usleep (100 * 1000);
-
- if (!gs_snapd_request ("GET", resource_path, NULL,
- macaroon, discharges,
- &status_code, &status_reason_phrase,
- &status_response_type, &status_response, NULL,
- cancellable, error)) {
- return FALSE;
- }
-
- if (status_code != SOUP_STATUS_OK) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "snapd returned status code %u: %s",
- status_code, status_reason_phrase);
- return FALSE;
- }
-
- status_parser = parse_result (status_response, status_response_type, error);
- if (status_parser == NULL)
- return FALSE;
-
- root = json_node_get_object (json_parser_get_root (status_parser));
- result = json_object_get_object_member (root, "result");
-
- g_free (status);
- status = g_strdup (json_object_get_string_member (result, "status"));
-
- if (g_strcmp0 (status, "Done") == 0)
- break;
-
- tasks = json_object_get_array_member (result, "tasks");
- task_list = json_array_get_elements (tasks);
-
- done = 0;
- total = 0;
+ gs_app_set_name (app, GS_APP_QUALITY_HIGHEST, snapd_snap_get_summary (snap));
+ gs_app_set_summary (app, GS_APP_QUALITY_HIGHEST, snapd_snap_get_description (snap));
+ gs_app_set_version (app, snapd_snap_get_version (snap));
+ size = snapd_snap_get_installed_size (snap);
+ if (size > 0)
+ gs_app_set_size_installed (app, (guint64) size);
+ size = snapd_snap_get_download_size (snap);
+ gs_app_add_quirk (app, AS_APP_QUIRK_PROVENANCE);
- for (l = task_list; l != NULL; l = l->next) {
- task = json_node_get_object (l->data);
- progress = json_object_get_object_member (task, "progress");
- task_done = json_object_get_int_member (progress, "done");
- task_total = json_object_get_int_member (progress, "total");
+ if (flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON != 0)
+ if (!load_icon (plugin, app, client, snap, cancellable, error))
+ return FALSE;
- done += task_done;
- total += task_total;
- }
+ apps = snapd_snap_get_apps (snap);
+ if (apps != NULL && apps->len > 0)
+ launch_name = snapd_app_get_name (apps->pdata[0]);
- if (total > 0)
- gs_app_set_progress (app, (guint) (100 * done / total));
+ if (launch_name)
+ gs_app_set_metadata (app, "snap::launch-name", launch_name);
+ else
+ gs_app_add_quirk (app, AS_APP_QUIRK_NOT_LAUNCHABLE);
- g_list_free (task_list);
- }
- }
+ return TRUE;
+}
- if (g_strcmp0 (status, "Done") != 0) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "snapd operation finished with status %s", status);
- return FALSE;
+static void
+progress_cb (SnapdClient *client, SnapdTask *main_task, GPtrArray *tasks, gpointer user_data)
+{
+ GsApp *app = user_data;
+ guint i;
+ gint64 done, total;
+
+ done = 0;
+ total = 0;
+ for (i = 0; i < tasks->len; i++) {
+ SnapdTask *task = tasks->pdata[i];
+ done += snapd_task_get_progress_done (task);
+ total += snapd_task_get_progress_total (task);
}
- return TRUE;
+ if (total > 0)
+ gs_app_set_progress (app, (guint) (100 * done / total));
}
gboolean
@@ -595,15 +347,20 @@ gs_plugin_app_install (GsPlugin *plugin,
GCancellable *cancellable,
GError **error)
{
- gboolean ret;
+ g_autoptr(SnapdClient) client = NULL;
/* We can only install apps we know of */
if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0)
return TRUE;
gs_app_set_state (app, AS_APP_STATE_INSTALLING);
- ret = send_package_action (plugin, app, gs_app_get_id (app), "install", cancellable, error);
- if (!ret) {
+ client = get_client (plugin, cancellable, error);
+ if (client == NULL)
+ return FALSE;
+ if (!snapd_client_install_sync (client,
+ gs_app_get_id (app), NULL,
+ progress_cb, app,
+ cancellable, error)) {
gs_app_set_state_recover (app);
return FALSE;
}
@@ -649,15 +406,20 @@ gs_plugin_app_remove (GsPlugin *plugin,
GCancellable *cancellable,
GError **error)
{
- gboolean ret;
+ g_autoptr(SnapdClient) client = NULL;
/* We can only remove apps we know of */
if (g_strcmp0 (gs_app_get_management_plugin (app), "snap") != 0)
return TRUE;
gs_app_set_state (app, AS_APP_STATE_REMOVING);
- ret = send_package_action (plugin, app, gs_app_get_id (app), "remove", cancellable, error);
- if (!ret) {
+ client = get_client (plugin, cancellable, error);
+ if (client == NULL)
+ return FALSE;
+ if (!snapd_client_remove_sync (client,
+ gs_app_get_id (app),
+ progress_cb, app,
+ cancellable, error)) {
gs_app_set_state_recover (app);
return FALSE;
}
@@ -670,105 +432,34 @@ gs_plugin_auth_login (GsPlugin *plugin, GsAuth *auth,
GCancellable *cancellable, GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- g_autoptr(JsonBuilder) builder = NULL;
- g_autoptr(JsonNode) json_root = NULL;
- g_autoptr(JsonGenerator) json_generator = NULL;
- g_autofree gchar *data = NULL;
- guint status_code;
- g_autofree gchar *reason_phrase = NULL;
- g_autofree gchar *response_type = NULL;
- g_autofree gchar *response = NULL;
- g_autoptr(JsonObject) result = NULL;
- JsonArray *discharges;
- guint i;
- g_autoptr(GVariantBuilder) b = NULL;
+ g_autoptr(SnapdAuthData) snapd_auth = NULL;
g_autoptr(GVariant) macaroon_variant = NULL;
g_autofree gchar *serialized_macaroon = NULL;
+ g_autoptr(GError) local_error = NULL;
if (auth != priv->auth)
return TRUE;
- builder = json_builder_new ();
- json_builder_begin_object (builder);
- json_builder_set_member_name (builder, "username");
- json_builder_add_string_value (builder, gs_auth_get_username (auth));
- json_builder_set_member_name (builder, "password");
- json_builder_add_string_value (builder, gs_auth_get_password (auth));
- if (gs_auth_get_pin (auth)) {
- json_builder_set_member_name (builder, "otp");
- json_builder_add_string_value (builder, gs_auth_get_pin (auth));
- }
- json_builder_end_object (builder);
-
- json_root = json_builder_get_root (builder);
- json_generator = json_generator_new ();
- json_generator_set_pretty (json_generator, TRUE);
- json_generator_set_root (json_generator, json_root);
- data = json_generator_to_data (json_generator, NULL);
- if (data == NULL) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "Failed to generate JSON request");
- return FALSE;
- }
-
- if (!gs_snapd_request ("POST", "/v2/login", data,
- NULL, NULL,
- &status_code, &reason_phrase,
- &response_type, &response, NULL,
- cancellable, error))
- return FALSE;
-
- if (status_code != SOUP_STATUS_OK) {
- g_autofree gchar *error_message = NULL;
- g_autofree gchar *error_kind = NULL;
-
- if (!gs_snapd_parse_error (response_type, response, &error_message, &error_kind, error))
- return FALSE;
-
- if (g_strcmp0 (error_kind, "two-factor-required") == 0) {
+ snapd_auth = snapd_login_sync (gs_auth_get_username (auth), gs_auth_get_password (auth),
gs_auth_get_pin (auth), cancellable, error);
+ if (snapd_auth == NULL) {
+ if (g_error_matches (local_error, SNAPD_ERROR, SNAPD_ERROR_TWO_FACTOR_REQUIRED)) {
g_set_error_literal (error,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_PIN_REQUIRED,
- error_message);
+ local_error->message);
}
else {
g_set_error_literal (error,
GS_PLUGIN_ERROR,
GS_PLUGIN_ERROR_FAILED,
- error_message);
+ local_error->message);
}
return FALSE;
}
- if (!gs_snapd_parse_result (response_type, response, &result, error))
- return FALSE;
-
- if (!json_object_has_member (result, "macaroon")) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "Login response missing macaroon");
- return FALSE;
- }
- discharges = json_object_get_array_member (result, "discharges");
- b = g_variant_builder_new (G_VARIANT_TYPE ("as"));
- for (i = 0; i < json_array_get_length (discharges); i++) {
- JsonNode *node;
- node = json_array_get_element (discharges, i);
- if (!JSON_NODE_HOLDS_VALUE (node) && json_node_get_value_type (node) != G_TYPE_STRING) {
- g_set_error_literal (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_FAILED,
- "Macaroon discharge contains unexpected value");
- return FALSE;
- }
- g_variant_builder_add (b, "s", json_node_get_string (node));
- }
- macaroon_variant = g_variant_new ("(sas)",
- json_object_get_string_member (result, "macaroon"),
- b);
+ macaroon_variant = g_variant_new ("(s^as)",
+ snapd_auth_data_get_macaroon (snapd_auth),
+ snapd_auth_data_get_discharges (snapd_auth));
serialized_macaroon = g_variant_print (macaroon_variant, FALSE);
gs_auth_add_metadata (auth, "macaroon", serialized_macaroon);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]