[gnome-software/wip/hughsie/shell-extensions] Add support for GNOME Shell extensions



commit ebc97e05b1b1f140af628c71d91ec17e0ae9b444
Author: Richard Hughes <richard hughsie com>
Date:   Thu Feb 25 09:56:21 2016 +0000

    Add support for GNOME Shell extensions

 src/plugins/Makefile.am                  |    6 +
 src/plugins/gs-plugin-shell-extensions.c |  310 ++++++++++++++++++++++++++++++
 2 files changed, 316 insertions(+), 0 deletions(-)
---
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 5156bb7..9f859be 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -40,6 +40,7 @@ plugin_LTLIBRARIES =                                  \
        libgs_plugin_fedora_provenance.la               \
        libgs_plugin_ubuntu-reviews.la                  \
        libgs_plugin_fedora_tagger_usage.la             \
+       libgs_plugin_shell-extensions.la                \
        libgs_plugin_epiphany.la                        \
        libgs_plugin_icons.la
 
@@ -73,6 +74,11 @@ libgs_plugin_dummy_la_LIBADD = $(GS_PLUGIN_LIBS)
 libgs_plugin_dummy_la_LDFLAGS = -module -avoid-version
 libgs_plugin_dummy_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
 
+libgs_plugin_shell_extensions_la_SOURCES = gs-plugin-shell-extensions.c
+libgs_plugin_shell_extensions_la_LIBADD = $(GS_PLUGIN_LIBS) $(JSON_GLIB_LIBS)
+libgs_plugin_shell_extensions_la_LDFLAGS = -module -avoid-version
+libgs_plugin_shell_extensions_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARN_CFLAGS)
+
 libgs_plugin_fedora_distro_upgrades_la_SOURCES = gs-plugin-fedora-distro-upgrades.c
 libgs_plugin_fedora_distro_upgrades_la_LIBADD = $(GS_PLUGIN_LIBS) $(JSON_GLIB_LIBS) $(SOUP_LIBS)
 libgs_plugin_fedora_distro_upgrades_la_LDFLAGS = -module -avoid-version
diff --git a/src/plugins/gs-plugin-shell-extensions.c b/src/plugins/gs-plugin-shell-extensions.c
new file mode 100644
index 0000000..dcecc6c
--- /dev/null
+++ b/src/plugins/gs-plugin-shell-extensions.c
@@ -0,0 +1,310 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 Kalev Lember <klember redhat 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 <errno.h>
+#include <json-glib/json-glib.h>
+
+#include <gs-plugin.h>
+#include <gs-os-release.h>
+#include <gs-utils.h>
+
+#define SHELL_EXTENSIONS_CACHE_AGE_MAX         237000 /* 1 week */
+#define SHELL_EXTENSIONS_API_URI               "https://extensions.gnome.org/extension-query/";
+
+// See https://git.gnome.org/browse/extensions-web/tree/sweettooth/extensions/views.py for src
+
+#if 0
+{
+  "numpages": 1,
+  "total": 1,
+  "extensions": [
+    {
+      "shell_version_map": {
+        "3.18": {
+          "pk": 5353,
+          "version": 23
+        },
+        "3.4.0": {
+          "pk": 2119,
+          "version": 9
+        },
+        "3.20": {
+          "pk": 2999,
+          "version": 110
+        },
+        "3.3.4": {
+          "pk": 848,
+          "version": 6
+        }
+      },
+      "description": "Now updated for shell 3.18\nissue:\nsudo apt-get install gir1.2-gconf\nor similar 
prior to installing",
+      "creator": "jablona123",
+      "name": "Gmail Notify",
+      "link": "\/extension\/154\/gmail-notify\/",
+      "pk": 154,
+      "creator_url": "\/accounts\/profile\/jablona123",
+      "icon": "\/static\/extension-data\/icons\/icon_154_1.png",
+      "uuid": "gmail_notify jablona123 pl"
+    }
+  ]
+}
+#endif
+
+#ifndef JsonParser_autoptr
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(JsonParser, g_object_unref)
+#endif
+
+struct GsPluginPrivate {
+       GPtrArray       *distros;
+};
+
+/**
+ * gs_plugin_get_name:
+ */
+const gchar *
+gs_plugin_get_name (void)
+{
+       return "shell-extensions";
+}
+
+/**
+ * gs_plugin_shell_extensions_parse_apps:
+ */
+static GPtrArray *
+gs_plugin_shell_extensions_parse_apps (const gchar *data,
+                                      gsize data_len,
+                                      GError **error)
+{
+       GPtrArray *apps;
+       JsonNode *json_root;
+       JsonObject *json_item;
+//     guint i;
+       g_autoptr(JsonParser) json_parser = NULL;
+
+       /* nothing */
+       if (data == NULL) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "server returned no data");
+               return NULL;
+       }
+
+       /* parse the data and find the success */
+       json_parser = json_parser_new ();
+       if (!json_parser_load_from_data (json_parser, data, data_len, error))
+               return NULL;
+       json_root = json_parser_get_root (json_parser);
+       if (json_root == NULL) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "no error root");
+               return NULL;
+       }
+       if (json_node_get_node_type (json_root) != JSON_NODE_OBJECT) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "no error object");
+               return NULL;
+       }
+       json_item = json_node_get_object (json_root);
+       if (json_item == NULL) {
+               g_set_error_literal (error,
+                                    GS_PLUGIN_ERROR,
+                                    GS_PLUGIN_ERROR_FAILED,
+                                    "no error object");
+               return NULL;
+       }
+       apps = g_ptr_array_new ();
+       return apps;
+}
+
+/**
+ * gs_plugin_shell_extensions_get_apps:
+ */
+static GPtrArray *
+gs_plugin_shell_extensions_get_apps (GsPlugin *plugin, GError **error)
+{
+       GPtrArray *apps;
+       guint status_code;
+       g_autofree gchar *cachedir = NULL;
+       g_autofree gchar *cachefn = NULL;
+       g_autofree gchar *data = NULL;
+       g_autofree gchar *uri = NULL;
+       g_autoptr(GFile) cachefn_file = NULL;
+       g_autoptr(SoupMessage) msg = NULL;
+
+       /* look in the cache */
+       cachedir = gs_utils_get_cachedir ("extensions", error);
+       if (cachedir == NULL)
+               return NULL;
+       cachefn = g_strdup_printf ("%s/gnome.json", cachedir);
+       cachefn_file = g_file_new_for_path (cachefn);
+       if (gs_utils_get_file_age (cachefn_file) < SHELL_EXTENSIONS_CACHE_AGE_MAX) {
+               g_autofree gchar *json_data = NULL;
+               if (!g_file_get_contents (cachefn, &json_data, NULL, error))
+                       return NULL;
+               g_debug ("got cached extension data from %s", cachefn);
+               return gs_plugin_shell_extensions_parse_apps (json_data, -1, error);
+       }
+
+       /* create the GET data */
+       uri = g_strdup_printf ("%s/?shell_version=%s&page=1&n_per_page=1000",
+                              SHELL_EXTENSIONS_API_URI,
+                              "3.20");
+       msg = soup_message_new (SOUP_METHOD_GET, uri);
+       status_code = soup_session_send_message (plugin->soup_session, msg);
+       if (status_code != SOUP_STATUS_OK) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "failed to get shell extensions: %s",
+                            msg->response_body->data);
+               return NULL;
+       }
+       g_debug ("%s returned: %s",
+                SHELL_EXTENSIONS_API_URI,
+                msg->response_body->data);
+       apps = gs_plugin_shell_extensions_parse_apps (msg->response_body->data,
+                                                     msg->response_body->length,
+                                                     error);
+       if (apps == NULL)
+               return NULL;
+
+       /* save to the cache */
+       if (!g_file_set_contents (cachefn,
+                                 msg->response_body->data,
+                                 msg->response_body->length,
+                                 error))
+               return NULL;
+
+       return apps;
+}
+
+/**
+ * _gs_plugin_startup:
+ */
+static gboolean
+_gs_plugin_startup (GsPlugin *plugin, GError **error)
+{
+       AsApp *app;
+       guint i;
+       g_autoptr(GPtrArray) apps = NULL;
+
+       /* get data */
+       apps = gs_plugin_shell_extensions_get_apps (plugin, error);
+       if (apps == NULL)
+               return FALSE;
+
+       /* add to global store */
+       for (i = 0; i < apps->len; i++) {
+               app = g_ptr_array_index (apps, i);
+               g_debug ("Adding to global store %s", as_app_get_id (app));
+       }
+
+       return TRUE;
+}
+
+/**
+ * gs_plugin_initialize:
+ */
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+       plugin->priv = GS_PLUGIN_GET_PRIVATE (GsPluginPrivate);
+
+       /* this really belongs in _startup() or something that runs as a 2nd phase */
+       _gs_plugin_startup (plugin, NULL);
+}
+
+/**
+ * gs_plugin_destroy:
+ */
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+       if (plugin->priv->distros != NULL)
+               g_ptr_array_unref (plugin->priv->distros);
+}
+
+/**
+ * gs_plugin_add_category_apps:
+ */
+gboolean
+gs_plugin_add_category_apps (GsPlugin *plugin,
+                            GsCategory *category,
+                            GList **list,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       if (g_strcmp0 (gs_category_get_id (category), "shell-extensions") != 0)
+               return TRUE;
+
+       //FIXME: add apps with the ShellExtensions management plugin?
+       //FIXME or leave to the appstream plugin?
+       return TRUE;
+}
+
+/**
+ * gs_plugin_app_remove:
+ */
+gboolean
+gs_plugin_app_remove (GsPlugin *plugin,
+                     GsApp *app,
+                     GCancellable *cancellable,
+                     GError **error)
+{
+       /* only process this app if was created by this plugin */
+       if (g_strcmp0 (gs_app_get_management_plugin (app), "ShellExtensions") != 0)
+               return TRUE;
+
+       /* FIXME */
+       g_set_error_literal (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "Not yet supported");
+       return FALSE;
+}
+
+/**
+ * gs_plugin_app_install:
+ */
+gboolean
+gs_plugin_app_install (GsPlugin *plugin,
+                      GsApp *app,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+       /* only process this app if was created by this plugin */
+       if (g_strcmp0 (gs_app_get_management_plugin (app), "ShellExtensions") != 0)
+               return TRUE;
+
+       /* FIXME */
+       g_set_error_literal (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "No yet supported");
+       return FALSE;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]