[PackageKit/f20] Backport some fixes from upstream

Richard Hughes rhughes at fedoraproject.org
Mon Sep 23 16:13:38 UTC 2013


commit 422248630d1ff9d287f9d011797adf4ed67fc0de
Author: Richard Hughes <richard at hughsie.com>
Date:   Mon Sep 23 16:47:53 2013 +0100

    Backport some fixes from upstream

 PackageKit-git-fixes.patch |  990 ++++++++++++++++++++++++++++++++++++++++++++
 PackageKit.spec            |   10 +-
 2 files changed, 997 insertions(+), 3 deletions(-)
---
diff --git a/PackageKit-git-fixes.patch b/PackageKit-git-fixes.patch
new file mode 100644
index 0000000..a1fc27c
--- /dev/null
+++ b/PackageKit-git-fixes.patch
@@ -0,0 +1,990 @@
+diff --git a/lib/packagekit-glib2/pk-common.c b/lib/packagekit-glib2/pk-common.c
+index 12f18cd..59ffc19 100644
+--- a/lib/packagekit-glib2/pk-common.c
++++ b/lib/packagekit-glib2/pk-common.c
+@@ -131,6 +131,50 @@ out:
+ }
+ 
+ /**
++ * pk_iso8601_to_datetime: (skip)
++ * @iso_date: The ISO8601 date to convert
++ *
++ * Return value: If valid then a new %GDateTime, else NULL
++ *
++ * Since: 0.8.11
++ **/
++GDateTime *
++pk_iso8601_to_datetime (const gchar *iso_date)
++{
++	gboolean ret = FALSE;
++	guint retval;
++	guint d = 0;
++	guint m = 0;
++	guint y = 0;
++	GTimeVal time_val;
++	GDateTime *date = NULL;
++
++	if (iso_date == NULL || iso_date[0] == '\0')
++		goto out;
++
++	/* try to parse complete ISO8601 date */
++	if (g_strstr_len (iso_date, -1, " ") != NULL)
++		ret = g_time_val_from_iso8601 (iso_date, &time_val);
++	if (ret && time_val.tv_sec != 0) {
++		g_debug ("Parsed %s %i", iso_date, ret);
++		date = g_date_time_new_from_timeval_utc (&time_val);
++		goto out;
++	}
++
++	/* g_time_val_from_iso8601() blows goats and won't
++	 * accept a valid ISO8601 formatted date without a
++	 * time value - try and parse this case */
++	retval = sscanf (iso_date, "%u-%u-%u", &y, &m, &d);
++	if (retval != 3)
++		goto out;
++
++	/* create valid object */
++	date = g_date_time_new_utc (y, m, d, 0, 0, 0);
++out:
++	return date;
++}
++
++/**
+  * pk_ptr_array_to_strv:
+  * @array: the GPtrArray of strings
+  *
+diff --git a/lib/packagekit-glib2/pk-common.h b/lib/packagekit-glib2/pk-common.h
+index f3d4315..379fd73 100644
+--- a/lib/packagekit-glib2/pk-common.h
++++ b/lib/packagekit-glib2/pk-common.h
+@@ -88,6 +88,7 @@ gchar		*pk_iso8601_present			(void)
+ 							 G_GNUC_WARN_UNUSED_RESULT;
+ gchar		*pk_iso8601_from_date			(const GDate	*date);
+ GDate		*pk_iso8601_to_date			(const gchar	*iso_date);
++GDateTime	*pk_iso8601_to_datetime			(const gchar	*iso_date);
+ gchar		*pk_get_distro_id			(void);
+ 
+ G_END_DECLS
+diff --git a/lib/packagekit-glib2/pk-control.c b/lib/packagekit-glib2/pk-control.c
+index 9477e65..e319bea 100644
+--- a/lib/packagekit-glib2/pk-control.c
++++ b/lib/packagekit-glib2/pk-control.c
+@@ -2447,6 +2447,24 @@ pk_control_name_appeared_cb (GDBusConnection *connection,
+ }
+ 
+ /**
++ * pk_control_proxy_destroy:
++ **/
++static void
++pk_control_proxy_destroy (PkControl *control)
++{
++	if (control->priv->proxy == NULL)
++		return;
++	g_signal_handlers_disconnect_by_func (control->priv->proxy,
++					      G_CALLBACK (pk_control_properties_changed_cb),
++					      control);
++	g_signal_handlers_disconnect_by_func (control->priv->proxy,
++					      G_CALLBACK (pk_control_signal_cb),
++					      control);
++	g_object_unref (control->priv->proxy);
++	control->priv->proxy = NULL;
++}
++
++/**
+  * pk_control_name_vanished_cb:
+  **/
+ static void
+@@ -2458,6 +2476,11 @@ pk_control_name_vanished_cb (GDBusConnection *connection,
+ 	control->priv->connected = FALSE;
+ 	g_debug ("notify::connected");
+ 	g_object_notify (G_OBJECT(control), "connected");
++
++	/* destroy the proxy, as even though it's "well known" we get a
++	 * GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown if we try to
++	 * use this after the server has restarted */
++	pk_control_proxy_destroy (control);
+ }
+ 
+ /**
+@@ -2497,6 +2520,9 @@ pk_control_finalize (GObject *object)
+ 	g_cancellable_cancel (priv->cancellable);
+ 	g_bus_unwatch_name (priv->watch_id);
+ 
++	/* disconnect proxy and destroy it */
++	pk_control_proxy_destroy (control);
++
+ 	/* remove pending sources */
+ 	if (priv->transaction_list_changed_id != 0)
+ 		g_source_remove (priv->transaction_list_changed_id);
+@@ -2506,15 +2532,6 @@ pk_control_finalize (GObject *object)
+ 		g_source_remove (priv->updates_changed_id);
+ 	if (priv->repo_list_changed_id != 0)
+ 		g_source_remove (priv->repo_list_changed_id);
+-	if (priv->proxy != NULL) {
+-		g_signal_handlers_disconnect_by_func (priv->proxy,
+-						      G_CALLBACK (pk_control_properties_changed_cb),
+-						      control);
+-		g_signal_handlers_disconnect_by_func (priv->proxy,
+-						      G_CALLBACK (pk_control_signal_cb),
+-						      control);
+-		g_object_unref (priv->proxy);
+-	}
+ 
+ 	g_free (priv->backend_name);
+ 	g_free (priv->backend_description);
+diff --git a/lib/packagekit-glib2/pk-package.c b/lib/packagekit-glib2/pk-package.c
+index 0c9e86d..4f7deb1 100644
+--- a/lib/packagekit-glib2/pk-package.c
++++ b/lib/packagekit-glib2/pk-package.c
+@@ -196,6 +196,46 @@ out:
+ }
+ 
+ /**
++ * pk_package_parse:
++ * @package: a valid #PkPackage instance
++ * @data: the data describing the package
++ * @error: a %GError to put the error code and message in, or %NULL
++ *
++ * Parses the data to populate the #PkPackage.
++ *
++ * Return value: %TRUE if the data was parsed correcty
++ *
++ * Since: 0.8.11
++ **/
++gboolean
++pk_package_parse (PkPackage *package, const gchar *data, GError **error)
++{
++	gboolean ret = TRUE;
++	gchar **sections;
++
++	g_return_val_if_fail (PK_IS_PACKAGE (package), FALSE);
++	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
++
++	/* split */
++	sections = g_strsplit (data, "\t", -1);
++	if (g_strv_length (sections) != 3) {
++		ret = FALSE;
++		g_set_error_literal (error, 1, 0, "data invalid");
++	}
++
++	/* parse object */
++	package->priv->info = pk_info_enum_from_string (sections[0]);
++	ret = pk_package_set_id (package, sections[1], error);
++	if (!ret)
++		goto out;
++	g_free (package->priv->summary);
++	package->priv->summary = g_strdup (sections[2]);
++out:
++	g_strfreev (sections);
++	return ret;
++}
++
++/**
+  * pk_package_get_info:
+  * @package: a valid #PkPackage instance
+  *
+diff --git a/lib/packagekit-glib2/pk-package.h b/lib/packagekit-glib2/pk-package.h
+index 60d0a10..8ca803b 100644
+--- a/lib/packagekit-glib2/pk-package.h
++++ b/lib/packagekit-glib2/pk-package.h
+@@ -72,6 +72,9 @@ void		 pk_package_test			(gpointer	 user_data);
+ gboolean	 pk_package_set_id			(PkPackage	*package,
+ 							 const gchar	*package_id,
+ 							 GError		**error);
++gboolean	 pk_package_parse			(PkPackage	*package,
++							 const gchar	*data,
++							 GError		**error);
+ void		 pk_package_print			(PkPackage	*package);
+ gboolean	 pk_package_equal			(PkPackage	*package1,
+ 							 PkPackage	*package2);
+diff --git a/lib/packagekit-glib2/pk-transaction-past.c b/lib/packagekit-glib2/pk-transaction-past.c
+index 13c2cb4..fa91b1d 100644
+--- a/lib/packagekit-glib2/pk-transaction-past.c
++++ b/lib/packagekit-glib2/pk-transaction-past.c
+@@ -33,6 +33,7 @@
+ #include <glib-object.h>
+ 
+ #include <packagekit-glib2/pk-transaction-past.h>
++#include <packagekit-glib2/pk-common.h>
+ #include <packagekit-glib2/pk-enum.h>
+ 
+ static void     pk_transaction_past_finalize	(GObject     *object);
+@@ -72,6 +73,187 @@ enum {
+ G_DEFINE_TYPE (PkTransactionPast, pk_transaction_past, PK_TYPE_SOURCE)
+ 
+ /**
++ * pk_transaction_past_get_id:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction ID value;
++ *
++ * Return value: The transaction data
++ *
++ * Since: 0.8.11
++ **/
++const gchar *
++pk_transaction_past_get_id (PkTransactionPast *past)
++{
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL);
++	return past->priv->tid;
++}
++
++/**
++ * pk_transaction_past_get_timespec:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction timespec value;
++ *
++ * Return value: The transaction data
++ *
++ * Since: 0.8.11
++ **/
++const gchar *
++pk_transaction_past_get_timespec (PkTransactionPast *past)
++{
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL);
++	return past->priv->timespec;
++}
++
++/**
++ * pk_transaction_past_get_datetime:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction date & time value;
++ *
++ * Return value: The transaction data, or %NULL if it's not available
++ *
++ * Since: 0.8.11
++ **/
++GDateTime *
++pk_transaction_past_get_datetime (PkTransactionPast *past)
++{
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL);
++	if (past->priv->timespec == NULL)
++		return NULL;
++	return pk_iso8601_to_datetime (past->priv->timespec);
++}
++
++/**
++ * pk_transaction_past_get_timestamp:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction timestamp
++ *
++ * Return value: The transaction data, or 0 if it's not available
++ *
++ * Since: 0.8.11
++ **/
++gint64
++pk_transaction_past_get_timestamp (PkTransactionPast *past)
++{
++	GDateTime *datetime;
++	gint64 timestamp;
++
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), 0);
++
++	datetime = pk_transaction_past_get_datetime (past);
++	if (datetime == NULL)
++		return 0;
++	timestamp = g_date_time_to_unix (datetime);
++	g_date_time_unref (datetime);
++	return timestamp;
++}
++
++/**
++ * pk_transaction_past_get_succeeded:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction succeeded value;
++ *
++ * Return value: The transaction data
++ *
++ * Since: 0.8.11
++ **/
++gboolean
++pk_transaction_past_get_succeeded (PkTransactionPast *past)
++{
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), FALSE);
++	return past->priv->succeeded;
++}
++
++/**
++ * pk_transaction_past_get_role:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction role;
++ *
++ * Return value: The transaction data
++ *
++ * Since: 0.8.11
++ **/
++PkRoleEnum
++pk_transaction_past_get_role (PkTransactionPast *past)
++{
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), PK_ROLE_ENUM_UNKNOWN);
++	return past->priv->role;
++}
++
++/**
++ * pk_transaction_past_get_duration:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction duration;
++ *
++ * Return value: The transaction data
++ *
++ * Since: 0.8.11
++ **/
++guint
++pk_transaction_past_get_duration (PkTransactionPast *past)
++{
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), 0);
++	return past->priv->duration;
++}
++
++/**
++ * pk_transaction_past_get_data:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction data;
++ *
++ * Return value: The transaction data
++ *
++ * Since: 0.8.11
++ **/
++const gchar *
++pk_transaction_past_get_data (PkTransactionPast *past)
++{
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL);
++	return past->priv->data;
++}
++
++/**
++ * pk_transaction_past_get_uid:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction uid;
++ *
++ * Return value: The transaction data
++ *
++ * Since: 0.8.11
++ **/
++guint
++pk_transaction_past_get_uid (PkTransactionPast *past)
++{
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), 0);
++	return past->priv->uid;
++}
++
++/**
++ * pk_transaction_past_get_cmdline:
++ * @past: a valid #PkTransactionPast instance
++ *
++ * Gets the past transaction cmdline value;
++ *
++ * Return value: The transaction data
++ *
++ * Since: 0.8.11
++ **/
++const gchar *
++pk_transaction_past_get_cmdline (PkTransactionPast *past)
++{
++	g_return_val_if_fail (PK_IS_TRANSACTION_PAST (past), NULL);
++	return past->priv->cmdline;
++}
++
++/**
+  * pk_transaction_past_get_property:
+  **/
+ static void
+diff --git a/lib/packagekit-glib2/pk-transaction-past.h b/lib/packagekit-glib2/pk-transaction-past.h
+index fcec8a5..5aa174b 100644
+--- a/lib/packagekit-glib2/pk-transaction-past.h
++++ b/lib/packagekit-glib2/pk-transaction-past.h
+@@ -28,6 +28,7 @@
+ 
+ #include <glib-object.h>
+ 
++#include <packagekit-glib2/pk-enum.h>
+ #include <packagekit-glib2/pk-source.h>
+ 
+ G_BEGIN_DECLS
+@@ -62,6 +63,16 @@ struct _PkTransactionPastClass
+ 
+ GType			 pk_transaction_past_get_type		(void);
+ PkTransactionPast	*pk_transaction_past_new		(void);
++const gchar		*pk_transaction_past_get_cmdline	(PkTransactionPast	*past);
++const gchar		*pk_transaction_past_get_data		(PkTransactionPast	*past);
++const gchar		*pk_transaction_past_get_id		(PkTransactionPast	*past);
++const gchar		*pk_transaction_past_get_timespec	(PkTransactionPast	*past);
++GDateTime		*pk_transaction_past_get_datetime	(PkTransactionPast	*past);
++gint64			 pk_transaction_past_get_timestamp	(PkTransactionPast	*past);
++gboolean		 pk_transaction_past_get_succeeded	(PkTransactionPast	*past);
++guint			 pk_transaction_past_get_duration	(PkTransactionPast	*past);
++guint			 pk_transaction_past_get_uid		(PkTransactionPast	*past);
++PkRoleEnum		 pk_transaction_past_get_role		(PkTransactionPast	*past);
+ 
+ G_END_DECLS
+ 
+diff --git a/src/org.freedesktop.PackageKit.xml b/src/org.freedesktop.PackageKit.xml
+index 297cbeb..b8038ca 100644
+--- a/src/org.freedesktop.PackageKit.xml
++++ b/src/org.freedesktop.PackageKit.xml
+@@ -316,6 +316,54 @@
+     </method>
+ 
+     <!--*****************************************************************************************-->
++    <method name="GetPackageHistory">
++      <doc:doc>
++        <doc:description>
++          <doc:para>
++            Gets the history for a given package name.
++            This uses the internal PackageKit history database and will not
++            return transactions done outside of PackageKit using a distribution
++            native tool.
++          </doc:para>
++        </doc:description>
++      </doc:doc>
++      <arg type="as" name="names" direction="in">
++        <doc:doc>
++          <doc:summary>
++            <doc:para>
++              The package names to return history for, e.g. <doc:tt>[ colord ]</doc:tt>.
++            </doc:para>
++          </doc:summary>
++        </doc:doc>
++      </arg>
++      <arg type="u" name="count" direction="in">
++        <doc:doc>
++          <doc:summary>
++            <doc:para>
++              The maximum number of past transactions to return, or 0 for no limit.
++            </doc:para>
++          </doc:summary>
++        </doc:doc>
++      </arg>
++      <arg type="a{saa{sv}}" name="history" direction="out">
++        <doc:doc>
++          <doc:summary>
++            <doc:para>
++              The list of actions performed on this package. The array may contain
++              the following keys of types:
++              <doc:tt>info[uint]</doc:tt>,
++              <doc:tt>user-id[uint]</doc:tt>,
++              <doc:tt>version[string]</doc:tt>,
++              <doc:tt>source[string]</doc:tt>,
++              <doc:tt>timestamp[uint64]</doc:tt>.
++              Other keys and values may be added in the future.
++            </doc:para>
++          </doc:summary>
++        </doc:doc>
++      </arg>
++    </method>
++
++    <!--*****************************************************************************************-->
+     <method name="GetDaemonState">
+       <doc:doc>
+         <doc:description>
+diff --git a/src/pk-engine.c b/src/pk-engine.c
+index 338cbaa..f7265bd 100644
+--- a/src/pk-engine.c
++++ b/src/pk-engine.c
+@@ -1255,6 +1255,165 @@ out:
+ }
+ 
+ /**
++ * pk_engine_package_name_in_strv:
++ **/
++static gboolean
++pk_engine_package_name_in_strv (gchar **strv, PkPackage *pkg)
++{
++	guint i;
++	for (i = 0; strv[i] != NULL; i++) {
++		if (g_strcmp0 (strv[i], pk_package_get_name (pkg)) == 0)
++			return TRUE;
++	}
++	return FALSE;
++}
++
++/**
++ * pk_engine_get_package_history_pkg:
++ *
++ * Create a 'a{sv}' GVariant instance from all the PkTransactionPast data
++ **/
++static GVariant *
++pk_engine_get_package_history_pkg (PkTransactionPast *item, PkPackage *pkg)
++{
++	GVariantBuilder builder;
++	g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
++	g_variant_builder_add (&builder, "{sv}", "info",
++			       g_variant_new_uint32 (pk_package_get_info (pkg)));
++	g_variant_builder_add (&builder, "{sv}", "source",
++			       g_variant_new_string (pk_package_get_data (pkg)));
++	g_variant_builder_add (&builder, "{sv}", "version",
++			       g_variant_new_string (pk_package_get_version (pkg)));
++	g_variant_builder_add (&builder, "{sv}", "timestamp",
++			       g_variant_new_uint64 (pk_transaction_past_get_timestamp (item)));
++	g_variant_builder_add (&builder, "{sv}", "user-id",
++			       g_variant_new_uint32 (pk_transaction_past_get_uid (item)));
++	return g_variant_builder_end (&builder);
++}
++/**
++ * pk_engine_get_package_history:
++ **/
++static GVariant *
++pk_engine_get_package_history (PkEngine *engine,
++			       gchar **package_names,
++			       guint max_size,
++			       GError **error)
++{
++	const gchar *data;
++	const gchar *pkgname;
++	gboolean ret;
++	gchar *key;
++	gchar **package_lines;
++	GHashTable *deduplicate_hash;
++	GHashTable *pkgname_hash;
++	gint64 timestamp;
++	GList *keys = NULL;
++	GList *l;
++	GList *list;
++	GPtrArray *array = NULL;
++	guint i;
++	GVariantBuilder builder;
++	GVariant *value = NULL;
++	PkPackage *package_tmp;
++	PkTransactionPast *item;
++
++	list = pk_transaction_db_get_list (engine->priv->transaction_db, max_size);
++
++	/* simplify the loop */
++	if (max_size == 0)
++		max_size = G_MAXUINT;
++
++	pkgname_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_ptr_array_unref);
++	deduplicate_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
++	package_tmp = pk_package_new ();
++	for (l = list; l != NULL; l = l->next) {
++		item = PK_TRANSACTION_PAST (l->data);
++
++		/* ignore anything that failed */
++		if (!pk_transaction_past_get_succeeded (item))
++			continue;
++
++		/* split up data */
++		data = pk_transaction_past_get_data (item);
++		if (data == NULL)
++			continue;
++		package_lines = g_strsplit (data, "\n", -1);
++		for (i = 0; package_lines[i] != NULL; i++) {
++			ret = pk_package_parse (package_tmp, package_lines[i], error);
++			g_assert (ret);
++
++			/* not the package we care about */
++			if (!pk_engine_package_name_in_strv (package_names, package_tmp))
++				continue;
++
++			/* not a state we care about */
++			if (pk_package_get_info (package_tmp) == PK_INFO_ENUM_CLEANUP)
++				continue;
++
++			/* transactions without a timestamp are not interesting */
++			timestamp = pk_transaction_past_get_timestamp (item);
++			if (timestamp == 0)
++				continue;
++
++			/* de-duplicate the entry, in the case of multiarch */
++			key = g_strdup_printf ("%s-%" G_GINT64_FORMAT,
++					       pk_package_get_name (package_tmp),
++					       timestamp);
++			if (g_hash_table_lookup (deduplicate_hash, key) != NULL) {
++				g_free (key);
++				continue;
++			}
++			g_hash_table_insert (deduplicate_hash, key, package_lines[i]);
++
++			/* get the blob for this data item */
++			value = pk_engine_get_package_history_pkg (item, package_tmp);
++			if (value == NULL)
++				continue;
++
++			/* find the array */
++			pkgname = pk_package_get_name (package_tmp);
++			array = g_hash_table_lookup (pkgname_hash, pkgname);
++			if (array == NULL) {
++				array = g_ptr_array_new ();
++				g_hash_table_insert (pkgname_hash,
++						     g_strdup (pkgname),
++						     array);
++			}
++			g_ptr_array_add (array, value);
++		}
++		g_strfreev (package_lines);
++	}
++
++	/* no history returns an empty array */
++	if (g_hash_table_size (pkgname_hash) == 0) {
++		value = g_variant_new_array (G_VARIANT_TYPE ("{saa{sv}}"), NULL, 0);
++		goto out;
++	}
++
++	/* we have a hash of pkgname:GPtrArray where the GPtrArray is an array
++	 * of GVariants of type a{sv} */
++	g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
++	keys = g_hash_table_get_keys (pkgname_hash);
++	for (l = keys; l != NULL; l = l->next) {
++		pkgname = l->data;
++		array = g_hash_table_lookup (pkgname_hash, pkgname);
++		/* create aa{sv} */
++		value = g_variant_new_array (NULL,
++					     (GVariant * const *) array->pdata,
++					     MIN (array->len, max_size));
++		g_variant_builder_add (&builder, "{s at aa{sv}}", pkgname, value);
++	}
++	value = g_variant_builder_end (&builder);
++out:
++	g_list_free (keys);
++	g_hash_table_unref (pkgname_hash);
++	g_hash_table_unref (deduplicate_hash);
++	g_object_unref (package_tmp);
++	g_list_free_full (list, (GDestroyNotify) g_object_unref);
++	return value;
++}
++
++/**
+  * pk_engine_daemon_method_call:
+  **/
+ static void
+@@ -1269,11 +1428,13 @@ pk_engine_daemon_method_call (GDBusConnection *connection_, const gchar *sender,
+ 	GError *error = NULL;
+ 	guint time_since;
+ 	GVariant *value = NULL;
++	GVariant *tuple = NULL;
+ 	PkAuthorizeEnum result_enum;
+ 	PkEngine *engine = PK_ENGINE (user_data);
+ 	PkRoleEnum role;
+ 	gchar **transaction_list;
+ 	gchar **array = NULL;
++	gchar **package_names;
+ 	guint size;
+ 	gboolean is_priority = TRUE;
+ 
+@@ -1298,6 +1459,31 @@ pk_engine_daemon_method_call (GDBusConnection *connection_, const gchar *sender,
+ 		goto out;
+ 	}
+ 
++	if (g_strcmp0 (method_name, "GetPackageHistory") == 0) {
++		g_variant_get (parameters, "(^a&su)", &package_names, &size);
++		if (package_names == NULL || g_strv_length (package_names) == 0) {
++			g_dbus_method_invocation_return_error (invocation,
++							       PK_ENGINE_ERROR,
++							       PK_ENGINE_ERROR_NOT_SUPPORTED,
++							       "history for package name invalid");
++			goto out;
++		}
++		value = pk_engine_get_package_history (engine, package_names, size, &error);
++		if (value == NULL) {
++			g_dbus_method_invocation_return_error (invocation,
++							       PK_ENGINE_ERROR,
++							       PK_ENGINE_ERROR_NOT_SUPPORTED,
++							       "history for package name %s failed: %s",
++							       package_names[0],
++							       error->message);
++			g_error_free (error);
++			goto out;
++		}
++		tuple = g_variant_new_tuple (&value, 1);
++		g_dbus_method_invocation_return_value (invocation, tuple);
++		goto out;
++	}
++
+ 	if (g_strcmp0 (method_name, "CreateTransaction") == 0) {
+ 
+ 		g_debug ("CreateTransaction method called");
+diff --git a/src/pk-transaction-db.c b/src/pk-transaction-db.c
+index 41c3807..2b20f3a 100644
+--- a/src/pk-transaction-db.c
++++ b/src/pk-transaction-db.c
+@@ -56,13 +56,6 @@ struct PkTransactionDbPrivate
+ 	guint			 database_save_id;
+ };
+ 
+-enum {
+-	SIGNAL_TRANSACTION,
+-	SIGNAL_LAST
+-};
+-
+-static guint signals [SIGNAL_LAST] = { 0 };
+-
+ G_DEFINE_TYPE (PkTransactionDb, pk_transaction_db, G_TYPE_OBJECT)
+ 
+ typedef struct {
+@@ -79,21 +72,21 @@ typedef struct {
+  * pk_transaction_sqlite_transaction_cb:
+  **/
+ static gint
+-pk_transaction_sqlite_transaction_cb (void *data, gint argc, gchar **argv, gchar **col_name)
++pk_transaction_db_add_transaction_cb (void *data,
++				      gint argc,
++				      gchar **argv,
++				      gchar **col_name)
+ {
+ 	PkTransactionPast *item;
+-	PkTransactionDb *tdb = PK_TRANSACTION_DB (data);
++	GList **list = (GList **) data;
+ 	gint i;
+ 	gchar *col;
+ 	gchar *value;
+ 	guint temp;
+ 	gboolean ret;
+ 
+-	g_return_val_if_fail (tdb != NULL, 0);
+-	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), 0);
+-
+ 	item = pk_transaction_past_new ();
+-	for (i=0; i<argc; i++) {
++	for (i = 0; i < argc; i++) {
+ 		col = col_name[i];
+ 		value = argv[i];
+ 		if (g_strcmp0 (col, "succeeded") == 0) {
+@@ -137,10 +130,9 @@ pk_transaction_sqlite_transaction_cb (void *data, gint argc, gchar **argv, gchar
+ 		}
+ 	}
+ 
+-	/* emit signal */
+-	g_signal_emit (tdb, signals [SIGNAL_TRANSACTION], 0, item);
++	/* add to start of the list */
++	*list = g_list_prepend (*list, item);
+ 
+-	g_object_unref (item);
+ 	return 0;
+ }
+ 
+@@ -156,7 +148,7 @@ pk_transaction_db_sql_statement (PkTransactionDb *tdb, const gchar *sql)
+ 	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
+ 	g_return_val_if_fail (tdb->priv->db != NULL, FALSE);
+ 
+-	rc = sqlite3_exec (tdb->priv->db, sql, pk_transaction_sqlite_transaction_cb, tdb, &error_msg);
++	rc = sqlite3_exec (tdb->priv->db, sql, NULL, tdb, &error_msg);
+ 	if (rc != SQLITE_OK) {
+ 		g_warning ("SQL error: %s\n", error_msg);
+ 		sqlite3_free (error_msg);
+@@ -307,24 +299,36 @@ out:
+ /**
+  * pk_transaction_db_get_list:
+  **/
+-gboolean
++GList *
+ pk_transaction_db_get_list (PkTransactionDb *tdb, guint limit)
+ {
++	gchar *error_msg = NULL;
+ 	gchar *statement;
++	gint rc;
++	GList *list = NULL;
+ 
+-	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
++	g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), NULL);
+ 
+-	if (limit == 0)
++	if (limit == 0) {
+ 		statement = g_strdup ("SELECT transaction_id, timespec, succeeded, duration, role, data, uid, cmdline "
+ 				      "FROM transactions ORDER BY timespec DESC");
+-	else
++	} else {
+ 		statement = g_strdup_printf ("SELECT transaction_id, timespec, succeeded, duration, role, data, uid, cmdline "
+ 					     "FROM transactions ORDER BY timespec DESC LIMIT %i", limit);
+-
+-	pk_transaction_db_sql_statement (tdb, statement);
++	}
++	rc = sqlite3_exec (tdb->priv->db,
++			   statement,
++			   pk_transaction_db_add_transaction_cb,
++			   &list,
++			   &error_msg);
++	if (rc != SQLITE_OK) {
++		g_warning ("SQL error: %s\n", error_msg);
++		sqlite3_free (error_msg);
++		goto out;
++	}
++out:
+ 	g_free (statement);
+-
+-	return TRUE;
++	return list;
+ }
+ 
+ /**
+@@ -830,11 +834,6 @@ pk_transaction_db_class_init (PkTransactionDbClass *klass)
+ {
+ 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ 	object_class->finalize = pk_transaction_db_finalize;
+-	signals [SIGNAL_TRANSACTION] =
+-		g_signal_new ("transaction",
+-			      G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+-			      0, NULL, NULL, g_cclosure_marshal_VOID__POINTER,
+-			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+ 	g_type_class_add_private (klass, sizeof (PkTransactionDbPrivate));
+ }
+ 
+diff --git a/src/pk-transaction-db.h b/src/pk-transaction-db.h
+index 41e9b94..4a66c62 100644
+--- a/src/pk-transaction-db.h
++++ b/src/pk-transaction-db.h
+@@ -77,7 +77,7 @@ gboolean	 pk_transaction_db_set_finished		(PkTransactionDb	*tdb,
+ gboolean	 pk_transaction_db_set_data		(PkTransactionDb	*tdb,
+ 							 const gchar		*tid,
+ 							 const gchar		*data);
+-gboolean	 pk_transaction_db_get_list		(PkTransactionDb	*tdb,
++GList		*pk_transaction_db_get_list		(PkTransactionDb	*tdb,
+ 							 guint			 limit);
+ gboolean	 pk_transaction_db_action_time_reset	(PkTransactionDb	*tdb,
+ 							 PkRoleEnum		 role);
+diff --git a/src/pk-transaction.c b/src/pk-transaction.c
+index 73a6960..123ad3f 100644
+--- a/src/pk-transaction.c
++++ b/src/pk-transaction.c
+@@ -1742,67 +1742,6 @@ pk_transaction_status_changed_cb (PkBackendJob *job,
+ }
+ 
+ /**
+- * pk_transaction_transaction_cb:
+- **/
+-static void
+-pk_transaction_transaction_cb (PkTransactionDb *tdb,
+-			       PkTransactionPast *item,
+-			       PkTransaction *transaction)
+-{
+-	gchar *tid;
+-	gchar *timespec;
+-	gchar *data;
+-	gchar *cmdline;
+-	guint duration;
+-	guint uid;
+-	gboolean succeeded;
+-	PkRoleEnum role;
+-
+-	g_return_if_fail (PK_IS_TRANSACTION (transaction));
+-	g_return_if_fail (transaction->priv->tid != NULL);
+-
+-	/* add to results */
+-	pk_results_add_transaction (transaction->priv->results, item);
+-
+-	/* get data */
+-	g_object_get (item,
+-		      "role", &role,
+-		      "tid", &tid,
+-		      "timespec", &timespec,
+-		      "succeeded", &succeeded,
+-		      "duration", &duration,
+-		      "data", &data,
+-		      "uid", &uid,
+-		      "cmdline", &cmdline,
+-		      NULL);
+-
+-	/* emit */
+-	g_debug ("emitting transaction %s, %s, %i, %s, %i, %s, %i, %s",
+-		   tid, timespec, succeeded,
+-		   pk_role_enum_to_string (role),
+-		   duration, data, uid, cmdline);
+-	g_dbus_connection_emit_signal (transaction->priv->connection,
+-				       NULL,
+-				       transaction->priv->tid,
+-				       PK_DBUS_INTERFACE_TRANSACTION,
+-				       "Transaction",
+-				       g_variant_new ("(osbuusus)",
+-						      tid,
+-						      timespec,
+-						      succeeded,
+-						      role,
+-						      duration,
+-						      data != NULL ? data : "",
+-						      uid,
+-						      cmdline != NULL ? cmdline : ""),
+-				       NULL);
+-	g_free (tid);
+-	g_free (timespec);
+-	g_free (data);
+-	g_free (cmdline);
+-}
+-
+-/**
+  * pk_transaction_update_detail_cb:
+  **/
+ static void
+@@ -3764,8 +3703,19 @@ pk_transaction_get_old_transactions (PkTransaction *transaction,
+ 				     GVariant *params,
+ 				     GDBusMethodInvocation *context)
+ {
++	const gchar *cmdline;
++	const gchar *data;
++	const gchar *modified;
++	const gchar *tid;
++	gboolean succeeded;
++	GList *l;
++	GList *transactions = NULL;
++	guint duration;
+ 	guint idle_id;
+ 	guint number;
++	guint uid;
++	PkRoleEnum role;
++	PkTransactionPast *item;
+ 
+ 	g_return_if_fail (PK_IS_TRANSACTION (transaction));
+ 	g_return_if_fail (transaction->priv->tid != NULL);
+@@ -3776,7 +3726,46 @@ pk_transaction_get_old_transactions (PkTransaction *transaction,
+ 	g_debug ("GetOldTransactions method called");
+ 
+ 	pk_transaction_set_role (transaction, PK_ROLE_ENUM_GET_OLD_TRANSACTIONS);
+-	pk_transaction_db_get_list (transaction->priv->transaction_db, number);
++	transactions = pk_transaction_db_get_list (transaction->priv->transaction_db, number);
++	for (l = transactions; l != NULL; l = l->next) {
++		item = PK_TRANSACTION_PAST (l->data);
++
++		/* add to results */
++		pk_results_add_transaction (transaction->priv->results, item);
++
++		/* get data */
++		role = pk_transaction_past_get_role (item);
++		tid = pk_transaction_past_get_id (item);
++		modified = pk_transaction_past_get_timespec (item);
++		succeeded = pk_transaction_past_get_succeeded (item);
++		duration = pk_transaction_past_get_duration (item);
++		data = pk_transaction_past_get_data (item);
++		uid = pk_transaction_past_get_uid (item);
++		cmdline = pk_transaction_past_get_cmdline (item);
++
++		/* emit */
++		g_debug ("adding transaction %s, %s, %i, %s, %i, %s, %i, %s",
++			 tid, modified, succeeded,
++			 pk_role_enum_to_string (role),
++			 duration, data, uid, cmdline);
++		g_dbus_connection_emit_signal (transaction->priv->connection,
++					       NULL,
++					       transaction->priv->tid,
++					       PK_DBUS_INTERFACE_TRANSACTION,
++					       "Transaction",
++					       g_variant_new ("(osbuusus)",
++							      tid,
++							      modified,
++							      succeeded,
++							      role,
++							      duration,
++							      data != NULL ? data : "",
++							      uid,
++							      cmdline != NULL ? cmdline : ""),
++					       NULL);
++	}
++	g_list_free_full (transactions, (GDestroyNotify) g_object_unref);
++
+ 	idle_id = g_idle_add ((GSourceFunc) pk_transaction_finished_idle_cb, transaction);
+ 	g_source_set_name_by_id (idle_id, "[PkTransaction] finished from get-old-transactions");
+ 
+@@ -5805,8 +5794,6 @@ pk_transaction_init (PkTransaction *transaction)
+ 			 error->message);
+ 		g_error_free (error);
+ 	}
+-	g_signal_connect (transaction->priv->transaction_db, "transaction",
+-			  G_CALLBACK (pk_transaction_transaction_cb), transaction);
+ 
+ 	/* load introspection from file */
+ 	transaction->priv->introspection = pk_load_introspection (DATADIR "/dbus-1/interfaces/"
diff --git a/PackageKit.spec b/PackageKit.spec
index 1dd8bf1..38cc618 100644
--- a/PackageKit.spec
+++ b/PackageKit.spec
@@ -6,7 +6,7 @@
 Summary:   Package management service
 Name:      PackageKit
 Version:   0.8.11
-Release:   1%{?dist}
+Release:   2%{?dist}
 License:   GPLv2+ and LGPLv2+
 URL:       http://www.packagekit.org
 Source0:   http://www.packagekit.org/releases/%{name}-%{version}.tar.xz
@@ -21,7 +21,7 @@ Patch1:    PackageKit-0.4.4-Fedora-turn-off-time.conf.patch
 Patch4: PackageKit-0.7.4-xulrunner2.patch
 
 # Upstream already
-#Patch99: PackageKit-git-fixes.patch
+Patch99: PackageKit-git-fixes.patch
 
 Requires: %{name}-glib%{?_isa} = %{version}-%{release}
 Requires: PackageKit-backend
@@ -253,7 +253,7 @@ user to restart the computer or remove and re-insert the device.
 %patch0 -p1 -b .fedora
 %patch1 -p1 -b .no-time
 %patch4 -p1 -b .xulrunner2
-#%patch99 -p1 -b .git
+%patch99 -p1 -b .git
 
 NOCONFIGURE=1 ./autogen.sh
 
@@ -455,6 +455,10 @@ update-mime-database %{_datadir}/mime &> /dev/null || :
 %{_libdir}/pkgconfig/packagekit-plugin.pc
 
 %changelog
+* Mon Sep 23 2013 Richard Hughes <rhughes at redhat.com> - 0.8.11-2
+- Backport the package history functionality from master and some other
+  related bug fixes for gnome-software.
+
 * Mon Sep 02 2013 Richard Hughes <rhughes at redhat.com> - 0.8.11-1
 - New upstream release
 - Add a few missing subcommands to the help output


More information about the scm-commits mailing list