[gnome-software] packagekit: Support apt:// URLs
- From: Iain Lane <iainl src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] packagekit: Support apt:// URLs
- Date: Tue, 5 Dec 2017 16:50:24 +0000 (UTC)
commit 8c739ffd075f06225a0631c5e84545a08af1d77e
Author: Iain Lane <iain orangesquash org uk>
Date: Mon Oct 23 16:57:26 2017 +0100
packagekit: Support apt:// URLs
When we receive an apt:// URL and we're runing a Debian-based distro,
try to resolve it to a package using PK.
lib/gs-os-release.c | 25 ++
lib/gs-os-release.h | 19 +-
plugins/packagekit/gs-plugin-packagekit-local.c | 18 +-
plugins/packagekit/gs-plugin-packagekit-refine.c | 242 +-------------------
plugins/packagekit/gs-plugin-packagekit-refresh.c | 37 +---
plugins/packagekit/gs-plugin-packagekit-upgrade.c | 15 +-
.../packagekit/gs-plugin-packagekit-url-to-app.c | 122 ++++++++++
plugins/packagekit/gs-plugin-packagekit.c | 79 +------
plugins/packagekit/meson.build | 16 ++
plugins/packagekit/packagekit-common.c | 218 ++++++++++++++++++
plugins/packagekit/packagekit-common.h | 37 +++-
11 files changed, 446 insertions(+), 382 deletions(-)
---
diff --git a/lib/gs-os-release.c b/lib/gs-os-release.c
index 2c3b1cb..2aa598e 100644
--- a/lib/gs-os-release.c
+++ b/lib/gs-os-release.c
@@ -43,6 +43,7 @@ struct _GsOsRelease
gchar *name;
gchar *version;
gchar *id;
+ gchar **id_like;
gchar *version_id;
gchar *pretty_name;
gchar *cpe_name;
@@ -111,6 +112,10 @@ gs_os_release_initable_init (GInitable *initable,
os_release->id = g_strdup (tmp);
continue;
}
+ if (g_strcmp0 (lines[i], "ID_LIKE") == 0) {
+ os_release->id_like = g_strsplit (tmp, " ", 0);
+ continue;
+ }
if (g_strcmp0 (lines[i], "VERSION_ID") == 0) {
os_release->version_id = g_strdup (tmp);
continue;
@@ -187,6 +192,25 @@ gs_os_release_get_id (GsOsRelease *os_release)
}
/**
+ * gs_os_release_get_id_like:
+ * @os_release: A #GsOsRelease
+ *
+ * Gets the ID_LIKE from the os-release parser. This is a list of operating
+ * systems that are "closely related" to the local operating system, possibly
+ * by being a derivative distribution.
+ *
+ * Returns: a %NULL terminated list
+ *
+ * Since: 3.26.2
+ **/
+const gchar * const *
+gs_os_release_get_id_like (GsOsRelease *os_release)
+{
+ g_return_val_if_fail (GS_IS_OS_RELEASE (os_release), NULL);
+ return (const gchar * const *) os_release->id_like;
+}
+
+/**
* gs_os_release_get_version_id:
* @os_release: A #GsOsRelease
*
@@ -278,6 +302,7 @@ gs_os_release_finalize (GObject *object)
g_free (os_release->name);
g_free (os_release->version);
g_free (os_release->id);
+ g_strfreev (os_release->id_like);
g_free (os_release->version_id);
g_free (os_release->pretty_name);
g_free (os_release->cpe_name);
diff --git a/lib/gs-os-release.h b/lib/gs-os-release.h
index 8da104a..ec68259 100644
--- a/lib/gs-os-release.h
+++ b/lib/gs-os-release.h
@@ -33,15 +33,16 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GsOsRelease, gs_os_release, GS, OS_RELEASE, GObject)
-GsOsRelease *gs_os_release_new (GError **error);
-const gchar *gs_os_release_get_name (GsOsRelease *os_release);
-const gchar *gs_os_release_get_version (GsOsRelease *os_release);
-const gchar *gs_os_release_get_id (GsOsRelease *os_release);
-const gchar *gs_os_release_get_version_id (GsOsRelease *os_release);
-const gchar *gs_os_release_get_pretty_name (GsOsRelease *os_release);
-const gchar *gs_os_release_get_cpe_name (GsOsRelease *os_release);
-const gchar *gs_os_release_get_distro_codename (GsOsRelease *os_release);
-const gchar *gs_os_release_get_home_url (GsOsRelease *os_release);
+GsOsRelease *gs_os_release_new (GError **error);
+const gchar *gs_os_release_get_name (GsOsRelease *os_release);
+const gchar *gs_os_release_get_version (GsOsRelease *os_release);
+const gchar *gs_os_release_get_id (GsOsRelease *os_release);
+const gchar * const *gs_os_release_get_id_like (GsOsRelease *os_release);
+const gchar *gs_os_release_get_version_id (GsOsRelease *os_release);
+const gchar *gs_os_release_get_pretty_name (GsOsRelease *os_release);
+const gchar *gs_os_release_get_cpe_name (GsOsRelease *os_release);
+const gchar *gs_os_release_get_distro_codename (GsOsRelease *os_release);
+const gchar *gs_os_release_get_home_url (GsOsRelease *os_release);
G_END_DECLS
diff --git a/plugins/packagekit/gs-plugin-packagekit-local.c b/plugins/packagekit/gs-plugin-packagekit-local.c
index 0840b12..f93d1dd 100644
--- a/plugins/packagekit/gs-plugin-packagekit-local.c
+++ b/plugins/packagekit/gs-plugin-packagekit-local.c
@@ -47,15 +47,10 @@ gs_plugin_destroy (GsPlugin *plugin)
g_object_unref (priv->task);
}
-typedef struct {
- GsApp *app;
- GsPlugin *plugin;
-} ProgressData;
-
static void
-gs_plugin_packagekit_progress_cb (PkProgress *progress,
- PkProgressType type,
- gpointer user_data)
+gs_plugin_packagekit_local_progress_cb (PkProgress *progress,
+ PkProgressType type,
+ gpointer user_data)
{
ProgressData *data = (ProgressData *) user_data;
GsPlugin *plugin = data->plugin;
@@ -83,7 +78,7 @@ gs_plugin_packagekit_refresh_guess_app_id (GsPlugin *plugin,
{
GsPluginData *priv = gs_plugin_get_data (plugin);
PkFiles *item;
- ProgressData data;
+ ProgressData data = { 0 };
guint i;
guint j;
gchar **fns;
@@ -99,7 +94,7 @@ gs_plugin_packagekit_refresh_guess_app_id (GsPlugin *plugin,
results = pk_client_get_files_local (PK_CLIENT (priv->task),
files,
cancellable,
- gs_plugin_packagekit_progress_cb, &data,
+ gs_plugin_packagekit_local_progress_cb, &data,
error);
if (!gs_plugin_packagekit_results_valid (results, error)) {
gs_utils_error_add_unique_id (error, app);
@@ -145,7 +140,7 @@ gs_plugin_file_to_app (GsPlugin *plugin,
GsPluginData *priv = gs_plugin_get_data (plugin);
const gchar *package_id;
PkDetails *item;
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr (PkResults) results = NULL;
g_autofree gchar *basename = NULL;
g_autofree gchar *content_type = NULL;
@@ -170,7 +165,6 @@ gs_plugin_file_to_app (GsPlugin *plugin,
if (!g_strv_contains (mimetypes, content_type))
return TRUE;
- data.app = NULL;
data.plugin = plugin;
/* get details */
diff --git a/plugins/packagekit/gs-plugin-packagekit-refine.c
b/plugins/packagekit/gs-plugin-packagekit-refine.c
index 486f4b0..0c6f41b 100644
--- a/plugins/packagekit/gs-plugin-packagekit-refine.c
+++ b/plugins/packagekit/gs-plugin-packagekit-refine.c
@@ -88,145 +88,6 @@ gs_plugin_adopt_app (GsPlugin *plugin, GsApp *app)
}
}
-typedef struct {
- GsApp *app;
- GsPlugin *plugin;
- AsProfileTask *ptask;
- gchar *profile_id;
-} ProgressData;
-
-static void
-gs_plugin_packagekit_progress_cb (PkProgress *progress,
- PkProgressType type,
- gpointer user_data)
-{
- ProgressData *data = (ProgressData *) user_data;
- GsPlugin *plugin = data->plugin;
- GsPluginStatus plugin_status;
- PkStatusEnum status;
-
- if (type != PK_PROGRESS_TYPE_STATUS)
- return;
- g_object_get (progress,
- "status", &status,
- NULL);
-
- /* profile */
- if (status == PK_STATUS_ENUM_SETUP) {
- data->ptask = as_profile_start (gs_plugin_get_profile (plugin),
- "packagekit-refine::transaction[%s]",
- data->profile_id);
- /* this isn't awesome, but saves us handling it in the caller */
- g_free (data->profile_id);
- data->profile_id = NULL;
- } else if (status == PK_STATUS_ENUM_FINISHED) {
- g_clear_pointer (&data->ptask, as_profile_task_free);
- }
-
- plugin_status = packagekit_status_enum_to_plugin_status (status);
- if (plugin_status != GS_PLUGIN_STATUS_UNKNOWN)
- gs_plugin_status_update (plugin, data->app, plugin_status);
-}
-
-static void
-gs_plugin_packagekit_set_metadata_from_package (GsPlugin *plugin,
- GsApp *app,
- PkPackage *package)
-{
- const gchar *data;
-
- gs_app_set_management_plugin (app, "packagekit");
- gs_app_add_source (app, pk_package_get_name (package));
- gs_app_add_source_id (app, pk_package_get_id (package));
-
- /* set origin */
- if (gs_app_get_origin (app) == NULL) {
- data = pk_package_get_data (package);
- if (g_str_has_prefix (data, "installed:"))
- data += 10;
- gs_app_set_origin (app, data);
- }
-
- /* set unavailable state */
- if (pk_package_get_info (package) == PK_INFO_ENUM_UNAVAILABLE) {
- gs_app_set_state (app, AS_APP_STATE_UNAVAILABLE);
- gs_app_set_size_installed (app, GS_APP_SIZE_UNKNOWABLE);
- gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
- }
- if (gs_app_get_version (app) == NULL)
- gs_app_set_version (app,
- pk_package_get_version (package));
- gs_app_set_name (app,
- GS_APP_QUALITY_LOWEST,
- pk_package_get_name (package));
- gs_app_set_summary (app,
- GS_APP_QUALITY_LOWEST,
- pk_package_get_summary (package));
-}
-
-static void
-gs_plugin_packagekit_resolve_packages_app (GsPlugin *plugin,
- GPtrArray *packages,
- GsApp *app)
-{
- GPtrArray *sources;
- PkPackage *package;
- const gchar *pkgname;
- guint i, j;
- guint number_available = 0;
- guint number_installed = 0;
-
- /* find any packages that match the package name */
- number_installed = 0;
- number_available = 0;
- sources = gs_app_get_sources (app);
- for (j = 0; j < sources->len; j++) {
- pkgname = g_ptr_array_index (sources, j);
- for (i = 0; i < packages->len; i++) {
- package = g_ptr_array_index (packages, i);
- if (g_strcmp0 (pk_package_get_name (package), pkgname) == 0) {
- gs_plugin_packagekit_set_metadata_from_package (plugin, app, package);
- switch (pk_package_get_info (package)) {
- case PK_INFO_ENUM_INSTALLED:
- number_installed++;
- break;
- case PK_INFO_ENUM_AVAILABLE:
- number_available++;
- break;
- case PK_INFO_ENUM_UNAVAILABLE:
- number_available++;
- break;
- default:
- /* should we expect anything else? */
- break;
- }
- }
- }
- }
-
- /* if *all* the source packages for the app are installed then the
- * application is considered completely installed */
- if (number_installed == sources->len && number_available == 0) {
- if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN)
- gs_app_set_state (app, AS_APP_STATE_INSTALLED);
- } else if (number_installed + number_available == sources->len) {
- /* if all the source packages are installed and all the rest
- * of the packages are available then the app is available */
- if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN)
- gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
- } else if (number_installed + number_available > sources->len) {
- /* we have more packages returned than source packages */
- gs_app_set_state (app, AS_APP_STATE_UNKNOWN);
- gs_app_set_state (app, AS_APP_STATE_UPDATABLE);
- } else if (number_installed + number_available < sources->len) {
- g_autofree gchar *tmp = NULL;
- /* we have less packages returned than source packages */
- tmp = gs_app_to_string (app);
- g_debug ("Failed to find all packages for:\n%s", tmp);
- gs_app_set_state (app, AS_APP_STATE_UNAVAILABLE);
- }
-}
-
static gboolean
gs_plugin_packagekit_resolve_packages (GsPlugin *plugin,
GsAppList *list,
@@ -239,7 +100,7 @@ gs_plugin_packagekit_resolve_packages (GsPlugin *plugin,
const gchar *pkgname;
guint i;
guint j;
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(PkResults) results = NULL;
g_autoptr(GPtrArray) package_ids = NULL;
g_autoptr(GPtrArray) packages = NULL;
@@ -263,10 +124,7 @@ gs_plugin_packagekit_resolve_packages (GsPlugin *plugin,
return TRUE;
g_ptr_array_add (package_ids, NULL);
- data.app = NULL;
data.plugin = plugin;
- data.ptask = NULL;
- data.profile_id = NULL;
/* resolve them all at once */
results = pk_client_resolve (priv->client,
@@ -308,13 +166,12 @@ gs_plugin_packagekit_refine_from_desktop (GsPlugin *plugin,
{
GsPluginData *priv = gs_plugin_get_data (plugin);
const gchar *to_array[] = { NULL, NULL };
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(PkResults) results = NULL;
g_autoptr(GPtrArray) packages = NULL;
data.app = app;
data.plugin = plugin;
- data.ptask = NULL;
data.profile_id = g_path_get_basename (filename);
to_array[0] = filename;
@@ -381,7 +238,7 @@ gs_plugin_packagekit_refine_updatedetails (GsPlugin *plugin,
GsApp *app;
guint cnt = 0;
PkUpdateDetail *update_detail;
- ProgressData data;
+ ProgressData data = { 0 };
g_autofree const gchar **package_ids = NULL;
g_autoptr(PkResults) results = NULL;
g_autoptr(GPtrArray) array = NULL;
@@ -398,10 +255,7 @@ gs_plugin_packagekit_refine_updatedetails (GsPlugin *plugin,
if (cnt == 0)
return TRUE;
- data.app = NULL;
data.plugin = plugin;
- data.ptask = NULL;
- data.profile_id = NULL;
/* get any update details */
results = pk_client_get_update_detail (priv->client,
@@ -437,83 +291,6 @@ gs_plugin_packagekit_refine_updatedetails (GsPlugin *plugin,
return TRUE;
}
-/*
- * gs_pk_compare_ids:
- *
- * Do not compare the repo. Some backends do not append the origin.
- */
-static gboolean
-gs_pk_compare_ids (const gchar *package_id1, const gchar *package_id2)
-{
- gboolean ret;
- g_auto(GStrv) split1 = NULL;
- g_auto(GStrv) split2 = NULL;
-
- split1 = pk_package_id_split (package_id1);
- split2 = pk_package_id_split (package_id2);
- ret = (g_strcmp0 (split1[PK_PACKAGE_ID_NAME],
- split2[PK_PACKAGE_ID_NAME]) == 0 &&
- g_strcmp0 (split1[PK_PACKAGE_ID_VERSION],
- split2[PK_PACKAGE_ID_VERSION]) == 0 &&
- g_strcmp0 (split1[PK_PACKAGE_ID_ARCH],
- split2[PK_PACKAGE_ID_ARCH]) == 0);
- return ret;
-}
-
-static void
-gs_plugin_packagekit_refine_details_app (GsPlugin *plugin,
- GPtrArray *array,
- GsApp *app)
-{
- GPtrArray *source_ids;
- PkDetails *details;
- const gchar *package_id;
- guint i;
- guint j;
- guint64 size = 0;
-
- source_ids = gs_app_get_source_ids (app);
- for (j = 0; j < source_ids->len; j++) {
- package_id = g_ptr_array_index (source_ids, j);
- for (i = 0; i < array->len; i++) {
- g_autofree gchar *desc = NULL;
- /* right package? */
- details = g_ptr_array_index (array, i);
- if (!gs_pk_compare_ids (package_id,
- pk_details_get_package_id (details))) {
- continue;
- }
- if (gs_app_get_license (app) == NULL) {
- g_autofree gchar *license_spdx = NULL;
- license_spdx = as_utils_license_to_spdx (pk_details_get_license (details));
- if (license_spdx != NULL) {
- gs_app_set_license (app,
- GS_APP_QUALITY_LOWEST,
- license_spdx);
- }
- }
- if (gs_app_get_url (app, AS_URL_KIND_HOMEPAGE) == NULL) {
- gs_app_set_url (app,
- AS_URL_KIND_HOMEPAGE,
- pk_details_get_url (details));
- }
- size += pk_details_get_size (details);
- break;
- }
- }
-
- /* the size is the size of all sources */
- if (gs_app_is_installed (app)) {
- gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
- if (size > 0 && gs_app_get_size_installed (app) == 0)
- gs_app_set_size_installed (app, size);
- } else {
- gs_app_set_size_installed (app, GS_APP_SIZE_UNKNOWABLE);
- if (size > 0 && gs_app_get_size_download (app) == 0)
- gs_app_set_size_download (app, size);
- }
-}
-
static gboolean
gs_plugin_packagekit_refine_details2 (GsPlugin *plugin,
GsAppList *list,
@@ -525,7 +302,7 @@ gs_plugin_packagekit_refine_details2 (GsPlugin *plugin,
GsApp *app;
const gchar *package_id;
guint i, j;
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(GPtrArray) array = NULL;
g_autoptr(GPtrArray) package_ids = NULL;
g_autoptr(PkResults) results = NULL;
@@ -541,9 +318,7 @@ gs_plugin_packagekit_refine_details2 (GsPlugin *plugin,
}
g_ptr_array_add (package_ids, NULL);
- data.app = NULL;
data.plugin = plugin;
- data.ptask = NULL;
data.profile_id = g_strjoinv (",", (gchar **) package_ids->pdata);
/* get any details */
@@ -579,7 +354,7 @@ gs_plugin_packagekit_refine_update_urgency (GsPlugin *plugin,
GsApp *app;
const gchar *package_id;
PkBitfield filter;
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(AsProfileTask) ptask = NULL;
g_autoptr(PkPackageSack) sack = NULL;
g_autoptr(PkResults) results = NULL;
@@ -591,10 +366,7 @@ gs_plugin_packagekit_refine_update_urgency (GsPlugin *plugin,
if ((flags & GS_PLUGIN_REFINE_FLAGS_REQUIRE_UPDATE_SEVERITY) == 0)
return TRUE;
- data.app = NULL;
data.plugin = plugin;
- data.ptask = NULL;
- data.profile_id = NULL;
/* get the list of updates */
filter = pk_bitfield_value (PK_FILTER_ENUM_NONE);
@@ -774,15 +546,13 @@ gs_plugin_packagekit_refine_distro_upgrade (GsPlugin *plugin,
GsPluginData *priv = gs_plugin_get_data (plugin);
guint i;
GsApp *app2;
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(PkResults) results = NULL;
g_autoptr(GsAppList) list = NULL;
guint cache_age_save;
data.app = app;
data.plugin = plugin;
- data.ptask = NULL;
- data.profile_id = NULL;
/* ask PK to simulate upgrading the system */
cache_age_save = pk_client_get_cache_age (priv->client);
diff --git a/plugins/packagekit/gs-plugin-packagekit-refresh.c
b/plugins/packagekit/gs-plugin-packagekit-refresh.c
index 729102d..ec4b261 100644
--- a/plugins/packagekit/gs-plugin-packagekit-refresh.c
+++ b/plugins/packagekit/gs-plugin-packagekit-refresh.c
@@ -55,40 +55,6 @@ gs_plugin_destroy (GsPlugin *plugin)
g_object_unref (priv->task);
}
-typedef struct {
- GsPlugin *plugin;
- AsProfileTask *ptask;
-} ProgressData;
-
-static void
-gs_plugin_packagekit_progress_cb (PkProgress *progress,
- PkProgressType type,
- gpointer user_data)
-{
- ProgressData *data = (ProgressData *) user_data;
- GsPlugin *plugin = data->plugin;
- GsPluginStatus plugin_status;
- PkStatusEnum status;
-
- if (type != PK_PROGRESS_TYPE_STATUS)
- return;
- g_object_get (progress,
- "status", &status,
- NULL);
-
- /* profile */
- if (status == PK_STATUS_ENUM_SETUP) {
- data->ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
- "packagekit-refresh::transaction");
- } else if (status == PK_STATUS_ENUM_FINISHED) {
- g_clear_pointer (&data->ptask, as_profile_task_free);
- }
-
- plugin_status = packagekit_status_enum_to_plugin_status (status);
- if (plugin_status != GS_PLUGIN_STATUS_UNKNOWN)
- gs_plugin_status_update (plugin, NULL, plugin_status);
-}
-
gboolean
gs_plugin_refresh (GsPlugin *plugin,
guint cache_age,
@@ -97,7 +63,7 @@ gs_plugin_refresh (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(PkResults) results = NULL;
/* nothing to re-generate */
@@ -108,7 +74,6 @@ gs_plugin_refresh (GsPlugin *plugin,
pk_client_set_background (PK_CLIENT (priv->task), cache_age > 0);
data.plugin = plugin;
- data.ptask = NULL;
/* refresh the metadata */
if (flags & GS_PLUGIN_REFRESH_FLAGS_METADATA ||
diff --git a/plugins/packagekit/gs-plugin-packagekit-upgrade.c
b/plugins/packagekit/gs-plugin-packagekit-upgrade.c
index e119389..20c8209 100644
--- a/plugins/packagekit/gs-plugin-packagekit-upgrade.c
+++ b/plugins/packagekit/gs-plugin-packagekit-upgrade.c
@@ -48,15 +48,10 @@ gs_plugin_destroy (GsPlugin *plugin)
g_object_unref (priv->task);
}
-typedef struct {
- GsApp *app;
- GsPlugin *plugin;
-} ProgressData;
-
static void
-gs_plugin_packagekit_progress_cb (PkProgress *progress,
- PkProgressType type,
- gpointer user_data)
+gs_plugin_packagekit_upgrade_progress_cb (PkProgress *progress,
+ PkProgressType type,
+ gpointer user_data)
{
ProgressData *data = (ProgressData *) user_data;
GsPlugin *plugin = data->plugin;
@@ -80,7 +75,7 @@ gs_plugin_app_upgrade_download (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(PkResults) results = NULL;
/* only process this app if was created by this plugin */
@@ -100,7 +95,7 @@ gs_plugin_app_upgrade_download (GsPlugin *plugin,
gs_app_get_version (app),
PK_UPGRADE_KIND_ENUM_COMPLETE,
cancellable,
- gs_plugin_packagekit_progress_cb, &data,
+ gs_plugin_packagekit_upgrade_progress_cb, &data,
error);
if (!gs_plugin_packagekit_results_valid (results, error)) {
gs_app_set_state_recover (app);
diff --git a/plugins/packagekit/gs-plugin-packagekit-url-to-app.c
b/plugins/packagekit/gs-plugin-packagekit-url-to-app.c
new file mode 100644
index 0000000..067b08e
--- /dev/null
+++ b/plugins/packagekit/gs-plugin-packagekit-url-to-app.c
@@ -0,0 +1,122 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2017 Canonical Ltd
+ *
+ * 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 <packagekit-glib2/packagekit.h>
+#include <gnome-software.h>
+
+#include "packagekit-common.h"
+
+struct GsPluginData {
+ PkClient *client;
+};
+
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+ GsPluginData *priv = gs_plugin_alloc_data (plugin, sizeof(GsPluginData));
+ priv->client = pk_client_new ();
+
+ pk_client_set_background (priv->client, FALSE);
+ pk_client_set_cache_age (priv->client, G_MAXUINT);
+}
+
+gboolean
+gs_plugin_url_to_app (GsPlugin *plugin,
+ GsAppList *list,
+ const gchar *url,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginData *priv = gs_plugin_get_data (plugin);
+
+ g_autofree gchar *scheme = NULL;
+ g_autofree gchar *path = NULL;
+ const gchar *id = NULL;
+ const gchar * const *id_like = NULL;
+ g_auto(GStrv) package_ids = NULL;
+ g_autoptr(PkResults) results = NULL;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GsOsRelease) os_release = NULL;
+ g_autoptr(GPtrArray) packages = NULL;
+ g_autoptr(GPtrArray) details = NULL;
+ ProgressData data = { 0 };
+
+ path = gs_utils_get_url_path (url);
+
+ data.app = app;
+ data.plugin = plugin;
+ data.profile_id = path;
+
+ /* only do this for apt:// on debian or debian-like distros */
+ os_release = gs_os_release_new (error);
+ if (os_release == NULL) {
+ g_prefix_error (error, "failed to determine OS information:");
+ return FALSE;
+ } else {
+ id = gs_os_release_get_id (os_release);
+ id_like = gs_os_release_get_id_like (os_release);
+ scheme = gs_utils_get_url_scheme (url);
+ if (!(g_strcmp0 (scheme, "apt") == 0 &&
+ (g_strcmp0 (id, "debian") == 0 ||
+ g_strv_contains (id_like, "debian")))) {
+ return TRUE;
+ }
+ }
+
+ app = gs_app_new (NULL);
+ gs_app_add_source (app, path);
+ gs_app_set_kind (app, AS_APP_KIND_GENERIC);
+
+ package_ids = g_new0 (gchar *, 2);
+ package_ids[0] = g_strdup (path);
+
+ results = pk_client_resolve (priv->client,
+ pk_bitfield_from_enums (PK_FILTER_ENUM_NEWEST, PK_FILTER_ENUM_ARCH, -1),
+ package_ids,
+ cancellable,
+ gs_plugin_packagekit_progress_cb, &data,
+ error);
+
+ if (!gs_plugin_packagekit_results_valid (results, error)) {
+ g_prefix_error (error, "failed to resolve package_ids: ");
+ return FALSE;
+ }
+
+ /* get results */
+ packages = pk_results_get_package_array (results);
+ details = pk_results_get_details_array (results);
+
+ if (packages->len >= 1) {
+ if (gs_app_get_local_file (app) != NULL)
+ return TRUE;
+
+ gs_plugin_packagekit_resolve_packages_app (plugin, packages, app);
+ gs_plugin_packagekit_refine_details_app (plugin, details, app);
+
+ gs_app_list_add (list, app);
+ } else {
+ g_warning ("no results returned");
+ }
+
+ return TRUE;
+}
diff --git a/plugins/packagekit/gs-plugin-packagekit.c b/plugins/packagekit/gs-plugin-packagekit.c
index 7978ba1..26ec0da 100644
--- a/plugins/packagekit/gs-plugin-packagekit.c
+++ b/plugins/packagekit/gs-plugin-packagekit.c
@@ -56,53 +56,6 @@ gs_plugin_destroy (GsPlugin *plugin)
g_object_unref (priv->task);
}
-typedef struct {
- GsApp *app;
- GsPlugin *plugin;
- AsProfileTask *ptask;
-} ProgressData;
-
-static void
-gs_plugin_packagekit_progress_cb (PkProgress *progress,
- PkProgressType type,
- gpointer user_data)
-{
- ProgressData *data = (ProgressData *) user_data;
- GsPlugin *plugin = data->plugin;
-
- if (type == PK_PROGRESS_TYPE_STATUS) {
- GsPluginStatus plugin_status;
- PkStatusEnum status;
- g_object_get (progress,
- "status", &status,
- NULL);
-
- /* profile */
- if (status == PK_STATUS_ENUM_SETUP) {
- data->ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
- "packagekit-refine::transaction");
- } else if (status == PK_STATUS_ENUM_FINISHED) {
- g_clear_pointer (&data->ptask, as_profile_task_free);
- }
-
- plugin_status = packagekit_status_enum_to_plugin_status (status);
- if (plugin_status != GS_PLUGIN_STATUS_UNKNOWN)
- gs_plugin_status_update (plugin, data->app, plugin_status);
-
- } else if (type == PK_PROGRESS_TYPE_PERCENTAGE) {
- gint percentage = pk_progress_get_percentage (progress);
- if (data->app != NULL && percentage >= 0 && percentage <= 100)
- gs_app_set_progress (data->app, (guint) percentage);
- }
-
- /* Only go from TRUE to FALSE - it doesn't make sense for a package
- * install to become uncancellable later on */
- if (data->app != NULL && gs_app_get_allow_cancel (data->app)) {
- gs_app_set_allow_cancel (data->app,
- pk_progress_get_allow_cancel (progress));
- }
-}
-
static gboolean
gs_plugin_add_sources_related (GsPlugin *plugin,
GHashTable *hash,
@@ -114,16 +67,14 @@ gs_plugin_add_sources_related (GsPlugin *plugin,
GsApp *app;
GsApp *app_tmp;
PkBitfield filter;
- ProgressData data;
+ ProgressData data = { 0 };
const gchar *id;
gboolean ret = TRUE;
g_autoptr(GsAppList) installed = gs_app_list_new ();
g_autoptr(PkResults) results = NULL;
g_autoptr(AsProfileTask) ptask = NULL;
- data.app = NULL;
data.plugin = plugin;
- data.ptask = NULL;
ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
"packagekit::add-sources-related");
@@ -174,16 +125,14 @@ gs_plugin_add_sources (GsPlugin *plugin,
GsPluginData *priv = gs_plugin_get_data (plugin);
PkBitfield filter;
PkRepoDetail *rd;
- ProgressData data;
+ ProgressData data = { 0 };
const gchar *id;
guint i;
g_autoptr(GHashTable) hash = NULL;
g_autoptr(PkResults) results = NULL;
g_autoptr(GPtrArray) array = NULL;
- data.app = NULL;
data.plugin = plugin;
- data.ptask = NULL;
/* ask PK for the repo details */
filter = pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_SOURCE,
@@ -232,12 +181,11 @@ gs_plugin_app_source_enable (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(PkResults) results = NULL;
data.app = app;
data.plugin = plugin;
- data.ptask = NULL;
/* do sync call */
gs_plugin_status_update (plugin, app, GS_PLUGIN_STATUS_WAITING);
@@ -263,7 +211,7 @@ gs_plugin_app_install (GsPlugin *plugin,
GsPluginData *priv = gs_plugin_get_data (plugin);
GPtrArray *addons;
GPtrArray *source_ids;
- ProgressData data;
+ ProgressData data = { 0 };
const gchar *package_id;
guint i, j;
g_autofree gchar *local_filename = NULL;
@@ -273,7 +221,6 @@ gs_plugin_app_install (GsPlugin *plugin,
data.app = app;
data.plugin = plugin;
- data.ptask = NULL;
/* only process this app if was created by this plugin */
if (g_strcmp0 (gs_app_get_management_plugin (app),
@@ -445,12 +392,11 @@ gs_plugin_app_source_disable (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(PkResults) results = NULL;
data.app = app;
data.plugin = plugin;
- data.ptask = NULL;
/* do sync call */
gs_plugin_status_update (plugin, app, GS_PLUGIN_STATUS_WAITING);
@@ -474,13 +420,11 @@ gs_plugin_app_source_remove (GsPlugin *plugin,
GError **error)
{
GsPluginData *priv = gs_plugin_get_data (plugin);
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(GError) error_local = NULL;
g_autoptr(PkResults) results = NULL;
- data.app = NULL;
data.plugin = plugin;
- data.ptask = NULL;
/* do sync call */
gs_plugin_status_update (plugin, app, GS_PLUGIN_STATUS_WAITING);
@@ -510,7 +454,7 @@ gs_plugin_app_remove (GsPlugin *plugin,
GsPluginData *priv = gs_plugin_get_data (plugin);
const gchar *package_id;
GPtrArray *source_ids;
- ProgressData data;
+ ProgressData data = { 0 };
guint i;
guint cnt = 0;
g_autoptr(PkResults) results = NULL;
@@ -518,7 +462,6 @@ gs_plugin_app_remove (GsPlugin *plugin,
data.app = app;
data.plugin = plugin;
- data.ptask = NULL;
/* only process this app if was created by this plugin */
if (g_strcmp0 (gs_app_get_management_plugin (app),
@@ -586,12 +529,10 @@ gs_plugin_add_search_files (GsPlugin *plugin,
{
GsPluginData *priv = gs_plugin_get_data (plugin);
PkBitfield filter;
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(PkResults) results = NULL;
- data.app = NULL;
data.plugin = plugin;
- data.ptask = NULL;
/* do sync call */
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_WAITING);
@@ -620,12 +561,10 @@ gs_plugin_add_search_what_provides (GsPlugin *plugin,
{
GsPluginData *priv = gs_plugin_get_data (plugin);
PkBitfield filter;
- ProgressData data;
+ ProgressData data = { 0 };
g_autoptr(PkResults) results = NULL;
- data.app = NULL;
data.plugin = plugin;
- data.ptask = NULL;
/* do sync call */
gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_WAITING);
diff --git a/plugins/packagekit/meson.build b/plugins/packagekit/meson.build
index ac049f2..b2cfc29 100644
--- a/plugins/packagekit/meson.build
+++ b/plugins/packagekit/meson.build
@@ -136,6 +136,22 @@ sources : 'gs-plugin-packagekit-proxy.c',
c_args : cargs,
dependencies : [ plugin_libs, packagekit ])
+shared_module(
+ 'gs_plugin_packagekit-url-to-app',
+ sources : [
+ 'gs-plugin-packagekit-url-to-app.c',
+ 'packagekit-common.c',
+ ],
+ include_directories : [
+ include_directories('../..'),
+ include_directories('../../lib'),
+ ],
+ install : true,
+ install_dir: plugin_dir,
+ c_args : cargs,
+ dependencies : [ plugin_libs, packagekit ]
+)
+
if get_option('enable-tests')
cargs += ['-DTESTDATADIR="' + join_paths(meson.current_source_dir(), 'tests') + '"']
e = executable(
diff --git a/plugins/packagekit/packagekit-common.c b/plugins/packagekit/packagekit-common.c
index 8295c98..4b53c79 100644
--- a/plugins/packagekit/packagekit-common.c
+++ b/plugins/packagekit/packagekit-common.c
@@ -291,3 +291,221 @@ gs_plugin_packagekit_add_results (GsPlugin *plugin,
}
return TRUE;
}
+
+void
+gs_plugin_packagekit_resolve_packages_app (GsPlugin *plugin,
+ GPtrArray *packages,
+ GsApp *app)
+{
+ GPtrArray *sources;
+ PkPackage *package;
+ const gchar *pkgname;
+ guint i, j;
+ guint number_available = 0;
+ guint number_installed = 0;
+
+ /* find any packages that match the package name */
+ number_installed = 0;
+ number_available = 0;
+ sources = gs_app_get_sources (app);
+ for (j = 0; j < sources->len; j++) {
+ pkgname = g_ptr_array_index (sources, j);
+ for (i = 0; i < packages->len; i++) {
+ package = g_ptr_array_index (packages, i);
+ if (g_strcmp0 (pk_package_get_name (package), pkgname) == 0) {
+ gs_plugin_packagekit_set_metadata_from_package (plugin, app, package);
+ switch (pk_package_get_info (package)) {
+ case PK_INFO_ENUM_INSTALLED:
+ number_installed++;
+ break;
+ case PK_INFO_ENUM_AVAILABLE:
+ number_available++;
+ break;
+ case PK_INFO_ENUM_UNAVAILABLE:
+ number_available++;
+ break;
+ default:
+ /* should we expect anything else? */
+ break;
+ }
+ }
+ }
+ }
+
+ /* if *all* the source packages for the app are installed then the
+ * application is considered completely installed */
+ if (number_installed == sources->len && number_available == 0) {
+ if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN)
+ gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+ } else if (number_installed + number_available == sources->len) {
+ /* if all the source packages are installed and all the rest
+ * of the packages are available then the app is available */
+ if (gs_app_get_state (app) == AS_APP_STATE_UNKNOWN)
+ gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+ } else if (number_installed + number_available > sources->len) {
+ /* we have more packages returned than source packages */
+ gs_app_set_state (app, AS_APP_STATE_UNKNOWN);
+ gs_app_set_state (app, AS_APP_STATE_UPDATABLE);
+ } else if (number_installed + number_available < sources->len) {
+ g_autofree gchar *tmp = NULL;
+ /* we have less packages returned than source packages */
+ tmp = gs_app_to_string (app);
+ g_debug ("Failed to find all packages for:\n%s", tmp);
+ gs_app_set_state (app, AS_APP_STATE_UNAVAILABLE);
+ }
+}
+
+void
+gs_plugin_packagekit_progress_cb (PkProgress *progress,
+ PkProgressType type,
+ gpointer user_data)
+{
+ ProgressData *data = (ProgressData *) user_data;
+ GsPlugin *plugin = data->plugin;
+
+ if (type == PK_PROGRESS_TYPE_STATUS) {
+ GsPluginStatus plugin_status;
+ PkStatusEnum status;
+ g_object_get (progress,
+ "status", &status,
+ NULL);
+
+ /* profile */
+ if (status == PK_STATUS_ENUM_SETUP) {
+ data->ptask = as_profile_start_literal (gs_plugin_get_profile (plugin),
+ "packagekit-refine::transaction");
+ } else if (status == PK_STATUS_ENUM_FINISHED) {
+ g_clear_pointer (&data->ptask, as_profile_task_free);
+ }
+
+ plugin_status = packagekit_status_enum_to_plugin_status (status);
+ if (plugin_status != GS_PLUGIN_STATUS_UNKNOWN)
+ gs_plugin_status_update (plugin, data->app, plugin_status);
+
+ } else if (type == PK_PROGRESS_TYPE_PERCENTAGE) {
+ gint percentage = pk_progress_get_percentage (progress);
+ if (data->app != NULL && percentage >= 0 && percentage <= 100)
+ gs_app_set_progress (data->app, (guint) percentage);
+ }
+
+ /* Only go from TRUE to FALSE - it doesn't make sense for a package
+ * install to become uncancellable later on */
+ if (data->app != NULL && gs_app_get_allow_cancel (data->app)) {
+ gs_app_set_allow_cancel (data->app,
+ pk_progress_get_allow_cancel (progress));
+ }
+}
+
+void
+gs_plugin_packagekit_set_metadata_from_package (GsPlugin *plugin,
+ GsApp *app,
+ PkPackage *package)
+{
+ const gchar *data;
+
+ gs_app_set_management_plugin (app, "packagekit");
+ gs_app_add_source (app, pk_package_get_name (package));
+ gs_app_add_source_id (app, pk_package_get_id (package));
+
+ /* set origin */
+ if (gs_app_get_origin (app) == NULL) {
+ data = pk_package_get_data (package);
+ if (g_str_has_prefix (data, "installed:"))
+ data += 10;
+ gs_app_set_origin (app, data);
+ }
+
+ /* set unavailable state */
+ if (pk_package_get_info (package) == PK_INFO_ENUM_UNAVAILABLE) {
+ gs_app_set_state (app, AS_APP_STATE_UNAVAILABLE);
+ gs_app_set_size_installed (app, GS_APP_SIZE_UNKNOWABLE);
+ gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
+ }
+ if (gs_app_get_version (app) == NULL)
+ gs_app_set_version (app,
+ pk_package_get_version (package));
+ gs_app_set_name (app,
+ GS_APP_QUALITY_LOWEST,
+ pk_package_get_name (package));
+ gs_app_set_summary (app,
+ GS_APP_QUALITY_LOWEST,
+ pk_package_get_summary (package));
+}
+
+/*
+ * gs_pk_compare_ids:
+ *
+ * Do not compare the repo. Some backends do not append the origin.
+ */
+static gboolean
+gs_pk_compare_ids (const gchar *package_id1, const gchar *package_id2)
+{
+ gboolean ret;
+ g_auto(GStrv) split1 = NULL;
+ g_auto(GStrv) split2 = NULL;
+
+ split1 = pk_package_id_split (package_id1);
+ split2 = pk_package_id_split (package_id2);
+ ret = (g_strcmp0 (split1[PK_PACKAGE_ID_NAME],
+ split2[PK_PACKAGE_ID_NAME]) == 0 &&
+ g_strcmp0 (split1[PK_PACKAGE_ID_VERSION],
+ split2[PK_PACKAGE_ID_VERSION]) == 0 &&
+ g_strcmp0 (split1[PK_PACKAGE_ID_ARCH],
+ split2[PK_PACKAGE_ID_ARCH]) == 0);
+ return ret;
+}
+
+
+void
+gs_plugin_packagekit_refine_details_app (GsPlugin *plugin,
+ GPtrArray *array,
+ GsApp *app)
+{
+ GPtrArray *source_ids;
+ PkDetails *details;
+ const gchar *package_id;
+ guint i;
+ guint j;
+ guint64 size = 0;
+
+ source_ids = gs_app_get_source_ids (app);
+ for (j = 0; j < source_ids->len; j++) {
+ package_id = g_ptr_array_index (source_ids, j);
+ for (i = 0; i < array->len; i++) {
+ g_autofree gchar *desc = NULL;
+ /* right package? */
+ details = g_ptr_array_index (array, i);
+ if (!gs_pk_compare_ids (package_id,
+ pk_details_get_package_id (details))) {
+ continue;
+ }
+ if (gs_app_get_license (app) == NULL) {
+ g_autofree gchar *license_spdx = NULL;
+ license_spdx = as_utils_license_to_spdx (pk_details_get_license (details));
+ if (license_spdx != NULL) {
+ gs_app_set_license (app,
+ GS_APP_QUALITY_LOWEST,
+ license_spdx);
+ }
+ }
+ if (gs_app_get_url (app, AS_URL_KIND_HOMEPAGE) == NULL) {
+ gs_app_set_url (app,
+ AS_URL_KIND_HOMEPAGE,
+ pk_details_get_url (details));
+ }
+ size += pk_details_get_size (details);
+ break;
+ }
+ }
+
+ /* the size is the size of all sources */
+ if (gs_app_is_installed (app)) {
+ gs_app_set_size_download (app, GS_APP_SIZE_UNKNOWABLE);
+ if (size > 0 && gs_app_get_size_installed (app) == 0)
+ gs_app_set_size_installed (app, size);
+ } else {
+ gs_app_set_size_installed (app, GS_APP_SIZE_UNKNOWABLE);
+ if (size > 0 && gs_app_get_size_download (app) == 0)
+ gs_app_set_size_download (app, size);
+ }
+}
diff --git a/plugins/packagekit/packagekit-common.h b/plugins/packagekit/packagekit-common.h
index 11e9714..68c71b2 100644
--- a/plugins/packagekit/packagekit-common.h
+++ b/plugins/packagekit/packagekit-common.h
@@ -29,15 +29,34 @@
G_BEGIN_DECLS
-GsPluginStatus packagekit_status_enum_to_plugin_status (PkStatusEnum status);
-
-gboolean gs_plugin_packagekit_add_results (GsPlugin *plugin,
- GsAppList *list,
- PkResults *results,
- GError **error);
-gboolean gs_plugin_packagekit_error_convert (GError **error);
-gboolean gs_plugin_packagekit_results_valid (PkResults *results,
- GError **error);
+typedef struct {
+ GsApp *app;
+ GsPlugin *plugin;
+ AsProfileTask *ptask;
+ gchar *profile_id;
+} ProgressData;
+
+GsPluginStatus packagekit_status_enum_to_plugin_status (PkStatusEnum status);
+
+gboolean gs_plugin_packagekit_add_results (GsPlugin *plugin,
+ GsAppList *list,
+ PkResults *results,
+ GError **error);
+gboolean gs_plugin_packagekit_error_convert (GError **error);
+gboolean gs_plugin_packagekit_results_valid (PkResults *results,
+ GError **error);
+void gs_plugin_packagekit_progress_cb (PkProgress *progress,
+ PkProgressType type,
+ gpointer user_data);
+void gs_plugin_packagekit_resolve_packages_app (GsPlugin *plugin,
+ GPtrArray *packages,
+ GsApp *app);
+void gs_plugin_packagekit_set_metadata_from_package (GsPlugin *plugin,
+ GsApp *app,
+ PkPackage *package);
+void gs_plugin_packagekit_refine_details_app (GsPlugin *plugin,
+ GPtrArray *array,
+ GsApp *app);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]