Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:JonathanKang:branches:GNOME:STABLE:41
gnome-software
gnome-software-plugin-opensuse-distro-upgrade.p...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File gnome-software-plugin-opensuse-distro-upgrade.patch of Package gnome-software
From 305060abd9f8bad1da813ebcd92702add1c9dfef Mon Sep 17 00:00:00 2001 From: Jonathan Kang <jonathankang@gnome.org> Date: Tue, 13 Jul 2021 09:51:00 +0800 Subject: [PATCH] Add openSUSE-distro-upgrade plugin --- meson.build | 1 + plugins/meson.build | 4 +- .../gs-plugin-openSUSE-distro-upgrade.c | 283 ++++++++++++++++++ plugins/openSUSE-distro-upgrade/meson.build | 17 ++ 4 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 plugins/openSUSE-distro-upgrade/gs-plugin-openSUSE-distro-upgrade.c create mode 100644 plugins/openSUSE-distro-upgrade/meson.build Index: gnome-software-41.5/plugins/opensuse-distro-upgrade/meson.build =================================================================== --- /dev/null +++ gnome-software-41.5/plugins/opensuse-distro-upgrade/meson.build @@ -0,0 +1,17 @@ +cargs = ['-DG_LOG_DOMAIN="GsPluginOpensuseDistroUpgrade"'] + +shared_module( + 'gs_plugin_opensuse-distro-upgrade', + sources : 'gs-plugin-opensuse-distro-upgrade.c', + include_directories : [ + include_directories('../..'), + include_directories('../../lib') + ], + install : true, + install_dir : plugin_dir, + c_args : cargs, + dependencies : plugin_libs, + link_with : [ + libgnomesoftware + ] +) Index: gnome-software-41.5/plugins/meson.build =================================================================== --- gnome-software-41.5.orig/plugins/meson.build +++ gnome-software-41.5/plugins/meson.build @@ -12,6 +12,7 @@ subdir('dpkg') subdir('dummy') subdir('fedora-langpacks') subdir('fedora-pkgdb-collections') +subdir('opensuse-distro-upgrade') if get_option('eos_updater') subdir('eos-updater') Index: gnome-software-41.5/plugins/opensuse-distro-upgrade/gs-plugin-opensuse-distro-upgrade.c =================================================================== --- /dev/null +++ gnome-software-41.5/plugins/opensuse-distro-upgrade/gs-plugin-opensuse-distro-upgrade.c @@ -0,0 +1,429 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Copyright (C) 2020 Jonathan Kang <jonathankang@gnome.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include <json-glib/json-glib.h> +#include <gnome-software.h> + +#define OPENSUSE_DISTRO_UPGRADE_API_URI "https://get.opensuse.org/api/v0/distributions.json" + +struct GsPluginData { + gchar *cachefn; + GFileMonitor *cachefn_monitor; + GsApp *cached_origin; + gboolean is_valid; + gchar *os_name; + gchar *os_version; + guint upgrade_weight; + GPtrArray *distros; + GMutex mutex; +}; + +typedef enum { + DISTRO_UPGRADE_ITEM_STATE_ALPHA, + DISTRO_UPGRADE_ITEM_STATE_BETA, + DISTRO_UPGRADE_ITEM_STATE_STABLE, + DISTRO_UPGRADE_ITEM_STATE_EOL, + DISTRO_UPGRADE_ITEM_STATE_LAST, +} DistroUpgradeItemState; + +typedef struct { + gchar *name; + gchar *version; + DistroUpgradeItemState state; + guint upgrade_weight; +} DistroUpgradeItem; + +static gboolean +is_valid_upgrade (GsPlugin *plugin, + DistroUpgradeItem *item) +{ + guint diff; + GsPluginData *priv = gs_plugin_get_data (plugin); + + diff = item->upgrade_weight - priv->upgrade_weight; + if (diff == 1) + return TRUE; + else + return FALSE; +} + + +static GsApp * +create_upgrade_app (GsPlugin *plugin, + DistroUpgradeItem *item) +{ + GsApp *app; + g_autofree gchar *app_id = NULL; + g_autofree gchar *app_version = NULL; + g_autofree gchar *background = NULL; + g_autofree gchar *cache_key = NULL; + g_autofree gchar *css = NULL; + g_autofree gchar *url = NULL; + g_autoptr(GFile) icon_file = NULL; + g_autoptr(GIcon) ic = NULL; + + cache_key = g_strdup_printf ("leap-%s", item->version); + app = gs_plugin_cache_lookup (plugin, cache_key); + if (app != NULL) + return app; + + app_id = g_strdup_printf ("org.openSUSE.Leap-%s", item->version); + app_version = g_strdup (item->version); + + /* icon from disk */ + icon_file = g_file_new_for_path ("/usr/share/pixmaps/distribution-logos/square-symbolic.svg"); + ic = g_file_icon_new (icon_file); + + app = gs_app_new (app_id); + gs_app_set_state (app, GS_APP_STATE_AVAILABLE); + gs_app_set_kind (app, AS_COMPONENT_KIND_OPERATING_SYSTEM); + gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_PACKAGE); + gs_app_set_name (app, GS_APP_QUALITY_LOWEST, item->name); + gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, + _("Upgrade for the latest features, performance and stability improvements.")); + gs_app_set_version (app, app_version); + gs_app_set_size_installed (app, GS_APP_SIZE_UNKNOWABLE); + gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE); + gs_app_set_license (app, GS_APP_QUALITY_LOWEST, "LicenseRef-free"); + gs_app_add_quirk (app, GS_APP_QUIRK_NEEDS_REBOOT); + gs_app_add_quirk (app, GS_APP_QUIRK_PROVENANCE); + gs_app_add_quirk (app, GS_APP_QUIRK_NOT_REVIEWABLE); + gs_app_add_icon (app, ic); + + /* Save it in the cache. */ + gs_plugin_cache_add (plugin, cache_key, app); + + return app; +} + + +static gboolean +_refresh_cache (GsPlugin *plugin, + guint cache_age, + GCancellable *cancellable, + GError **error) +{ + GsPluginData *priv = gs_plugin_get_data (plugin); + g_autoptr(GsApp) app_dl = gs_app_new (gs_plugin_get_name (plugin)); + + /* check cache age */ + if (cache_age > 0) { + g_autoptr(GFile) file = g_file_new_for_path (priv->cachefn); + guint tmp = gs_utils_get_file_age (file); + if (tmp < cache_age) { + g_debug ("%s is only %u seconds old", + priv->cachefn, tmp); + return TRUE; + } + } + + /* download new file */ + gs_app_set_summary_missing (app_dl, + /* TRANSLATORS: status text when downloading */ + _("Downloading upgrade information…")); + if (!gs_plugin_download_file (plugin, app_dl, + OPENSUSE_DISTRO_UPGRADE_API_URI, + priv->cachefn, + cancellable, + error)) { + gs_utils_error_add_origin_id (error, priv->cached_origin); + return FALSE; + } + + /* success */ + priv->is_valid = FALSE; + return TRUE; +} + +static gboolean +_ensure_cache (GsPlugin *plugin, + GCancellable *cancellable, + GError **error) +{ + GsPluginData *priv = gs_plugin_get_data (plugin); + JsonArray *distros; + JsonObject *root; +#if !JSON_CHECK_VERSION(1, 6, 0) + gsize len; + g_autofree gchar *data = NULL; +#endif /* json-glib < 1.6.0 */ + g_autoptr(JsonParser) parser = NULL; + + /* already done */ + if (priv->is_valid) + return TRUE; + + /* just ensure there is any data, no matter how old */ + if (!_refresh_cache (plugin, G_MAXUINT, cancellable, error)) + return FALSE; + +#if JSON_CHECK_VERSION(1, 6, 0) + parser = json_parser_new_immutable (); + if (!json_parser_load_from_mapped_file (parser, priv->cachefn, error)) + return FALSE; +#else /* if json-glib < 1.6.0 */ + /* get cached file */ + if (!g_file_get_contents (priv->cachefn, &data, &len, error)) { + gs_utils_error_convert_gio (error); + return FALSE; + } + + /* parse data */ + parser = json_parser_new (); + if (!json_parser_load_from_data (parser, data, len, error)) + return FALSE; +#endif /* json-glib < 1.6.0 */ + + root = json_node_get_object (json_parser_get_root (parser)); + if (root == NULL) { + g_set_error (error, + GS_PLUGIN_ERROR, + GS_PLUGIN_ERROR_INVALID_FORMAT, + "no root object"); + return FALSE; + } + + distros = json_object_get_array_member (root, "Leap"); + if (distros == NULL) { + g_set_error (error, + GS_PLUGIN_ERROR, + GS_PLUGIN_ERROR_INVALID_FORMAT, + "No array member named \"Leap\"."); + return FALSE; + } + + g_ptr_array_set_size (priv->distros, 0); + for (guint i = 0; i < json_array_get_length (distros); i++) { + DistroUpgradeItem *item; + DistroUpgradeItemState state; + JsonObject *distro; + const gchar *name; + const gchar *version; + const gchar *state_str; + guint upgrade_weight; + + distro = json_array_get_object_element (distros, i); + if (distro == NULL) + continue; + + name = json_object_get_string_member (distro, "name"); + if (name == NULL) + continue; + + version = json_object_get_string_member (distro, "version"); + if (version == NULL) + continue; + + state_str = json_object_get_string_member (distro, "state"); + + if (state_str == NULL) + continue; + if (g_strcmp0 (state_str, "Alpha") == 0) + state = DISTRO_UPGRADE_ITEM_STATE_ALPHA; + else if (g_strcmp0 (state_str, "Beta") == 0) + state = DISTRO_UPGRADE_ITEM_STATE_BETA; + else if (g_strcmp0 (state_str, "Stable") == 0) + state = DISTRO_UPGRADE_ITEM_STATE_STABLE; + else if (g_strcmp0 (state_str, "EOL") == 0) + state = DISTRO_UPGRADE_ITEM_STATE_EOL; + else + continue; + + /* Do not care about versions that are end-of-life. */ + if (state == DISTRO_UPGRADE_ITEM_STATE_EOL) + continue; + + upgrade_weight = json_object_get_int_member (distro, "upgrade-weight"); + + /* Set upgrade weight for current OS. */ + if (g_strcmp0 (priv->os_version, version) == 0) + priv->upgrade_weight = upgrade_weight; + + /* add item */ + item = g_new0 (DistroUpgradeItem, 1); + item->name = g_strdup (name); + item->version = g_strdup (version); + item->state = state; + item->upgrade_weight = upgrade_weight; + g_ptr_array_add (priv->distros, item); + } + + + + /* success */ + priv->is_valid = TRUE; + return TRUE; +} + +gboolean +gs_plugin_add_distro_upgrades (GsPlugin *plugin, + GsAppList *list, + GCancellable *cancellable, + GError **error) +{ + gboolean show_prerelease; + g_autoptr(GSettings) settings = NULL; + GsPluginData *priv = gs_plugin_get_data (plugin); + g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&priv->mutex); + + /* ensure valid data is loaded */ + if (!_ensure_cache (plugin, cancellable, error)) + return FALSE; + + /* Only interested in stable versions. */ + settings = g_settings_new ("org.gnome.software"); + show_prerelease = g_settings_get_boolean (settings, "show-upgrade-prerelease"); + + /* Is there any upgrade available? */ + for (guint i = 0; i < priv->distros->len; i++) { + DistroUpgradeItem *item; + + item = g_ptr_array_index (priv->distros, i); + if (show_prerelease || + (!show_prerelease && item->state == DISTRO_UPGRADE_ITEM_STATE_STABLE)) + if (is_valid_upgrade (plugin, item)) { + g_autoptr(GsApp) app = NULL; + + app = create_upgrade_app (plugin, item); + gs_app_list_add (list, app); + + break; + } + } + + return TRUE; +} + +gboolean +gs_plugin_refresh (GsPlugin *plugin, + guint cache_age, + GCancellable *cancellable, + GError **error) +{ + GsPluginData *priv = gs_plugin_get_data (plugin); + g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->mutex); + return _refresh_cache (plugin, cache_age, cancellable, error); +} + +static void +_file_changed_cb (GFileMonitor *monitor, + GFile *file, GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + GsPlugin *plugin = GS_PLUGIN (user_data); + GsPluginData *priv = gs_plugin_get_data (plugin); + + g_debug ("cache file changed, so reloading upgrades list"); + gs_plugin_updates_changed (plugin); + priv->is_valid = FALSE; +} + +static void +distro_upgrade_item_destroy (DistroUpgradeItem *item) +{ + g_free (item->name); + g_free (item->version); + g_slice_free (DistroUpgradeItem, item); +} + +void +gs_plugin_initialize (GsPlugin *plugin) +{ + GsPluginData *priv = gs_plugin_alloc_data (plugin, sizeof (GsPluginData)); + + g_mutex_init (&priv->mutex); + + /* Check if we are running openSUSE Leap. */ + if (!gs_plugin_check_distro_id (plugin, "opensuse-leap")) { + gs_plugin_set_enabled (plugin, FALSE); + g_debug ("Disabling '%s' as it's only supported in openSUSE Leap", gs_plugin_get_name (plugin)); + return; + } + + priv->distros = g_ptr_array_new_with_free_func ((GDestroyNotify) distro_upgrade_item_destroy); + + /* require the GnomeSoftware::CpeName metadata */ + gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "os-release"); +} + +void +gs_plugin_destroy (GsPlugin *plugin) +{ + GsPluginData *priv = gs_plugin_get_data (plugin); + + if (priv->cachefn_monitor != NULL) + g_object_unref (priv->cachefn_monitor); + if (priv->cached_origin != NULL) + g_object_unref (priv->cached_origin); + if (priv->distros != NULL) + g_ptr_array_unref (priv->distros); + + g_free (priv->os_name); + g_free (priv->os_version); + g_free (priv->cachefn); + + g_mutex_clear (&priv->mutex); +} + +gboolean +gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error) +{ + GsPluginData *priv = gs_plugin_get_data (plugin); + g_autoptr(GFile) file = NULL; + g_autoptr(GsOsRelease) os_release = NULL; + g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&priv->mutex); + + /* get the file to cache */ + priv->cachefn = gs_utils_get_cache_filename ("opensuse-distro-upgrade", + "distributions.json", + GS_UTILS_CACHE_FLAG_WRITEABLE | + GS_UTILS_CACHE_FLAG_CREATE_DIRECTORY, + error); + if (priv->cachefn == NULL) + return FALSE; + + /* watch this in case it is changed by the user */ + file = g_file_new_for_path (priv->cachefn); + priv->cachefn_monitor = g_file_monitor (file, + G_FILE_MONITOR_NONE, + cancellable, + error); + if (priv->cachefn_monitor == NULL) + return FALSE; + g_signal_connect (priv->cachefn_monitor, "changed", + G_CALLBACK (_file_changed_cb), plugin); + + os_release = gs_os_release_new (error); + if (os_release == NULL) + return FALSE; + priv->os_name = g_strdup (gs_os_release_get_name (os_release)); + if (priv->os_name == NULL) + return FALSE; + priv->os_version = g_strdup (gs_os_release_get_version_id (os_release)); + if (priv->os_version == NULL) + return FALSE; + + /* add source */ + priv->cached_origin = gs_app_new (gs_plugin_get_name (plugin)); + gs_app_set_kind (priv->cached_origin, AS_COMPONENT_KIND_REPOSITORY); + gs_app_set_origin_hostname (priv->cached_origin, + OPENSUSE_DISTRO_UPGRADE_API_URI); + gs_app_set_management_plugin (priv->cached_origin, gs_plugin_get_name (plugin)); + + /* add the source to the plugin cache which allows us to match the + * unique ID to a GsApp when creating an event */ + gs_plugin_cache_add (plugin, + gs_app_get_unique_id (priv->cached_origin), + priv->cached_origin); + + return TRUE; +}
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor