991 lines
29 KiB
Diff
991 lines
29 KiB
Diff
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@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", ×pec,
|
|
- "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/"
|